对于日常见到的应用程序而言,许多都是基于主窗口的,主窗口中包含了菜单栏、工具栏、状态栏和中心区域等。这一章会详细介绍主窗口的每一个部分,还会涉及资源管理、富文本处理、拖放操作和文档打印等相关内容。重点是讲解知识点,而相关的综合应用实例放到了《Qt及Qt Quick开发实战精解》一书中。
Qt中提供了以QMainWindow类为核心的主窗口框架,包含了众多相关的类,它们的继承关系如下图所示,本章会讲解到图中每一个类的基本应用。
一、主窗口框架
主窗口为建立应用程序用户界面提供了一个框架,Qt提供了 QMainWindow 和其他一些相关的类共同主窗口的管理。QMainWindow 类拥有自己的布局,如下图所示,它包含以下组件:
- 菜单栏(QMemuBar)。菜单栏包含了一个下拉菜单项的列表,这些菜单项由 QAction 动作类实现。菜单栏位于主窗口的顶部,一个主窗口只能有一个菜单栏。
- 工具栏(QToolBar)。工具栏一般用于显示一些常用的菜单项目,也可以插人其他窗口部件,并且工具栏是可以移动的。一个主窗口可以拥有多个工具栏。
- 中心部件(Central Widget)。在主窗口的中心区域可以放人一个窗口部件作为中心部件,是应用程序的主要功能实现区域。一个主窗口只能拥有一个中心部件。
- Dock部件(QDockWidget)。Dock部件常被称为停靠窗口,因为可以停靠在中心部件的四周。它用来放置—些部件来实现一些功能,就像个工具箱。一个主窗口可以拥有多个 Dock 部件。
- 状态栏(QStatusBar)。状态栏用于显示程序的一些状态信息,在主窗口的最底部。一个主窗口只能拥有一个状态栏。
本节知识可以在帮助索引中查看 Application Main Window 关键字,其中列出所有与创建主窗口应用程序相关的类,而查看 Main Window 关键字,可以看到主窗口相关类的应用介绍。
1.1 菜单栏和工具栏
下面先来看一个例子。新建QtGui应用,项目名称myMainWindow,类名默认为 MainWindow,基类默认为 QMainWindow不做改动。建立好项目后,在文件列表中双击mainwindow. ui 文件进人设计模式,这时在设计区域出现的便是主窗口界面。下面来添加菜单。双击左上角的“在这里输入”,修改为“文件(&F)”,这里要使用英文半角的括号,“&F”被称为加速键,表明程序运行时,可以按下Alt + F键来激活该菜单。修改完成后,按下回车键,并在弹出的 下拉菜单中将第一项改为“新建文件(&N)”并按下回车键,效果如图5-3所示。这时可以看到在下面的 Action 编辑器中已经有了“新建文件”动作,如图5-4所示。单击该动作,将其拖入菜单栏下面的工具栏中,如下图所示。关于在设计器中创建主窗口,也可以在帮助索引中查看Creating Main Windows in Qt Designer关键字。
运行程序,按下Ah + F键就可以打开文件菜单,按下N键就可以激活新建文件菜单。需要说明,必须在文件菜单在激活状态时按下N键才有效,这也就是加速键与快捷键的不同之处。因为一般的菜单都有一个对应的图标,下面就来为菜单添加图标。
1. 使用资源
3.3. 1小节讲解标签部件时使用了图片,不过那里的图片是放在可执行程序外部的,如果图片位置发生变化,那么程序将无法显示图片。这里将使用Qt的资源系统来存储图片,这样它们就可以嵌人到可执行文件之中了。
(1)添加Qt资源文件。往项目中添加新文件,选择Qt分类中的Qt资源文件,文件名称改为“mylmage”,其他选项默认即可。
(2)添加资源。建立好资源文件后会默认进人资源管理界面,就是新建的 myImage. qrc 文件中。选择“添加前缀”,然后将属性栏中的前缀改为“/mylmage”,再单击“添加”按钮选择“添加文件”,在弹出的对话框中进人到前面新建的images文件夹,选中两张图片单击“打开”即可,这时 myImage. qrc 文件中就出现了添加的图片列表。
(3)使用图片。先使用Ctrl+Tab快捷键转到 mainwindow.ui 文件,回到设计模式在Action编辑器中双击“新建文件”动作,这时会弹出编辑动作对话框。在其中将对象名称改为“action_New”,工具提示改为“新建文件”,然后单击图标后面的按钮进人选择资源界面。笫一次进人该界面还没有显示可用的资源,需要单击左上角的重新加载绿色箭头图标,这时图片资源就显示出来了。这里选择new. png 图片,然后单击“确定”按钮,最后在快捷键后面的输人栏上单击并按下了Ctrl+N,就可以将它设为这个动作的快捷键了,到这里就为动作添加了图标和快捷键了。
可以在帮助索引中查看 The Qt Resource System 关键字,这里介绍了Qt资源系统的相关内容。上面在使用资源时添加的qrc资源文件其实是一个XML格式的文本文件。
2. 编写代码方式添加菜单
上面在设计器中添加了文件菜单,然后添加了新建文件子菜单,其实这些都可以使用代码来实现。下面使用代码来添加一个菜单。首先先在 main.cpp 文件中添加代码使其可以支持中文,然后在 mainwindow. cpp 文件的 MainWindow 类构造函数中添加代码:
QMenu *editMenu = ui->menuBar->addMenu(tr("编辑(&E)")); // 添加编辑菜单
QAction *action_Open = editMenu->addAction(QIcon(":/image/images/open.png"),tr("打开文件(&O)")); // 添加打开菜单
action_Open->setShortcut(QKeySequence("Ctrl+O")); // 设置快捷键
ui->mainToolBar->addAction(action_Open); // 在工具栏中添加动作
这里使用 ui->memuBar 来获取了 QMainWindow 的菜单栏,使用 ui->mainTooBar 來获取工具栏,然后分别使用相应的函数来添加菜单和动作,就像前面提到过的,在菜单中的各种菜单项目都是一个 QAction 类对象,这个后面还会讲到。现在运行程序就可以看到已经添加了新的菜单了。
3. 菜单栏
QMenuBar 类提供了一个水平的菜单栏,在 QiMainWindow 中可以直接获取它的默认存在的菜单栏。向其中添加 QMemu 类型的菜单对象,然后向弹出菜单中添加 QAction 类型的动作对象。
QMenu 中还提供了间隔器,可以在设计器中向添加菜单那样直接添加间隔器,或者在代码中使用 addSeparator() 函数来添加,它是一条水平线, 可以将菜单分成几组,使得布局很整齐。
在应用程序中很多普通的命令都可以通过菜单来实现的,而我们也希望能将这些菜单命令放到工具栏中,以方便使用。QAction 就是这样一种命令动作,可以同时放在菜单和工具栏中。一个QAction动作包含了图标、 菜单显示文本、快捷键、状态栏显示文本、“What's This?”显示文本及工具提示文本。 这些都可以在构建 QAction 类对象时在构造函数中指定。另外还可以设置 QAction 的 checkable 属性,如果指定这个动作的 checkable 为true,那么当选中这个菜单时就会在它的前面显示“√”之类的表示选中状态的符号;如果该菜单有图标,那么就会用线框将图标围住,用来表示该动作被选中了。
下面再介绍一个动作组 QActionGroup 类,它可以包含一组动作 QAction,支持这组动作中是否只能有一个动作处于选中状态,这对于互斥型动作很有用,在上面程序的 MainWindow 类构造函数中继续添加如下代码:
QActionGroup *group = new QActionGroup(this); // 建立动作组
QAction *action_L = group->addAction(tr("左对齐(&L)")); // 向动作组中添加动作
action_L->setCheckable(true); // 设置动作checkable属性为true
QAction *action_R = group->addAction(tr("右对齐(&R)"));
action_R->setCheckable(true);
QAction *action_C = group->addAction(tr("居中(&C)"));
action_C->setCheckable(true);
action_L->setChecked(true); // 最后指定action_L为选中状态
editMenu->addSeparator(); // 向菜单中添加间隔器
editMenu->addAction(action_L); // 向菜单中添加动作
editMenu->addAction(action_R);
editMenu->addAction(action_C);
这里让“左对齐”、“右对齐”和“居中”3个动作处于一个动作组中,然后设置“左对齐”动作为默认选中状态。
4. 工具栏
工具栏 QToolBar 类提供了一个包含了一组控件的可以移动的面板。在上面已经看到可以将 QAction 对象添加到工具栏中,它默认只是显示一个动作的图标,这个可以在 QToolBar 的属性栏中更改。在设计器中查看 QToolBar 的属性栏,其中 toolButtonStyle 属性设置图标和相应文本的显示及其相对位置等;movabel 属性设置状态栏是否可以移动;allowedArea 设置允许停靠的位置;iconsize 属性设置图标的大小;floatable 属性设置是否可以悬浮。
工具栏中除了可以添加动作外,还可以添加其他的窗口部件,下面来看一个例子: 在前面的程序中的mainwindow. cpp文件中添加头文件:
#include <QToolButton>
#include <QSpinBox>
然后在构造函数中继续添加以下代码:
QToolButton *toolBtn = new QToolButton(this); // 创建QToolButton
toolBtn->setText(tr("颜色"));
QMenu *colorMenu = new QMenu(this); // 创建一个菜单
colorMenu->addAction(tr("红色"));
colorMenu->addAction(tr("绿色"));
toolBtn->setMenu(colorMenu); // 添加菜单
toolBtn->setPopupMode(QToolButton::MenuButtonPopup); // 设置弹出模式
ui->mainToolBar->addWidget(toolBtn); // 向工具栏添加QToolButton按钮
QSpinBox *spinBox = new QSpinBox(this); // 创建QSpinBox
ui->mainToolBar->addWidget(spinBox); // 向工具栏添加QSpinBox部件
这里创建了一个 QToolButton 类对象,并为它添加了一个弹出菜单,这里设置了弹出方式是在按钮旁边有一个向下的小箭头,可以按下这个箭头弹出菜单,而默认的弹出方式是按下按钮一段时间才弹出菜单。最后将它添加到了工具栏中。下面又在工具栏中添加了一个 QSpinBox 部件.可以看到往工具栏中添加部件可以使用 addWidget () 函数。
这里还要再说明一下 QToolButton 类。其实,往工具栏中添加一个 QAction 类对象时就会自动创建了一个 QToolButton,所以说工具栏上的动作就是一个 QToolButton,这就是为什么属性栏中会有 toolButtcmStyle 属性的原因了。
1.2 中心部件
在主窗口的中心区域可以放置一个中心部件,它一般是一个编辑器或者浏览器。这里支持单文档部件,也支持多文档部件。一般的,我们会在这里放置一个部件,然后使用布局管理器使其充满整个中心区域,并可以随着窗口的大小变化而改变大小。
下面在前面的程序中添加中心部件。在设计模式中,往中心区域拖人一个 Text Edit,然后单击界面,按下 Ctrl + G 使其处于一个栅格布局中。现在可以运行程序查看效果。 QTextEdit 是一个髙级的 WYSIWYG(所见即所得) 浏览器和编辑器,支持富文本的处理,为用户提供了强大的文本编辑功能。而与 QTextEdit 对应的是 QPlainTextEdit 类,它提供了一个纯文本编辑器,这个类与 QTextEdit 类的很多功能都很相似,只不过无法处理富文本。还有一个 QTextBrowser 类,是一个富文本浏览器,可以看作 QTextEdit 的只读模式。
中心区域还可以使用多文档部件。Qt中的 QMdiArea 部件就是用来提供一个可以显示 MDI (Multiple Document Interface)多文档界面的区域,它代替了以前的 QWorkspace 类,用来有效地管理多个窗口。QMdiArea 中的子窗口由 QMdiSubWindow 类提供,这个类有自己的布局,包含一个标题栏和一个中心区域,可以向它的中心区域添加部件。
下面更改前面的程序,在设计模式将前面添加的 Text Edit 部件删除,然后拖入一个 MdiArea 部件。在 Action 编辑器中的“新建文件”动作上右击,在弹出的菜单中选择“转到槽...”,然后在弹出的对话框中选择 triggered() 触发信号,单击“确定”按钮后便会转到 mainwindow. cpp 文件中的该信号的槽的定义处,更改如下:
void MainWindow::on_action_New_triggered()
{
// 新建文本编辑器部件
QTextEdit *edit = new QTextEdit(this);
// 使用QMdiArea类的addSubWindow()函数创建子窗口,以文本编辑器为中心部件
QMdiSubWindow *child = ui->mdiArea->addSubWindow(edit);
child->setWindowTitle(tr("多文档编辑器子窗口"));
child->show();
}
这里需要添加 #include <QTextEdit>和 #include <QMdiSubWindow> 头文件。在新建文件菜单动作的触发信号槽 on_action_New_triggered() 中创建了多文档区域的子窗口。这时运行程序,然后按下工具栏上的新建文件动作图标,每按下一次, 就会生成一个子窗口。
1.3 Dock 部件
QDockWidget 类提供了这样一个部件,它可以停靠在 QMainWindow 中,也可以悬浮起来作为桌面*窗口,称它为Dock部件或者停靠窗。Dock 部件一般用于存放一些其他部件来实现特殊功能,就像一个工具箱。它在主窗口中可以停靠在中心部件的四周,也可以悬浮起来,被拖动到任意的地方,还可以被关闭或隐藏起来。一个 Dock 部件包含一个标题栏和一个内容区域,可以向 Dock 部件中放入任何部件。
在设计模式中向中心区域拖人一个 Dock Widget 部件,然后再向 Dock 中随意拖 人几个部件,比如这里拖入一个 Push Button 和 Font Combo Box。然后在 dockWidget 的属性栏中更改其 windowTitle 为“工具箱”,另外还可以设置它的 features 厲性,包含是否可以关闭、移动和悬浮等;还有 allowedArea 属性,用来设置可以停靠的区域。现在运行程序,效果如图5 - 6所示,然后拖动它,使其悬浮起来,如下图所示。
下面在文件菜单中添加“显示Dock”菜单,然后在Action编辑器中进入“显示 Dock”菜单动作的触发信号 triggered() 的槽函数,更改如下:
void MainWindow::on_action_Dock_triggered()
{
ui->dockWidget->show();
}
运行程序时关闭了 Dock 部件后,按下该菜单,就可以重新显示 Dock 了。
1.4 状态栏
QStatusBar 类提供了一个水平条,用来显示状态信息。QMainWindow 中默认提供了一个状态栏。状态信息可以被分为3类:临时信息,如一般的提示信息;正常信 息,如显示页数和行号;永久信息,如显示版本号或者日期。可以使用 showMessage() 函数来显示一个临时消息,它会出现在状态栏的最左边。一般用 addWidget() 函数添加一个 QLabel 到状态栏上用于显示正常信息,它会生成到状态栏的最左边,可能会被临时消息所掩盖。
如果要显示永久信息,要使用 addPermanentWidget() 函数来添加一个如 QLabel —样的可以显示信息的部件,它会生成在状态栏的最右端,不会被临时消息所掩盖。在状态栏的最右端还有一个 QSizeGrip 部件,用来调整窗口的大小,可以使用 setSizeGripEnabled() 函数来禁用它。
因为在目前的设计器中还不支持直接向状态栏中拖放部件,所以需要使用代码来生成。在 mainwindow. cpp 文件中的构造函数里继续添加代码:
// 显示临时消息,显示2000毫秒即2秒
ui->statusBar->showMessage(tr("欢迎使用多文档编辑器"), 2000);
// 创建标签,设置标签样式并显示信息,然后将其以永久部件的形式添加到状态栏
QLabel *permanent = new QLabel(this);
permanent->setFrameStyle(QFrame::Box | QFrame::Sunken);
permanent->setText("www.qter.org");
ui->statusBar->addPermanentWidget(permanent);
此时运行程序可以发现“欢迎使用多文档编辑器”字符串在显示一会儿后就自动消失了,而“WWW. yafeilinux. com”一直显示在状态栏右端。
1.5 自定义菜单
这里由于篇幅原因,这节就不再多介绍了,具体内容可去《Qt Creator 快速入门》的对应章节查看。
二、富文本处理
前面提到 QTextEdit 支持富文本的处理,什么是富文本呢?富文本(Rich Text)或者富文本格式,简单来说就是在文档中可以使用多种格式,比如字体颜色、图片和表格等。它是与纯文本(Plain Text)相对而言的,比如Windows上的记事本就是纯文本编辑器,而Word就是富文本编辑器。Qt提供了对富文本处理的支持,可以在帮助中査看Rich Text Processing关键字,那里详细讲解了富文本处理的相关内容。这里由于篇幅原因,这节就不再多介绍了,具体内容可去《Qt Creator 快速入门》的对应章节查看。