4.3 代码创建主窗口
前面详细阐述了如何在Qt设计器中绘制应用程序的主窗口,这种方法的特点是直观形象,所见即所得。现在通过手写代码实现应用程序主窗口的创建,有时候手动创建主窗口会比较快捷。之所以提供两种方法创建应用程序的主窗口,主要是为了进行互补。程序员在创建应用程序主窗口的时候,在开发程序的不同阶段,可以有一种选择。如果读者仅仅对Qt设计器绘制主窗口感兴趣,完全可以忽略本小节。
首先,创建一个名字为“codemainwindow”的新的KDevelop工程(源码路径为chapter04/codemainwindow)。修改src目录下主程序文件codemainwindow.cpp,内容和designmainwindow.cpp的完全相同。
下面依次为工程添加资源文件和主窗口的实现类。
4.3.1 创建资源文件
在新建KDevelop工程的src目录下创建新的目录images。接着,将必要的图标资源复制到images目录下。然后,在images目录下创建资源文件mainwindow.qrc文件,编辑该文件添加相应的图标资源。mainwindow.qrc的内容如下。
<RCC> <qresource> <file>asave.png</file> <file>copy.png</file> <file>cut.png</file> <file>new.png</file> <file>open.png</file> <file>paste.png</file> <file>save.png</file> <file>undo.png</file> </qresource> </RCC>
4.3.2 定义主窗口类
为KDevelop工程添加新的头文件mainwindow.h,该文件给出了主窗口类CMainWindow的定义。文件内容如下所示。
// chapter04/codemainwindow/src/mainwindow.h. #ifndef _MAINWINDOW_H_ #define _MAINWINDOW_H_ #include <QMainWindow> class QTextEdit; class CMainWindow : public QMainWindow { Q_OBJECT public: CMainWindow(QWidget* = 0); private: QMenu* menu_F; QMenu* menu_E; QMenu* menu_T; QToolBar* fileToolBar; QToolBar* editToolBar; QAction* actNew; QAction* actOpen; QAction* actClose; QAction* actSave; QAction* actASave; QAction* actQuit; QAction* actUndo; QAction* actCut; QAction* actCopy; QAction* actPast; QAction* actAll; QAction* actFind; QTextEdit* textEdit; void iniMenu(); void iniToolBar(); void iniCentralWidget(); }; #endif
在类CMainWindow的私有区,声明了3个指向菜单的指针成员变量,分别指向文件菜单、编辑菜单和工具菜单;定义了2 个指向工具栏对象的指针,指向文件工具栏和编辑工具栏;定义了12 个指向动作的指针,以及指向菜单和工具栏的动作。这些指针将会在关联信号和槽函数等操作中使用。还定义了一个指向QTextEdit对象的指针,该QTextEdit对象是主窗口的中心部件。
私有函数iniMenu()初始化应用程序主窗口的菜单;iniToolBar()初始化应用程序主窗口的工具栏;iniCentralWidget()初始化主窗口的中心部件。
下面是主窗口类CMainWindow的实现文件mainwindow.cpp。
// chapter04/codemainwindow/src/mainwindow.cpp. #include <QtGui> #include "mainwindow.h"
程序采用了模块化的设计,因此构造函数比较简单。
CMainWindow::CMainWindow(QWidget* parent) : QMainWindow(parent) { iniMenu(); iniToolBar(); iniCentralWidget(); setWindowTitle(tr("文本编辑器")); showMaximized(); }
接下来,重点看一下类CMainWindow的菜单初始化函数和工具栏初始化函数。
void CMainWindow::iniMenu() { menu_F = new QMenu(tr("文件(&F)"), this); actNew = menu_F->addAction(QIcon(":/new.png"), tr("新建(&N)")); actNew->setShortcut(QKeySequence(tr("Ctrl+N")));
首先构造一个菜单QMenu对象并赋给指针menu_F,QMenu构造函数的第一个参数指定了菜单的显示文本;第二个参数指定了菜单对象的父窗口部件。
函数QMenu::addAction()添加一个新的动作到菜单的动作列表,并返回该动作对象的指针。此处,该函数具有两个参数:第一个参数构造了一个不具名的、图标为“:/new.png”的QIcon对象,前面讲过,对于不具名的常量对象的引用是合法的,“:/new.png”引用Qt资源文件中的资源;第二个参数指定了动作对象的显示文本。此外,该函数还有一个只有指定显示文本的重载函数,重载函数只指定了动作的显示文本,没有图标,在下面的代码中有用到。
函数QAction::setShortcut()为新加的动作设置快捷键,它的参数是一个不具名的QKeySequence对象。此处,QKeySequence对象构造了一个“Ctrl+N”快捷键。
注意
QMenu::addAction(QIcon(":/new.png"), tr("新建(&N)"))添加的加速键(accelerator)“N”与QAction:: setShortcut(QKeySequence(tr("Ctrl+N")))添加的快捷键(shortcut)“Ctrl + N”的不同之处。为了不至于引起混淆,笔者对加速键和快捷键的使用有意进行了约束:加速键“N”必须在文件菜单活动的状态下才有效,即在这种情况下一律使用加速键的概念;而快捷键“Ctrl + N”只要在应用程序活动的状态下就可以直接激活(此时,文中使用快捷键描述这种情况)。
接下来,创建“文件”菜单的其他动作,以及“编辑”菜单和“工具”菜单。
actOpen = menu_F->addAction(QIcon(":/open.png"), tr("打开(&O)")); actOpen->setShortcut(QKeySequence(tr("Ctrl+O"))); actClose = menu_F->addAction(tr("关闭(&C)")); menu_F->addSeparator(); actSave = menu_F->addAction(QIcon(":/save.png"), tr("保存(&S)")); actSave->setShortcut(QKeySequence(tr("Ctrl+S"))); actASave = menu_F->addAction(QIcon(":/asave.png"), tr("另存为(&A)")); menu_F->addSeparator(); actQuit = menu_F->addAction(tr("退出(&X)")); menu_E = new QMenu(tr("编辑(&E)"), this); actUndo = menu_E->addAction(QIcon(":/undo.png"), tr("撤销(&U)")); actUndo->setShortcut(QKeySequence(tr("Ctrl+Z"))); menu_E->addSeparator(); actCut = menu_E->addAction(QIcon(":/cut.png"), tr("剪切(&C)")); actCut->setShortcut(QKeySequence(tr("Ctrl+X"))); actCopy = menu_E->addAction(QIcon(":/copy.png"), tr("复制(&C)")); actCopy->setShortcut(QKeySequence(tr("Ctrl+C"))); actPast = menu_E->addAction(QIcon(":/paste.png"), tr("粘贴(&P)")); actPast->setShortcut(QKeySequence(tr("Ctrl+V"))); menu_E->addSeparator(); actAll = menu_E->addAction(tr("全选(&A)")); actAll->setShortcut(QKeySequence(tr("Ctrl+A"))); menu_T = new QMenu(tr("工具(&T)"), this); actFind = menu_T->addAction(QIcon(":/find.png"), tr("查找文件...(&F)")); QMenuBar* bar = menuBar(); bar->addMenu(menu_F); bar->addMenu(menu_E); bar->addMenu(menu_T); }
函数QMainWindow::menuBar()获取主窗口的菜单栏。如果主窗口的菜单栏已经存在,该函数将返回菜单栏的指针;否则该函数将创建并返回一个新的菜单栏。
函数QMainWindow::addMenu()将前面定义好的菜单添加到主窗口的菜单栏上。
void CMainWindow::iniToolBar() { fileToolBar = new QToolBar(this); fileToolBar->setAllowedAreas(Qt::AllToolBarAreas); fileToolBar->setOrientation(Qt::Horizontal); fileToolBar->addAction(actNew); fileToolBar->addAction(actOpen); fileToolBar->addAction(actSave); fileToolBar->addAction(actASave);
在初始化工具栏函数iniToolBar()中,首先调用QToolBar的构造函数创建一个“文件”工具栏。函数QToolBar::setAllowedAreas()设置工具栏可放置的位置,共有6个选项(Qt::ToolBarAreas枚举类型):
● Qt::LeftToolBarArea,主窗口的左侧;
● Qt::RightToolBarArea,主窗口的右侧;
● Qt::TopToolBarArea,主窗口的顶部;
● Qt::BottomToolBarArea,主窗口的底部;
● Qt::AllToolBarAreas,可以放在主窗口四个方向的任何一个;
● Qt::NoToolBarArea,没有可放置工具条的区域。
工具栏放置区域的前四个选择可以通过位或操作运算符 “|”进行任意的组合。
函数QToolBar::setOrientation()设置工具栏图标的排列方向。事实上,Qt的工具栏的方向是由主窗口QMainWindow对象自动管理的,当一个工具栏被放置在主窗口的顶部时,就决定了工具栏的方向是水平的。该函数的参数由两个选项:
● Qt::Horizontal,水平方向;
● Qt::vertical,垂直方向。
此处,无论设置哪个选项,都不会影响工具栏在当前放置区域的方向。
QToolBar::addAction() 将动作添加到相应的工具栏上,该函数继承自QToolBar类的父类QWidget。
下面完成“编辑”工具栏的创建。
editToolBar = new QToolBar(this); editToolBar->setAllowedAreas(Qt::AllToolBarAreas); editToolBar->setOrientation(Qt::Horizontal); editToolBar->addAction(actUndo); editToolBar->addAction(actCut); editToolBar->addAction(actCopy); editToolBar->addAction(actPast); addToolBar(Qt::TopToolBarArea, fileToolBar); addToolBar(Qt::TopToolBarArea, editToolBar); }
最后,QMainWindow::addToolBar()将“文件”工具栏和“编辑”工具栏添加到主窗口。它的第一个参数指定了工具栏放置的区域;第二个参数指定了被放置的工具栏对象。
void CMainWindow::iniCentralWidget() { textEdit = new QTextEdit(this); setCentralWidget(textEdit); }
iniCentralWidget()函数构造一个QTextEdit对象,并将它设置为应用程序主窗口的中心部件。
修改KDevelop工程的qmake工程文件src.pro,加入资源选项:
RESOURCES += ./images/mainwindow.qrc
现在编译运行应用程序,它的显示效果和Qt设计器绘制的界面效果基本上是相同的,如图4-21所示。
图4-21 主窗口的运行效果图