存档

文章标签 ‘Qt’

Next Generation Qt UI Demos

2009年12月21日

上周三在台北的Qt开发者大会上给大家展示了Qt中一些新的特性,特别是下一代的界面和效果,下面是如何得到这些Demo的方法:

1. 首先你需要下载Qt Declarative UI的安装包,Qt Declarative会在4.6中正式发布,所以现在还是技术预览版。

qt-4.6.0-declarative.zip 或者 qt-4.6.0-declarative.tar.gz, 解压缩,然后按照readme中的方法去编译和安装,前提是你必须要有安装好的Qt 4.6开发环境。

2. 在Qt Declarative包中有两个目录,分别是Demos和Examples,里面有当天演示的绝大多数Demos,包括QML的。

3. Applauncher Demo在这里animationDemos,需要下载并且编译一下,前提是你已经安装好了Qt Declarative。

4. Qt Mobile Demos,就是运行在Mac, Maemo(Nokia N900), Symbian(Nokia N97)上的那个demo,可以在http://qtlabs.openbossa.org/mobile-demos/下载到Symbian和Maemo的版本,Source Code在这里:qt-labs-mobile-demos-master.tar

以上基本就是所有我使用的Demos了,大家自己好好玩玩吧!

Qt, Technology , , , , ,

Qt 4.6 正式发布!

2009年12月1日

诺基亚发布Qt 4.6

让开发人员在SymbianMaemo 及其他平台开发杰出应用程序的过程变得比以往更加轻松。

2009年12月1日 – 诺基亚今日发布了Qt 4.6——最新版的跨平台应用程序和用户界面框架。Qt 4.6 对全新平台提供支持,具有强大的全新图形处理能力并支持多点触摸和手势输入,让高级应用程序和设备的开发过程变得更加轻松和快乐。

诺基亚应用服务和框架副总裁Sebastian Nystrom说:“不论是什么样产品设计或开发平台,Qt 4.6的发布对开发人员来说都是一件令人兴奋的事。”

“开发人员可以轻而易举地为桌面平台或设备(包括数亿部基于Symbian 和 Maemo系统的设备)开发出具有视觉美感和网络连接功能的应用程序。”

Nystrom 补充说:“开发人员将非常喜欢使用Qt直观的编程界面,快速开发出功能强大、外表美观的应用程序。”

阅读全文…

Qt , ,

官方消息:Qt 将会是Symbian的标准开发平台

2009年11月30日

读者们可还记得“Avkon已死,Qt当立”这篇文章?当时还只是rumor,现在已经已经成为现实了,官方消息在Symbian的网站上。

Platform_plan

在2010年中旬左右,也就在是Symbian ^4的发布中,Qt将会作为标准的应用开发平台,而原有的Avkon也将退出历史舞台了。具体的Symbian Roadmap,请看如下链接:http://developer.symbian.org/wiki/index.php/Roadmap_for_the_Symbian_Platform

想给Symbian开发应用的朋友,可以开始准备了。

Nokia, Qt , ,

Qt 4.6 demo for Nokia mobiles

2009年11月11日

很多人都想看看Qt运行在自己手机上的样子,但是编译过程又很繁琐。我做个一个安装包,包含了最新的Qt4.6 beta,以及很多有趣的Qt demo。有兴趣的同学可以安装在自己的手机上运行看看。

机型要求:

Symbian S60 V3 FP1 and above, Symbian S60 V5

E71, E72, E75, N5800, N97, N97mini,  等等。。

下载

Qt , , ,

发现Qt的bug该怎么办?

2009年11月6日

如果你在开发Qt或者使用Qt Creator过程中发现了bug怎么办?

现在简单了,打开http://bugreports.qt.nokia.com,搜搜看别人有没有报过类似的bug,有的话就加到自己的跟踪列表里,随时关注,没有的话,就报一个bug,很快就会有人来帮你解决的,如果这个bug已经存在系统中,你还可以进行“投票”,票数越多的bug说明解决得迫切性越高,这个bug得优先级就会越高,解决得速度就越快些。当然,你首先得注册个帐号。

当然,如果你自己打算解决这个bug就更好不过了,访问http://qt.gitorious.org/qt/pages/QtContributionGuidelines 提交你的代码修改就可以了。

这两个系统不仅仅是供外部开发者使用的,Qt本身的开发人员也使用这两个系统进行日常的开发。怎么样,很有诚意吧,而且开发过程可以说是相当透明了。

Qt ,

对 Windows Mobile 6.5 的支持

2009年11月6日

Qt 4.6支持了雪豹,Windows 7以及Nokia的Symbian和maemo平台,是不是还少了些什么?其实,Qt并没有忘记Windows CE和Windows Mobile。在Qt 4.6里面,修复了很多原有Windows CE平台上的Bug,并且提升了运行性能。

微软最近发布了Windows Mobile 6.5,而且相比于桌面系统,Windows Mobile是没有那么多预览版可以拿到的,所以在Qt 4.6中,就很难完全支持Windows Mobile 6.5了。不过也不全是坏消息,虽然不能完全支持,但一些主要的功能还是移植到了6.5的版本上:

-针对Windows Mobile 6.5的mkspecs

-支持Windows Mobile 6.5 风格,为Qt应用提供本地化的外观

-Qt 4.6的动画框架已被完全移植到Windows Mobile 6.5上

阅读全文…

Qt , , ,

Qt学习之路(18): Qt标准对话框之QInputDialog

2009年11月5日

这是Qt标准对话框的最后一部分。正如同其名字显示的一样,QInputDialog用于接收用户的输入。QInputDialog提供了一些简单的static函数,用于快速的建立一个对话框,正像QColorDialog提供了getColor函数一样。

首先来看看getText函数:

bool isOK;
QString text = QInputDialog::getText(NULL, "Input Dialog",
                                                   "Please input your comment",
                                                   QLineEdit::Normal,
                                                   "your comment",
                                                   &isOK);
if(isOK) {
       QMessageBox::information(NULL, "Information",
                                           "Your comment is: <strong>" + text + "</strong>",
                                           QMessageBox::Yes | QMessageBox::No,
                                           QMessageBox::Yes);
}

代码比较简单,使用getText函数就可以弹出一个可供用户输入的对话框:

200910311256957470355

下面来看一下这个函数的签名:

static QString QInputDialog::getText ( QWidget * parent,
                                                      const QString &amp; title,
                                                      const QString &amp; label,
                                                      QLineEdit::EchoMode mode = QLineEdit::Normal,
                                                      const QString &amp; text = QString(),
                                                      bool * ok = 0,
                                                      Qt::WindowFlags flags = 0 )

第一个参数parent,也就是那个熟悉的父组件的指针;第二个参数title就是对话框的标题;第三个参数label是在输入框上面的提示语句;第四个参数mode用于指明这个QLineEdit的输入模式,取值范围是QLineEdit::EchoMode,默认是Normal,也就是正常显示,你也可以声明为password,这样就是密码的输入显示了,具体请查阅API;第五个参数text是QLineEdit的默认字符串;第六个参数 ok是可选的,如果非NLL,则当用户按下对话框的OK按钮时,这个bool变量会被置为true,可以由这个去判断用户是按下的OK还是Cancel,从而获知这个text是不是有意义;第七个参数flags用于指定对话框的样式。

虽然参数很多,但是每个参数的含义都比较明显,大家只要参照API就可以知道了。

函数的返回值是QString,也就是用户在QLineEdit里面输入的内容。至于这个内容有没有意义,那就要看那个ok参数是不是true了。

QInputDialog不仅提供了获取字符串的函数,还有getInteger,getDouble,getItem三个类似的函数,这里就不一一介绍。

本文出自 “豆子空间” 博客,请务必保留此出处http://devbean.blog.51cto.com/448512/219338

Noshow ,

新的Qt学习实例

2009年11月4日

如果能从一些实际的例子开始,特别是比较实用的例子,那么学习Qt就会事倍功半。在网上偶然发现了这三个例子,发现相当不错,于是请人帮忙翻译,现在拿来以飨读者。

Code Project:创建一个媒体播放器
Code Project:创建一个FFMPEG前端
Code Project:创建一个Qt RSS阅读器

三个例子都比较长,但是由浅入深,解释的也很详细,非常有学习价值。大家可以耐心阅读,并亲自一试,也不枉翻译的辛苦工作。

Qt, Technology , , ,

Code Project:创建一个FFMPEG前端

2009年11月4日

命令行没有什么不好。对于我们很多人来说,这是使用Linux的最佳理由之一。可以通过输入内容实现几乎所有功能,而且命令行工具对于它们的运行方式通常能够提供极好的控制。但是命令行并不适合所有人,觉得命令行难以理解和令人生畏的Linux用户数量多得令人吃惊,这或许是完全避免使用Linux的理由之一。尽管如今不愿意使用命令行的用户可以不必再使用它,但这仍然意味着他们将遗漏一些很优秀的实用工具。

Qt正好可以扭转这种局面。它是为你最喜爱的命令行工具创建友好GUI的理想工具。它不需要任何顶级的编程技巧,而且工作量也不大,但在此过程中你可以为讨厌命令行的朋友提供帮助,并且对开源应用程序开发做出自己的贡献。为命令行工具创建GUI是最佳起点之一!

如果你已经完成了我们以前的Qt Creator代码项目,如何创建自己的媒体播放器,就能够更加自如地完成这个任务……

如果说有一种工具非常需要GUI,那就是FFMPEG。FFMPEG是一个十分优秀的命令行应用程序,它可以将视频和电影文件从一种格式转换为另一种格式。同时它的复杂程度也令人吃惊。有好几位开发人员都曾经试过为这个工具创建一个GUI,但是FFMPEG的发展速度让人很难驾驭所有额外的组件和用于各个选项的不断改变的语法。

我们将会构建我们自己的FFMPEG GUI,但本指南的意义并不在于帮助人们了解FFMPEG的非凡之处。本指南将展示为几乎任意命令行工具创建GUI是多么轻松的事情——只要替换几行代码即可,而且结果可能对我们大有好处。

qt_menq_step_01

* 应该只有意志坚定和不怕阅读符号文字的人才会输入“ffmpeg -h”

应用程序设计

我们将假定已经启动并正在运行Creator,而且对于使用开发环境相对比较满意。如果不满足上述条件,请复习我们以前的指南。运行应用程序之后,创建一个新的项目并使用“Qt Gui Application”模板,同时保留其他选项的默认值。

和以前的指南一样,我们的开发工作仍然从GUI开始。点击“.ui”文件,Designer视图随之出现。如果想从空白画布开始,可在视图中删除菜单栏、工具栏和状态栏,方法是在窗口右上方的对象视图中选中它们,右键单击每个组件,然后从出现的菜单中选择删除。

我们应用程序的GUI布局显然依赖于要运行的命令行工具。但对于我们的FFMPEG例子,我们要尽可能尝试保持内容的开放性和可修改性。我们需要一个按钮来添加要转换的源文件,以及一个用于显示此文件位置的文本字段。我们需要一些途径来选择转换过程的最终格式,并显示FFMPEG命令的结果。我们还需要另一个按钮,点击它便可启动整个转换过程。

但是用户界面的主要部分将会被我们选出让用户编辑的FFMPEG选项所占据。我们没有理由向普通用户公开FFMPEG中数以百计的选项,因此这里只会出现最常用和最简单的使用选项。

qt_menq_step_02

* 我们的目标是构建出的布局能够最好地利用空间。这也正是我们选择在另一个页面上隐藏命令行输出的原因。

GUI的构建

从左边的Button小部件列表中拖两个按钮到空白画布上,然后双击每个按钮,修改它们的名称。一个按钮的名称定为“Source”,而另一个用于触发转换过程的按钮则需要取类似于“Go!”的名称。另外还可以使用图标代替文本,或者二者同时出现亦无不可(如果这是一种改进的话)。现在从Inputs列表中添加一个Line Edit小部件,然后点击左下方面板中的“enabled”属性以禁用它。

由于Line Edit小部件是交互式的——即默认情况下,用户可以在里面输入内容——我们想禁用这项功能,而只使用它来显示我们要转换文件的源位置。如果想让用户手动输入或修改文件的名称和位置,可以保留此字段的值为enabled。

我们还为用户提供了一条选择输出格式的方便途径。我们选择使用一列单选按钮,每个单选按钮代表一种格式。从调色板中拖动Radio Button小部件即可添加这些按钮。这种方法的好处在于,每次只能选择一种格式,而这正是我们需要的行为模式。对于每个单选按钮,还需要将其标签的文本修改为能够反映适合FFMPEG输出的设备。例如,如果选择PSP作为输出设备,将禁用iPhone输出和GP2X输出。
为了最大程度利用可用空间,我们准备使用选项卡小部件来保存余下的参数。就像浏览器中的选项卡式web页面一样,允许用户在一块GUI区域的两种不同视图之间进行切换。我们将使用一个选项卡来保存要公开的主要参数,而另一个选项卡可用于保存来自FFMPEG的原始命令输出。这应该意味着,除非用户切换选项卡,否则不会看到乱七八糟的FFMPEG输出。

从Creator中的Containers列表把选项卡小部件拖到画布上,选中之后,点击属性列表中的“currentTabText”属性,以便修改每个选项卡上显示的文本。我们选择了“Options”和“Output”。

被拖到选项卡小部件中的任意小部件都只显示在当前选项卡上,因此我们给Options选项卡添加了5个组合框和5个标签。对于像FFMEG这样的工具而言,组合框是对用户最友好的选项,因为它们将可用选项限制为只出现有效的选项。它对于程序员意味着额外的工作,但这种额外工作可以为可怜的老用户节省很多时间。借助这5个组合框,我们选择支持如下配置:视频的分辨率、帧率和比特率,以及视频的采样率和压缩比特率。

我们重新命名了每个组合框小部件,以便在源代码中能够更好地区分它们,同时在每个组合框旁边放置一个标签,并使用标签文本对每个选项进行了说明。在组合框下面,我们添加了更多小部件,用于保存目的文件的名称—— 一个按钮用于选择文件,以及一个禁用的线编辑字段用于显示位置。

最后,切换到选项卡小部件的下一个页面,并添加一个TextBrowser小部件。我们将使用这个小部件来显示FFMPEG命令的输出。

间距器

现在,我们的应用程序看起来应该相当复杂了。我们需要对各个小部件进行排列,让它们能够很好地缩放并且看起来间隔均匀。Qt使用一个分组和间距器的系统来创建布局,但了解这个系统的使用原理需要花点功夫。它和DTP应用程序处理对象的方式不同。例如,要在选项页面中创建良好的布局,首先shift选择一个标签及其相关组合框,然后从工具栏选择“Lay Out Horizontally”。这将会把两个小部件锁定在并排的位置。

对其他小部件做同样的事情,然后shift选择用于修改视频设置的分组对,并选择“Lay Out Vertically”。这将把每对小部件都对齐到一列中,对音频设置也要做同样的事情。我们还为音频和视频列添加了标签,并在垂直布局集合中包含了它们。要想正确实现分组选择,过程更加麻烦,但如果犯错我们始终可以进行“Undo”和“Redo”操作。

qt_menq_spacers

最好把间距器看作弹簧,并重新复习一些旧的物理课本。

为了保证我们的GUI不会明显延伸为一个大窗口,我们需要使用“间距器”。它们看起来有点像弹簧,可以从小部件调色板添加垂直或水平的间距器。当在水平或垂直布局中包含一个正确的间距器时,小部件将会与一块可扩展空间组合在一起,这块空间就是弹簧所在的位置。如果应用程序窗口扩展或收缩,这块空间也会根据弹簧长度成比例地伸缩。

这用语言也许很难描绘,但只要动手实践便不难理解。最后的结果是布局系统十分灵活,但学习起来却比较困难。我们使用三个水平弹簧来分开视频和音频选项,以及它们与窗口边界的空间,同时使用一个垂直弹簧来将视频与音频编码选项和目的文件位置分开。间距器还可用于在单选按钮之间安插一点距离。

当我们大体上安排好所需要的一切小部件后,选择“Lay Out in a Grid”将所有小部件绑定到主窗口上。此时仍然能够拖动和添加小部件到布局上,但如果需要做较大的改动,则需要首先打破这种绑定,即选择“Break Layout”。

信号与槽

现在,可以把GUI设计与我们将要在源代码中添加的程序功能联系起来了。这要借助于我们前面提过的Qt的信号与槽机制。一开始,切换到Signals/Slots编辑模式(F4),并且从“Go”按钮拖出一个连接到窗口的背景画布上,用于有效地发送信号给MainWindow类。在出现的窗口中,点击左边的Edit按钮,从而打开Signals/Slots编辑窗口。

我们需要添加6个槽:executeCommand()、setSource()、setDestination()、setPSP()、setIPOD() 和 setGP()。点击OK,选择新创建的“executeCommand()”槽,然后连接到我们当前正在编辑的Go按钮的clicked信号。需要对我们刚刚为其创建了槽的其他每个按钮做同样的事情,方法是把它们连接到它们对应的槽。例如,应该把来自PSP单选按钮的“clicked()”信号连接到“setPSP()”。

qt_menq_step_03

我们从GUI创建我们自己的槽,而且后面需要在源代码编辑器中为它们添加代码。

完成这项任务之后,Designer编辑就结束了,保存项目并切换为编辑MainWindow.h。我们需要在文件顶部添加几个头:

#include <QProcess>
#include <QByteArray>
#include <QTextBrowser>
#include <QFileDialog>
#include <QDesktopServices>
#include <QComboBox>

因为我们要对已经在Designer中添加给应用程序的小部件进行操作,所以这些头文件中的大部分都是必不可少的。Qprocess和QbyteArray用于在Qt中运行外部的可执行文件,并抓取命令的输出,但我们很快就会讲到这个函数。现在,我们需要为要编写的槽添加定义。在“public:”部分下面添加如下代码:

private slots:
    void executeCommand();
    void outputCommand();
    void setSource();
    void setDestination();
    void setPSP();
    void setIPOD();
    void setGP();

最后,我们需要在头文件的“private:”部分中添加一个变量。此变量将用于在Qt中处理外部可执行文件(FFMPEG):

QProcess commandProcess;

qt_menq_step_04

* 我们从GUI创建我们自己的槽,而且后面需要在源代码编辑器中为它们添加代码。

编程

现在我们到了最富于技巧性的部分,即给应用程序添加功能。首先,我们要为三种要处理的不同输出格式编写“set”函数。这些函数都将使用与设备相关的参数填充组合框,而我们最终将采用这些参数来编译将创建正确输出的FFMPEG命令行。

当然,在能够给GUI添加值之前,首先针对每种格式要有一个有效的FFMPEG命令。例如,我们已经找到用于转换运行在PSP上的视频的最佳FFMEPG命令是:

ffmpeg -i space.mpg '-vcodec' 'libxvid' -s 320x240 -r 29.97 -b 1500 -acodec libfaac
-ac 2 -ar 24000 -ab 65535 -f psp M4V80113.mp4 -y

我们准备采用这些参数中的一部分,并使它们能够在我们的GUI中进行编辑。根据我们在其他项目中的经验,可以通过“ui”对象运行属于GUI中对象的方法,此对象默认是使用标准Creator模板创建的。例如,“ui->comboResolution->clear()”将在comboResolution组合框上执行清除工作。

Creator集成环境的好处在于,可以使用自动完成功能列出每个对象的可用选项,而不用全靠记忆。下面是我们在setPSP函数中换到GUI中的FFMPEG选项。需要把它添加到MainWindow.cpp文件的底部:

void MainWindow::setPSP()
{
    ui->comboResolution->clear();
    ui->comboFramerate->clear();
    ui->comboBitrate->clear();
    ui->comboSamplerate->clear();
    ui->comboAbitrate->clear();
    ui->comboResolution->addItem("240x320");
    ui->comboResolution->addItem("160x120");
    ui->comboFramerate->addItem("29.97");
    ui->comboBitrate->addItem("1500");
    ui->comboSamplerate->addItem("2400");
    ui->comboAbitrate->addItem("65535");
    ui->lineEdit_2->setText("M4V80113.mp4");
 
}

这段代码的自解释程度相当高。为了节省空间,我们将会给其添加多个选项的惟一组合框是分辨率框,但可以很容易地看到如何添加其他选项。我们还需要为其他两种预设置创建相同模板,并把它们放在“setIPOD”和“setGP”函数槽中。由于我们只选择了一个参数集合让用户编辑,因此需要将这些参数与FFMPEG命令中的其他参数结合起来,而我们准备在处理运行外部FFMPEG命令的函数中做这件事情,这个函数叫做“executeCommand()”。

执行一个命令

void MainWindow::executeCommand()
{
    QStringList args;
 
    args << "-i";
    args << ui->lineEdit->text();
    args << "-y";
    args << "-s"; args << ui->comboResolution->currentText();
    args << "-r"; args << ui->comboFramerate->currentText();
    args << "-b"; args << ui->comboBitrate->currentText();
    args << "-ar"; args << ui->comboSamplerate->currentText();
    args << "-ab"; args << ui->comboBitrate->currentText();
    args << ui->lineEdit_2->text();          
 
    if (ui->radioButton->isChecked()){
        args << "-vcodec"; args << "libxvid";
        args << "-acodec"; args << "libfaac";
        args << "-ac"; args << "2";
        args << "-f"; args << "psp";
    }
    commandProcess.start("ffmpeg", args);
 
}

下面是对于以上代码块作用的解释。在Qt中运行外部命令的关键是一个叫做“Qprocess”的类。在步骤三结束时,我们在头文件中使用这个类创建了我们自己的对象,现在正是时候使用它来执行FFMPEG。使用“commandProcess”变量时,我们只要使用两个变量运行“start”即可——命令本身和我们的参数列表。

我们使用“QstringList”来快速构造这个参数列表,首先从我们GUI中的小部件,然后是包含在有条件的“if”语句中的PSP特定参数(ui->radioPSP->isChecked)。需要为其他目的设备添加更多参数,才能让转换过程开始工作。

qt_menq_step_05

* 来自FFPMEG命令的输出将显示在我们的主应用程序的输出选项卡中。

在用户点击我们在GUI中创建的“Go”按钮时,将执行这个函数,而且由于我们早先配置好的信号和槽,这个过程也是自动的。但是我们还需要捕捉该过程的输出,以便在文本视图中显示出来,同时给用户提供一些可视的反馈。令人高兴的是,由于信号与槽的神奇魔力,Qprocess可以不太费力地完全执行这种操作。

在MainWindow::MainWindow初始化例行程序中,我们需要在Qprocess输出信号和我们将用于把输出转换为文本以便于显示的“outputCommand”槽之间手动创建连接。在“ui->setupUi”行前面添加如下两行:

connect (&commandProcess, SIGNAL(readyReadStandardOutput()),this, SLOT(outputCommand()));
connect (&commandProcess, SIGNAL(readyReadStandardError()),this, SLOT(outputCommand()));

正如我们看到的那样,从Qprocess发出的有两种类型的输出信号,而且我们将来自这两种信号的输出都发送给同一个函数“outputCommand”,现在需要把这个函数添加到源代码中:

void MainWindow::outputCommand()
{
    QByteArray cmdoutput = commandProcess.readAllStandardOutput();
    QString txtoutput = cmdoutput;
    ui->textBrowser->append(txtoutput);
    cmdoutput = commandProcess.readAllStandardError();
    txtoutput = cmdoutput;
    ui->textBrowser->append(txtoutput);
 
}

这是当Qt从运行“FFMPEG”的Qprocess检测输出时执行的函数。这有点繁复,因为我们不能假定命令的输出是文本,而且输出数据有两种流形式——一种用于来自命令的标准输出,而另一种用于错误输出。我们的安全做法是在使用Qt的优秀转换例行程序将这些数据转换为一个文本字符串之前,将流中的二进制数据复制到一个原始字节数组中。接着把这些数据添加到文本视图中,而且我们对于命令的错误输出重复这个过程。没有什么捷径可以同时抓取到这两种流。

最后,在完成我们的应用程序之前,最后一个步骤是添加两个槽,用于处理源和目的文件位置。这两个槽几乎是完全相同的。下面给出了处理目的文件位置的槽函数:

void MainWindow::setDestination()
{
    QString file = QFileDialog::getSaveFileName (this, tr("Select Destination"),
         QDesktopServices::storageLocation(QDesktopServices::MoviesLocation));
    ui->lineEdit_2->setText(file);
}

第一行创建了一个Qt文件请求器,自动指向系统默认的电影位置,而因为我们已经使用了“getSaveFileName”,用户将被询问一个不一定存在的文件的名称。这与“setSource”完全相反:

void MainWindow::setSource()
{
     QString file = QFileDialog::getOpenFileName(this, tr("Select Source File"),
         QDesktopServices::storageLocation(QDesktopServices::MoviesLocation));
    ui->lineEdit->setText(file);
 
}

输入这最后两个函数后,我们应用程序的源代码就已经完成了,应该有一个可用的FFMPEG GUI,可以自定义它以使用所需的任意参数。编译并运行就可以了。还应该看到,修改这些代码以使用其他命令行工具是多么轻松的事情。

qt_menq_final_pic

下载此项目的代码:qt_menq.tar

借助基于Qt的前端,用户就不必深入研究FFMPEG的命令行用法了。

原文:http://www.tuxradar.com/content/code-project-create-ffmpeg-front-end

翻译:CSDN

Noshow , , ,

Code Project:创建一个Qt RSS阅读器

2009年10月30日

我们将构建一个完整的应用程序,使其不必太费事便可重新发布为一个真正的开源应用程序。这个应用程序就是一个RSS阅读器,它允许用户添加自己的种子,列出该种子上的内容,然后让用户在主应用程序自带的一个浏览器窗口中阅读这些内容。

如果你已经尝试过了我们前两个Qt代码项目——创建一个ffmpeg前端创建一个媒体播放器,而且正在寻求更多Qt方面的乐趣,那么请读下去…

RSS是一个以特定方式进行格式化的XML文本文件。它包含对网站上每段内容的简短描述。它最大的优点就是,始终随着新内容的发布而更新。使用RSS阅读器或像Firefox这样与RSS兼容的浏览器时,用户可以从网站订阅RSS种子,而且阅读器将定期检查更新,并列出所有新的内容供用户浏览。而这也正是我们的应用程序所要实现的功能。

它还将引入一些主要的Qt技术,包括处理XML数据流的手段,如何动态填充树视图小部件,以及使用WebKit小部件并将所有小部件组合为一个可动态扩展的、将自动更新为显示web页面的应用程序窗口。这使得RSS阅读器成为启动更多目标远大的项目的最佳起点,即使你马上弃用RSS处理的代码,我们为这个应用程序所构建的可扩展GUI仍然可以发挥作用。

这正是首次运行Qt Creator并创建一个新项目时,需要选择三个单独的模块在应用程序中使用的原因。在向导中点击Qt4 GUI Application模块,给它取一个名字,然后启用如下三个模块:QtNetwork, QtWebkit 和 QtXML。这些模块将紧密联系我们将在本指南中讲到的三个新领域,而且从向导添加它们后,便不用再手动把它们添加到项目的“.pro”文件中。

设计GUI

和我们其他的Qt编程指南一样,在运行Creator创建一个新项目后,接下来要做的工作就是GUI设计。点击“ui”文件打开Designer视图。这一次,我们将采用稍微开放一点的方法进行设计。主窗口将被划分为两个面板。在左侧,我们将添加RSS消息列表,并让用户能够添加他们自己的种子。而窗口的右半部分将是web浏览器,我们将对这部分使用WebKit小部件。

但是Qt的聪明之处在于,我们可以根据用户是否想使用内部浏览器来使每个面板变得可扩展或可隐藏,或者干脆使用他们最惯于使用的浏览器。例如,如果用户不想看到web视图,只需要把中间的分离线拖到右边,它就会消失。这给予了我们的应用程序很大的灵活性,并不强迫想使用自己的浏览器阅读新闻的用户使用web视图。

这项特别的功能是通过Qt中的Dock Widget小部件实现的。当应用程序分为几个部分时,它提供了很强的灵活性,允许用户在四周拖放窗口的不同部分。从Creator页面的Containers列表中拖出两个Dock Widget小部件到空白的应用程序画布上。如果在应用程序中用不着,还可以从Object视图删除多余的菜单、工具栏和状态面板小部件。我们已经添加了两个可停靠小部件,因为我们要在应用程序的两侧使用它们来保存小部件,而且它们是可停靠小部件,用户能够拖动它们之间的分离线,从而改变应用程序每个半区的尺寸。

但在添加更多小部件之前,我们需要确保只启用了每个可停靠小部件的一组有限功能。我们不想让用户完全访问Qt 可停靠小部件更多难以驾驭的功能,KDevelop已经很好地证明了这一点。在Object列表中选择每个可停靠小部件,然后在下面的属性窗口中,确保将选中的“Features”字段设置为“NoDockWidgetFeatures”。这将阻止用户将小部件拖动至窗口外部或者完全关闭它们。你可能想对浏览器面板启用这项功能,这由你自己决定。

a

* 可停靠小部件的优点是,用户可在应用程序运行时改变两侧的比例差异。

小部件面板

在添加其他小部件之前,选择可停靠小部件并点击“Lay Out Horizontally”按钮。接着点击“Lay Out in a Grid”按钮。这样做的效果是同时拉伸跨应用程序窗口的、中间具有一条分离线的两个可停靠小部件。当用户改变主窗口的大小时,这两个小部件将保持它们的相对位置。

尽管网格被锁定,我们仍然能够以常规方式给可停靠小部件添加小部件,而且我们准备从左侧开始。如果在网格被锁定的情况下编辑GUI,Designer将使用蓝色光标突出显示每个小部件要插入的位置,这一点十分类似于字处理器。需要将三个小部件拖动到左边面板中——一个行编辑小部件和一个按钮,它们已经在窗口顶部水平对齐了,还有一个位于下方的树视图。行编辑小部件用于给用户输入RSS种子的URL,按钮用于提交种子给我们的解析器,而树视图用于列出RSS种子的每个入口。

我们给行编辑小部件添加了一个默认的URL。只要双击该小部件,然后输入类似于“http://www.qteverywhere.com/rss”的内容,再将按钮文本改为“Add Feed”。双击树视图,再添加两列,将它们分别取名为“Feed”、“Date”和“URL”。这些列将包含每个新闻内容的信息,但只有“Feed”和“Date”两列可见。这是因为我们要内部使用URL列,不显示给用户看。它将保存内容的URL,这样当用户点击它时,我们可以把URL发送给WebKit。

如果我们不使用这种方法,我们就不得不为应用程序实现一个成熟的MVC解决方案,而这描述起来都超过4页纸了。MVC(模型/视图/控制器)是一种将数据(在这个例子中是指URL)与显示数据的视图分离,同时保持二者联系的方法。后一部分由控制器来处理。当我们使用它的任意容器类时,Qt在后台使用的是MVC,而它用于添加和删除内容项的方法实际上是用于在后台处理MVC的便利函数。我们将在树视图中利用这一点,隐藏URL列并在应用程序中使用数据,但我们只能在源代码中做到这一点。

最后,将WebKit小部件拖动到右侧面板中。这是一个自包含的浏览器窗口,我们不需要添加任何别的内容就可以让它工作。只要保证所有小部件都经过了正确排列,以及你已经在两个面板上使用了一些间距器和“Lay Out in the Grid”模式,从而锁定可缩放窗口的布局。

a

* 在可停靠小部件的左侧,我们添加了树视图,XML 提要的 URL,以及用于从Internet抓取数据的按钮。

连接

既然我们的布局已经最终确定,下一步就要添加槽/信号连接,用于补充我们应用程序的功能。切换到Signals/Slots编辑器,方法是按下F4键或者在工具栏中点击相应按钮。从“Add Feed”按钮拖动一个信号到应用程序窗口的轮廓处,当“Configure Connection”窗口出现时,点击右侧面板上的“Edit”按钮。

我们需要添加两个槽。第一个用于给树视图添加种子,而另一个用于当用户在种子列表中选择一个新闻内容时更新web视图。我们将第一个槽称为“fetch()”,而将第二个槽称为“itemActivated(QTreeWidgetItem*)”。这是我们首次遇到通过信号/槽机制传递的参数,要在设计器中使用它们,必须满足一些严格的规则。其中最重要的一条是,对于一个在传递这类参数时要连接到槽的信号,二者都必须完全支持同一类型。在这个例子中是QTreeWidgetItem类型。

创建这两个槽并将“clicked”连接到“fetch()”之后,从树视图拖一个新连接到窗口背景。我们将看到,很多函数将QItemTreeTree参数作为一个参数包含在内。这是树视图中每一项的类型,以这种方式传递它使我们能够轻松抓取到当前选中的新闻内容的URL,并使用它来更新web浏览器。只要将位于左边的“’itemActivated(QTreeWidgetItem*)”与我们刚刚为自己的应用程序创建的名称相同的新槽连接起来即可。

c

* 这是我们在Creator中建立并用于应用程序中各个函数的SIGNAL和SLOT连接的一个视图。

代码

现在我们已经建立了框架,是时候添加代码了。和我们其他的项目一样,我们从“mainwindow.h”开始,把它作为需要添加我们刚刚在GUI中创建的新槽的地方。我们还准备添加要在程序逻辑中使用的新槽,用于告诉我们的应用程序,从Internet读取web数据的过程已经结束。

     void fetch();
     void itemActivated(QTreeWidgetItem * item);
     void readData(const QHttpResponseHeader &);

现在,我们需要给项目添加一些私有成员。我们将使用这些私有成员管理数据流,并且为解析从站点的RSS种子抓取到的XML数据和HTML数据而创建数据结构。

    void parseXml();
 
    QString currentTag;
    QString linkString;
    QString titleString;
    QString dateString;
 
    QTreeWidgetItem *feed;
 
    int connectionId;
    QHttp http;
    QXmlStreamReader xml;

这是我们需要给头文件添加的内容。我们余下的编码将限制在“mainwindow.cpp”文件中,从位于该文件顶部的初始化函数开始。首先,我们需要在“setupUi”前面添加一个连接行,用于当我们知道Qt的HTTP抓取器已经正确解析HTTP时,自动运行我们的“readyRead”方法。其次,我们想隐藏treeWidget的两列,因为我们只使用这些列来保存数据,而不想让用户看到它们。一旦“setupUi”创建了GUI,我们就可以这样修改它。下面给出相应的代码:

    connect(&http, SIGNAL(readyRead(const QHttpResponseHeader &)), this,
            SLOT(readData(const QHttpResponseHeader &)));
 
    ui->setupUi(this);
 
    ui->treeWidget->setColumnHidden(1, true);
    ui->treeWidget->setColumnHidden(2, true);

现在,我们准备编写fetch()函数。当我们在应用程序中输入RSS种子的URL,然后点击“Add Feed”按钮时,将触发这个函数的功能。

void MainWindow::fetch()
{
        xml.clear();
 
        QUrl url(ui->lineEdit->text());
 
        http.setHost(url.host());
        connectionId = http.get(url.path());
}

这段代码相对较为直观。首先,我们清理了保存XML日期的流读取对象,然后将我们用于保存URL的行编辑组件中的文本转换为一个QUrl,这是Qt中访问在线资源的首选方法。接下来,我们使用这个资源设定QHttp的位置,这个类是用于实现HTTP协议的。我们需要 使用这个类来抓取XML数据,而下一行中使用“get”函数和经过转换的URL调用了这个函数。当“http”成功打开HTTP位置时,它将发出我们前面连接到我们自己的“readData”函数的“readyRead”信号。现在我们需要添加这个函数:

 void MainWindow::readData(const QHttpResponseHeader &resp)
 {
     if (resp.statusCode() != 200)
         http.abort();
     else {
         xml.addData(http.readAll());
         parseXml();
     }
 
 }

这个函数的全部功能就是检查是否找到了URL,如果没有找到,它会中断,而且我们的应用程序也不会再往下执行。但如果远程位置是合法的,在把数据发送给“parseXML”函数之前,我们首先会使用数据填满我们的XML容器——xml.addData(http.readAll())。这是应用程序的一个难点,因为需要遍历从internet抓取的XML树,并把我们需要的数据块放到treeView中。因此,对应代码的篇幅要长很多。

 void MainWindow::parseXml()
 {
 
     while (!xml.atEnd()) {
         xml.readNext();
         if (xml.isStartElement()) {
 
             if (xml.name() == "item"){
 
                 if (titleString!=""){
                    feed = new QTreeWidgetItem;
                    feed->setText(0, titleString);
                    feed->setText(2, linkString);
                    ui->treeWidget->addTopLevelItem(feed);
 
                 }
 
                 linkString.clear();
                 titleString.clear();
                 dateString.clear();
             }
 
             currentTag = xml.name().toString();
         } else if (xml.isEndElement()) {
              if (xml.name() == "item") {
 
                 QTreeWidgetItem *item = new QTreeWidgetItem(feed);
                 item->setText(0, titleString);
                 item->setText(1, dateString);
                 item->setText(2, linkString);
                 ui->treeWidget->addTopLevelItem(item);
 
                 titleString.clear();
                 linkString.clear();
                 dateString.clear();
             }
 
         } else if (xml.isCharacters() && !xml.isWhitespace()) {
             if (currentTag == "title")
                 titleString += xml.text().toString();
             else if (currentTag == "link")
                 linkString += xml.text().toString();
             else if (currentTag == "pubDate")
                 dateString += xml.text().toString();
         }
     }
     if (xml.error() && xml.error() != QXmlStreamReader::PrematureEndOfDocumentError) {
         qWarning() << "XML ERROR:" << xml.lineNumber() << ": " << xml.errorString();
         http.abort();
     }
 }

这段代码看起来有点吓人,但这主要是因为它包含了几条嵌套的“if”语句,用于处理我们在RSS种子中将会遇到的不同类型的XML元素。

我们从依次读取每个元素开始,然后检查该元素在树上是属于新的内容项,一个元素的末端,还是包含真正的元素数据。

当代码检测到XML种子中一个新元素的起点时,它会将“currentTag”设为该元素中所包含数据的类型。我们只对“title”、“link”和“pubDate”字段感兴趣,而且当XML流移动到文件的字符部分时,每个字段的文本就会根据currentTag类型转移到“titleString”、“linkString”和“dateString”中。当检测到一个元素的终点时,我们已经知道这些字符串是否已经被填充,以及是否可以把数据复制到我们GUI中的“treeView”对象中。这就是“item->setText”行的作用,而这些字符串被添加到一个treeView顶部的内容项中,该treeView创建来保存“StartElement”部分中的每个RSS种子的树视图。

如果我们在理解这个函数时有困难,使用Creator的优秀调试器把代码完整地运行一遍,会对我们有所帮助。如果在这个函数中设置一个断点,当应用程序的执行到达代码的这个部分时,我们就能够使用Debug菜单单步调试每一行,并监视感兴趣参数的值。

最后,我们需要添加的最后一个函数是用于在用户点击RSS新闻项之一时,将该新闻项指向的web页面装载到我们的WebKit小部件中。这个函数是使用我们在GUI设计器中建立的“itemActivated” SIGNAL/SLOT连接来执行的。我们从树小部件内容项中找到了由信号传递的URL,并把这些数据发送给webView小部件,然后把它转换为一个QUrl,而我们也正是这样做的。幸运的是,此功能一共只需要两行代码:

 void MainWindow::itemActivated(QTreeWidgetItem * item)
 {
     ui->webView->load(QUrl(item->text(2)));
     ui->webView->show();
 
 }

d

* 尝试使用调试器来理解我们项目中一些更为复杂的函数。

运行应用程序

以上就是需要完成的全部工作。剩下的就是保存项目,编译和运行。点击“Add Feed”按钮可以添加我们在GUI中创建的默认RSS种子,而且我们应该看到,位于左侧的树视图使用了来自TuxRadar.com的所有最新内容进行填充。点击其中任意的内容,右侧的web查看器就会加载相应的页面。

但这个应用程序的最大优点是缩放两个面板的方式。在树视图和web页面之间,应该能够找到三个很小的垂直点。可以把这些点拖到左边或右边,从而改变RSS种子或正在显示的web页面的比例。如果将这一条完全移到右边,web视图就会完全关闭。如果我们只想看到种子列表,这是个不错的主意。

可以轻松给这个应用程序添加所需要的内容。我们从一个具有自动功能的刷新按钮开始。这个按钮功能是大约每小时增加一次新种子,或者在点击它时手动刷新。应用程序还迫切需要保存其设置的功能。这是一项十分艰巨的任务,几乎可以作为另一份指南的主题——为什么不亲自写写试试看呢?

e

完成之后的应用程序:密切注意Akregator,我们的RSS应用程序是跨平台的,而且使用WebKit来呈现web页面。

下载源代码:qt_mrss.tar

原文链接:http://www.tuxradar.com/content/code-project-create-qt-rss-reader
翻译CSDN:http://qt.csdn.net/articles.aspx?pointid=178

Noshow , , , ,