文章翻译自 Qt 文档里的一个教程,原文地址为 http://doc.qt.io/qt-4.8/gettingstartedqt.html .
欢迎来到 Qt ──一个跨平台 GUI 工具集── 的世界。在这个新手教程里,我们将通过实现一
个简单的 Notepad 应用程序来教授基本的 Qt 知识。在完成这个引导之后,你应该可以通
过自己查阅我们的概述和 API 文档来找到开发你自己应用所需要的信息。
这个教程里的代码在你 Qt 安装目录下的examples/tutorials/gettingStarted/gsQt
。如
果你正在使用 Qt SDK,你会在Examples/4.7/tutorials/gettingStarted/gsQt
下找到它
(如果你用的 Qt 版本比较新,把 4.7 改为相应的值)。
Hello Notepad
在这第一个例子中,我们只是在桌面上简单地建立并显示一个窗口(window frame),里面是
一个文本框(text edit)。这展示了有 GUI 的最简单的 Qt 程序。
代码如下:
1 |
|
让我们一行一行地来看一看。前两行中,我们包含了QApplication
和QTextEdit
所需要
的头文件,我们的例子中要用到这两个类。所有的 Qt 类都有一个根据它命令的头文件。
第 6 行新建了一个QApplication
对象。这个对象管理整个应用(application-wide)的资
源并且是所有有 GUI 的 Qt 程序必需的。因为 Qt 接受一些命令行参数所以需要argv
和args
。
第 8 行新建了一个QTextEdit
对象。文本框(text edit)是 GUI 里的一个可见元素。在
Qt 中,我们把这样的元素叫做widget
。其他的 widget 还包括滚动条(scroll bar),标
签(label)和单选按钮(radio button)。一个 widget 也可以包含其他 widget 的容器,比
如对话框(dialog)或者主程序窗口(main application window)。
第 9 行显示一个处于窗口中的文本框。由于widget也有容器的功能(比如一个QMainWindow
会包含工具栏,菜单,状栏和其他一些 widget),使得让一个 widget 在它自己的窗口中
显示也是可能的。Widget 默认不可见,函数show()
可以使它们可见。
第 11 行使得 QApplication 进入它的事件循环。当一个 Qt 程序运行时,会有事件产生并
被发送给程序的 widget。按下鼠标和键盘按键都是事件。当你在文本框中输入文本时,它
会收到按键按下的事件并以画出输入的文本作为响应。
要运行这个程序,打开一个命令窗口,进入 .cpp 文件所在的那个目录。以下的 shell 命
令会构建这个程序。
1 | qmake -project |
这会在part1
目录下生成一个可执行文件(在 Windows 下,你可能要使用 nmake 而非
make。且可执行文件会被放在part1\debug
或part1\release
目录下(这些目录在运行
make时生成))。qmake
是Qt的构建工具,它需要一个配置文件。如果指定了-project
选项的话qmake
会为我们生成。给定了配置文件(后缀为 .pro),qmake
会
生成一个给make
命令使用的文件,它会帮你构建这个程序。我们会在以后讲解编写自己的
.pro 文件。
Learn More
About | Here |
---|---|
Widgets and Window Geometry | Window and Dialog Widgets |
Events and event handling | The Event System |
添加退出按钮 Adding a Quit Button
在一个真实的程序里,通常会需要不止一个 widget。我们现在将要在文本框下面添加一个QPushButton
。这个按钮在被按下时会退出 Notepad 程序。
先看一眼代码。
1 |
|
第 1 行包含了 QtGui
,里面包括了所有的 Qt 的 GUI 类。
第 10 行使用了 Qt 的 Signal/Slot 机制使得当退出按钮被按下时程序能够退出。Slot 是
一个在运行时可以通过名字(作为字符串)被调用的函数。Signal 是一个函数,被调用时会
调用与之注册的 Slots;我们把这称为‘关联 slot 和 signal’以及‘产生 signal’。
quit()
是QApplication
退出程序的 slot。clicked()
是QPushButton
被按下时发出
的 signal。静态方法QObject::connect()
将 slot 和 signal 关联起来。SIGNAL()
和SLOT()
是两个宏,它们接受要关联的 signal 和 slot 的函数签名。我们还需要给定发出
和接受信号的对象的指针。
第 12 行创建了一个QVBoxLayout
。正如前面所说,widget 可以包含其他 widget。直接
设置一个子 widget 的边界(位置和大小)是可以的,但使用 layout 通常更简单。layout
会管理子 widget 的边界。QVBoxLayout
会将子 widget 放在一竖列上。
第 13~14 行把文本框和按钮添加到 layout 里。在 17 行中,我们将设置了一个 widget
的 layout。
Learn More
About | Here |
---|---|
Signals and Slots | Signals & Slots |
Layouts | Layout Management, Widgets and Layouts, Layout examples |
The widgets that come with Qt | Qt Widget Gallery, Widget Examples |
Subclassing QWidget
当用户想要退出程序时,你可能想要弹出一个对话框请求确认。在这个例子里,我们创建一
个QWidget
的子类并添加一个我们关联到退出按钮的 slot。
请看代码:
1 | class Notepad : public QWidget |
Q_OBJECT
宏必须在类定义的第一行从而将类声明为QObject
(自然地,它必须也继承自QObject
)。QObject
为普通的 C++ 类增加了些许功能。重要地功能如,类名和 slot 名
可以在运行时被查询。查询一个 slot 的参数类型并调用它也是可行的。
第 9 行声明了 slot quit()
。使用 slots
宏可以很简单地做到。quit()
这个 slot
可以被关联到 signal 了。我们一会儿再做这件事。
这次我们不再 main() 函数中设置 GUI 和关联 slot 了,而是使用 Notepad 的构造函数。
1 | Notepad::Notepad() |
如你在类定义中所见,我们使用了指向QObject
(textEdit 和 quitButton)的指针。作为
规定,你应该总是在堆上分配QObject
且永不复制它们。
我们使用函数tr()
处理用户可见字符串。当你想为你的程序提供不止一种语言的支持(如
英语和汉语)时就是必需的。我们不会在此详述,你可以点击 Learn more 表中的链接查看
更多信息。
下面是 slot quit()
的代码:
1 | void Notepad::quit() |
我们使用QMessageBox
类来显示一个对话框询问用户是否确认退出。
Learn More
About | Here |
---|---|
tr() and internationlization | Qt Linguist Manual, Writing Source Code for Translation, Hello tr() Example, Internationalization with Qt |
QObjects and the Qt Object model (This is essential to understand Qt) | Object Model |
qmake and the Qt build system | qmake Manual |
建立 .pro 文件
在这个例子中,我们会创建自己的 .pro 文件,而不是使用 qmake 的 -project 选项自动
生成。
1 | HEADERS = notepad.h |
使用 QMainWindow
很多应用程序可以从QMainWindow
中获益,它有自己的 layout,你可以向其中添加菜单栏,
widget,工具栏和状态栏。QMainWindow 有一个中间区域,任何 widget 都可以使用。在我
们的例子中,我们会把文本框放在那儿。
让我们来看看新的 Notepad 类定义。
1 |
|
我们多包含了两个 slot 用来保存和打开文档。我们会在下一节实现他们。
在一个主窗口中,相同的 slot 经常会被多个 widget 调用。比如菜单项和工具栏上的按钮。
为了使这种情况变得简单,Qt 提供了QAction
,它可以被多个 widget 拥有,并且被关联
到同一个 slot 上。例如,QMenu
和QToolBar
都可以从相同的 QAction 创建菜单项或工
具按钮。我们马上就会看到这怎么做到。
像以前一样,我们使用 Notepad 构建函数来设置 GUI。
1 |
|
QAction 应该在创建时给定它们在其它 widget(我们用的是菜单项)上应该显示的文字。
如果我们还想把它添加到工具栏上,我们还可以指定图标。
现在当一个菜单项被点击时,就会触发相应的行为,对应的 slot 也会被调用。
Learn More
About | Here |
---|---|
Main Windows and main window classes | Application Main Window, Main Window Examples |
MDI applications | QMdiArea, MDI Example |
保存和载入
在这个例子中,我们会实现前面例子中添加的open()
和save()
两个 slot 的功能。
我们从open()
开始:
1 | void Notepad::open() |
第一步是询问用户要打开的文件名。Qt 提供了QFileDialog
,用户可以通过它选择一个文
件。上面的图片展示的是 Kubuntu 上的对话框。静态方法getOpenFileName()
会展示一个
文件对话框。它会返回所选文件的路径,如果用户取消了对话框则返回空字符串。
如果我们有一个文件名,我们就使用open()
打开它,如果可以打开会返回 true。我们在
这里不会深入错误处理,你可以点击查看更多处的链接了解更多。如果文件不能打开,我们
用 QMessageBox 显示一个带错误信息的对话框(查看 QMessageBox
类描述可以了解更多)。
现在我们再来看看save()
。
1 | void Notepad::save() |
我们把文本框内容写入文件时,又用到了 QTextStream 类。QTextStream 还可以使用 <<
操作符把 QString 写入文件。
Learn More
About | Here |
---|---|
Files and I/O devices | QFile, QIODevice |
后记
原以为翻译完这篇就知道个大概了,谁知道官方的教程这么不友好,后面的代码不完整,没
有 main 函数,完全不知道怎么使用定义好的类,真是无语了。
后面自己查了一些资料,好像也不太难,不过怎么也是面向新手的,不能这样吧。大概可以这样使用:
1 |
|
编译运行方式与前面相同。