4.2 Qt设计器绘制主窗口
创建应用程序主窗口界面主要有两种方式:
(1)全部代码生成,单继承QMainWindow类,在子类的实现文件中使用代码创建应用程序主窗口的菜单、工具栏、锚接部件及状态栏等并设置它们的属性;使用单继承Qt窗口部件类的方法生成中心部件并添加到主窗口中。
(2)Qt设计器绘制应用程序主窗口,在Qt设计器中添加菜单(以及子菜单和动作)、工具栏(以及动作)、锚接部件(以及子窗口部件)、状态栏(目前,Qt设计器没有提供状态栏的设计编辑功能,比如无法将窗口部件直接拖放到主窗口的状态栏上)等并设置它们的属性,以及关联一些基本的信号和槽;然后采用前面介绍的“单一继承方式”或“多继承方式”实现应用程序主窗口的代码。
一般的,第二种方法创建应用程序主窗口比较快捷。下面在Qt设计器中对应用程序主窗口进行初步的设计和绘制。
在Qt设计器中的“new form”对话框中选择“Main Window“选项,单击“create”按钮,创建应用程序的主窗口。选择“Tools”菜单的“Object Inspector”子菜单,在Qt设计器的对象监视器中,可以看到,应用程序主窗口的对象名字为MainWindow,同时Qt设计器也已经创建了一个中心部件centralwidget、一个菜单栏menubar和一个状态栏statusbar。通过Qt设计器的属性编辑器,可以修改这些窗口部件对象的属性(包括它们的名字等)。在此,采用默认值。
将创建的主窗口ui文件保存在下面创建的KDevelop工程的src目录下(chapter04/designmaindow/src),文件名为“mainwindow.ui”。
现在,将主窗口引入到应用程序中,以便我们一边在Qt设计器中绘制主窗口界面,一边可以运行应用程序直接查看绘制效果(在Qt设计器中也可以预览绘制的GUI用户界面,通过菜单“Form”|“Preview” 可以做到,或者直接在键盘上激活快捷键“Ctrl + R”)。
建立KDevelop工程designmainwindow;
新建CMainWindow类的头文件mainwindow.h,并添加到工程中;
// chapter04/designmainwindow/src/mainwindow.h. #ifndef _MAINWINDOW_H_ #define _MAINWINDOW_H_ #include "ui_mainwindow.h" class CMainWindow : public QMainWindow, public Ui_MainWindow { Q_OBJECT public: CMainWindow(QWidget* = 0); }; #endif
新建CMainWindow类的实现文件mainwindow.cpp,并添加到工程中。
// chapter04/designmainwindow/src/mainwindow.cpp. #include <QtGui> #include "mainwindow.h" CMainWindow::CMainWindow(QWidget* parent) : QMainWindow(parent) { setupUi(this); showMaximized(); }
QQMainWindow::showMaximized()函数最大化显示应用程序主窗口界面。
在mainwindow工程中修改src目录下的主程序源文件designmainwindow.cpp;
// chapter04/designmainwindow/src/designmainwindow.cpp. #include <QtGui> #include <QtCore> #include "mainwindow.h" int main(int argc, char* argv[]) { QApplication app(argc, argv); QTextCodec::setCodecForTr(QTextCodec::codecForName("gb18030")); QTranslator translator; { QStringList environment = QProcess::systemEnvironment(); QString str; bool bFinded = false; foreach(str, environment) { if(str.startsWith("QTDIR=")) { bFinded = true; break; } } if(bFinded) { str = str.mid(6); bFinded = translator.load("qt_" + QLocale::system().name(), str.append("/translations/")); if(bFinded) qApp->installTranslator(&translator); else qDebug() << QObject::tr("没有支持中文的Qt国际化翻译文件!"); } else { qDebug() << QObject::tr(" 必须设置QTDIR环境变量!"); exit(1); } } CMainWindow mainWindow; return app.exec(); }
将mainwindow.ui文件加入到qmake工程中。
现在编译运行应用程序,可以看到一个没有任何内容的主窗口。
4.2.1 菜单
在一个大型的应用程序中,菜单往往是不可或缺的,它为客户提供了简便快捷的操作模式。菜单有两种:主菜单(或下拉菜单)和上下文菜单。主菜单的位置是固定的,即在应用程序主界面的顶部;上下文菜单一般在用户单击鼠标右键时出现在鼠标的位置,应用更加灵活方便。
下面学习创建应用程序主窗口的主菜单。
默认情况下,Qt设计器已经生成一个名字为“menubar”的主菜单栏,如图4-2所示。
图4-2 默认的主菜单
通过在菜单栏上单击鼠标右键,可以选择Qt设计器的上下文菜单命令“Remove Menu Bar”移除菜单(如图4-3所示);移除之后也可以通过上下文菜单命令“Create Menu Bar”再次添加一个新的菜单条(如图4-4所示)。
图4-3 移除主窗口菜单条
图4-4 添加主窗口菜单条
接下来要做的是,在主菜单栏上添加/编辑菜单和子菜单。
下面,按步骤建立“文件”菜单。
在主窗口上双击“type here”,在出现的文本框中输入第一个菜单的名字“文件(&F)”,并按回车键。括号中的“&F”表示将字符F作为“文件”菜单显示文本的助记符(在字母F下加下画线,即显示为“文件(F)”),作用是将“Alt + F”设置为加速键(accelerator)。当应用程序处在活动状态时,通过按下加速键“Alt + F”,就可以将“文件”菜单激活;或者主窗口的菜单栏处在活动的状态下(通过按键“Alt ”就可以将菜单栏激活),在键盘上直接按下“F”键就可以激活“文件”菜单。
这时Qt设计器会自动显示需要建立的“文件”菜单。接着,输入菜单命令的名字“新建(&N)”,“打开(&O)...”和“关闭”&C”。“&N”,“&O”和“&C”定义了子菜单的加速键,它们必须在“文件”菜单处在激活的状态下才有效,即在文件菜单活动的状态下,通过直接按键“N”、“O”和“C”可以激活“新建”、“打开”和“关闭”菜单命令。
双击菜单底部的“add separator”,在“关闭”菜单命令后面添加一条分隔线。
建立“保存(&S)...”和“另存为(&A)...”菜单命令。
加一条分隔线,建立“退出(&X)”菜单命令。
在对象监视器(Object Inspector)中单击需要修改属性的动作QAction(对应于菜单命令),接着在“属性编辑器”中修改菜单动作的属性;在此,修改动作的对象名字(objectName),并添加必要的快捷键(shortcut属性,选中shortcut属性后,直接按键就可以了,比如“Ctrl+S”,如图4-5所示)。文件菜单属性表如表4-1所示。
图4-5 设置快捷键
表4-1 “文件”菜单属性表
笔者建议一边添加菜单命令,一边修改动作的对象名字,以免造成混乱,防止对象名字的张冠李戴。如果实在不知道那个菜单命令对应哪个动作,可以在相应的菜单命令上点击鼠标右键,这时会出现一个文本为“Remove action ‘xxx’”的上下文菜单命令,这样就知道单击的这个菜单动作的对象名称叫xxx了。如果仅仅修改动作的显示文本、对象名称或者添加图标,也可以在动作编辑器中双击某个动作,然后在“Edit Action”对话框中进行编辑,如图4-6所示。
建好后的菜单如图4-7所示。
图4-6 编辑动作
图4-7 创建“文件”菜单后的主窗口
现在通过相同的方式,添加“编辑”菜单,如图4-8 所示。“编辑”菜单属性如表4-2 所示。添加“工具”菜单,如图4-9所示。“工具”菜单属性如表4-3所示。
图4-8 创建“编辑”菜单后的主窗口
图4-9 创建“工具”菜单后的主窗口
表4-2 “编辑”菜单属性表
表4-3 “工具”菜单属性表
在上述过程中,如果要删除一个菜单(或菜单命令),可以在相应的菜单(或菜单命令)上单击右键,在弹出的快捷菜单中选择“Remove action‘xxx’”或者“Remove Menu‘xxx’”就可以了。
保存绘制的主窗口界面文件,编译运行应用程序,看一下刚刚绘制的应用程序主窗口菜单。
4.2.2 工具栏
对于用户而言,工具栏提供了一种更简捷的实现用户操作意图的操作模式,不用拉下菜单或者记住具体的按键,工具栏就出现在用户的面前。为了适应不同的用户,大型的应用程序往往提供很多的工具栏,而工具栏的缺点就是它要占据GUI用户界面空间。因此,往往只有用户最常用的命令放置在工具栏中,同时工具栏也可以根据用户的喜好关闭或打开。
现在,在Qt设计器中建立两个工具栏:“文件”工具栏和“编辑”工具栏,分别对应于应用程序主窗口的“文件”菜单和“编辑”菜单的某些常用功能。
首先添加“文件”工具栏。
在Qt设计器中,在应用程序主窗口中单击鼠标右键,在弹出的上下文菜单中选择“Add Tool Bar”命令,在应用程序主窗口的顶部、主菜单的下面添加一个空白的工具栏,在属性编辑器中修改工具栏的对象名字为“fileToolBar”;
接下来,设计工具栏的动作(actions)。因为在绘制主菜单的时候,Qt设计器已经生成了“文件”菜单的动作,因此我们可以直接利用已存在的动作。选择Qt设计器的菜单 “Tools” |“Action Eidtor”,打开动作编辑器。可以看到所有的Qt设计中创建的动作,如图4-10所示。
图4-10 已添加的主菜单的动作
将动作编辑器中的动作actNew、actOpen、actSave和actASave拖放到添加的“文件”工具栏上,如图4-11所示。
图4-11 “文件”工具条按钮
通过同样的方法添加“编辑”工具栏“editToolBar”,并将动作actUndo、actCut、actCopy和actPast拖放到编辑工具栏上,如图4-12所示。
图4-12 “编辑”工具条按钮
目前,这些动作是没有图标的。为了更直观地在工具栏上显示这些动作,现在给它们添加必要的图标。步骤如下:
打开资源编辑器,新建资源文件mainwindow.qrc,保存在src/images目录下。
为资源文件添加图标资源,添加图标资源后的资源编辑器如图4-13所示(假设src/images目录下已经存在这些图标资源)。
在动作编辑器中双击“打开”动作actOpen,打开“Edit action”对话框,如图4-14所示。
图4-13 创建主窗口的资源文件
图4-14 为动作添加图标
单击“icon”标签右侧的“…”按钮,弹出“Find icon”对话框,在对话框中选择“Specify resource”单选框,在图标资源列表中选择open.png图标,单击“确定”按钮,如图4-15所示。
重新返回到“Edit action”对话框,这时候图标已经添加到“icon”标签右侧的按钮上,如图4-16所示。
图4-15 指定图标资源
图4-16 添加图标后的动作
在“Edit action”对话框中单击“确定”按钮,图标会自动出现在 “文件”| “打开” 菜单、“文件”工具栏以及动作编辑器中的actOpen动作上。
通过上述步骤,依次为工具栏上的其他动作添加图标,添加图标后的工具栏如图4-17 所示。添加图标后的动作编辑器如图4-18所示。
图4-17 添加图标后的工具栏
图4-18 添加图标后的动作编辑器
建好工具栏及其工具按钮后,为了使图标在应用程序运行的时候能够可见,还必须要在src目录下的qmake工程文件src.pro中添加下列语句:
RESOURCES += images/mainwindow.qrc
修改后的工程文件src.pro的内容如下所示。
FORMS += mainwindow.ui HEADERS += mainwindow.h SOURCES += designmainwindow.cpp \ mainwindow.cpp TARGET=../bin/designmainwindow RESOURCES += images/mainwindow.qrc
建立工具栏后,还可以将工具栏拖动到主窗口的左边、右边和下边。将鼠标放在工具栏的左侧且当鼠标变为十字形“+”时按住鼠标左键拖动即可。此外,也可以设置工具栏的一些属性,例如,属性“movable”定义工具栏是否可以被拖动;属性“layoutDirection”定义动作在工具栏上排列的顺序(从左到右或从右到左),等等。
除了利用建立主菜单时添加的动作之外,还可以独立建立新的动作。步骤如下:
在动作编辑器中单击“新建”按钮。
在出现的“New Action”对话框中输入动作的文本Text,输入对象名字Object Name,选择动作的图标(如图4-14和图4-16所示)。
单击“确定”按钮,完成动作的新建。
这些新建的动作可以不在Qt设计器中直接使用。保存好Qt设计器绘制的主窗口的时候,Qt设计器便保存了设计的动作、资源文件等等。uic编译器会根据ui文件生成创建这些动作对象的代码。之后,可以在应用程序中直接使用代码操控这些动作,比如关联它们的信号和槽、设置动作的一些属性等等。
保存绘制的应用程序主窗口,在KDevelop中编辑应用程序。在主程序源文件designmainwindow.cpp中,在初始化CMainWindow对象之前的位置添加如下语句:
Q_INIT_RESOURCE(mainwindow);
现在编译运行应用程序,可以看到我们添加的工具条及其按钮以及菜单中的图标。
4.2.3 中心部件
在Qt设计器中绘制应用程序主窗口的时候,Qt已经为主窗口自动生成了一个名字为centralwidget的、类型为QWidget的中心部件,只不过它是空白的,没有任何内容,因此我们很难看到它。不过在Qt设计器的对象监视器中,可以一目了然地看到它的存在。主窗口类QMainWindow的中心部件可以有多种类型:
● Qt提供的标准窗口部件,比如QWidget、QTextEdit等;
● 用户自定义的窗口部件,比如在第3章绘制的查找文件窗口部件;
● 分裂器——QSplitter,QSplitter作为一个容器可以容纳多个Qt窗口部件,此时中心部件是一个包容多个窗口部件的容器;
● 工作空间部件(workspace)——QWorkspace,在一个MDI应用程序中,应用程序主窗口的中心部件是一个QWorkspace部件;
● 多文档区部件——QMdiArea,它是Qt4.3新增的一个支持多文档的类,用法同Qworkspace有些类似。
本章的例子是一个简单文本编辑器,我们把QTextEdit作为应用程序主窗口的中心部件:
在Qt设计器左侧“Widget Box”框中,选择“Input Widgets”中的TextEdit窗口部件,并将它拖放到主窗口中,属性采用默认值。
将主窗口放置在一个垂直布局管理器中,添加中心部件后的主窗口如图4-19所示。
图4-19 添加中心部件后的主窗口
现在,再次打开对象监视器,可以看到,刚添加的QTextEdit窗口部件对象textEdit作为中心部件的一个子窗口部件而存在。但这并不影响对textEdit窗口部件的使用。
注意
Qt应用程序的主窗口能够实现对中心部件的自动管理。在主窗口已经存在中心部件的情况下,如果再通过QMainWidget::setCentralWidget()函数为主窗口设置一个新的中心部件,那么原来的中心部件将会被主窗口销毁掉。这时候,如果再引用原来的中心部件的话(包括delete该对象),将会造成应用程序崩溃。
QTextEdit是一个功能强大的Qt GUI类,是一个高级的所见即所得(What You See is What You Get, WYS/WYG)视图/编辑器(viewer/editor),在处理大文档文件时,做了优化处理,能够快速响应用户的输入。它支持普通文本的显示、编辑,能够加载HTML格式的文本,可以显示表格、图片和列表等等。此外,QTextEdit绑定了一些阅读文件时常用的导航键,如表4-4所示。
表4-4 QTextEdit窗口部件的导航键表
此外,QTextEdit类提供了上下文菜单,菜单内容包括撤销、恢复、剪切、复制、粘贴、删除及选择全部和插入Unicode字符等,如图4-20所示。
图4-20 QTextEdit窗口部件的上下文菜单
功能强大的QTextEdit类极大地简化了文本编辑器的实现,无需编程就能够实现文本编辑器常用的快捷键和上下文菜单。
现在重新保存用户界面文件,在KDevelop中编译运行应用程序。