Qt 学习之路 2(13):对话框简介

 豆子  2012年9月14日  Qt 学习之路 2  53条评论

对话框是 GUI 程序中不可或缺的组成部分。很多不能或者不适合放入主窗口的功能组件都必须放在对话框中设置。对话框通常会是一个顶层窗口,出现在程序最上层,用于实现短期任务或者简洁的用户交互。尽管 Ribbon 界面的出现在一定程度上减少了对话框的使用几率,但是,我们依然可以在最新版本的 Office 中发现不少对话框。因此,在可预见的未来,对话框会一直存在于我们的程序之中。

Qt 中使用QDialog类实现对话框。就像主窗口一样,我们通常会设计一个类继承QDialogQDialog(及其子类,以及所有Qt::Dialog类型的类)的对于其 parent 指针都有额外的解释:如果 parent 为 NULL,则该对话框会作为一个顶层窗口,否则则作为其父组件的子对话框(此时,其默认出现的位置是 parent 的中心)。顶层窗口与非顶层窗口的区别在于,顶层窗口在任务栏会有自己的位置,而非顶层窗口则会共享其父组件的位置。

 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    setWindowTitle(tr("Main Window"));
 
    openAction = new QAction(QIcon(":/images/doc-open"), tr("&Open..."), this);
    openAction->setShortcuts(QKeySequence::Open);
    openAction->setStatusTip(tr("Open an existing file"));
    connect(openAction, &QAction::triggered, this, &MainWindow::open);
 
    QMenu *file = menuBar()->addMenu(tr("&File"));
    file->addAction(openAction);
 
    QToolBar *toolBar = addToolBar(tr("&File"));
    toolBar->addAction(openAction);
}
 
MainWindow::~MainWindow()
{
}
 
void MainWindow::open()
{
    QDialog dialog;
    dialog.setWindowTitle(tr("Hello, dialog!"));
    dialog.exec();
}

上面我们使用了前面的示例代码。注意看的是open()函数里面的内容。我们使用QDialog创建了一个对话框,设置其标题为“Hello, dialog!”,然后调用exec()将其显示出来。注意看的是任务栏的图标,由于我们没有设置对话框的 parent 指针,我们会看到在任务栏出现了对话框的位置:

我们修改一下open()函数的内容:

 
 
1
2
3
4
5
6
void MainWindow::open()
{
    QDialog dialog(this);
    dialog.setWindowTitle(tr("Hello, dialog!"));
    dialog.exec();
}

重新运行一下,对比一下就会看到 parent 指针的有无对QDialog实例的影响。

对话框分为模态对话框和非模态对话框。所谓模态对话框,就是会阻塞同一应用程序中其它窗口的输入。模态对话框很常见,比如“打开文件”功能。你可以尝试一下记事本的打开文件,当打开文件对话框出现时,我们是不能对除此对话框之外的窗口部分进行操作的。与此相反的是非模态对话框,例如查找对话框,我们可以在显示着查找对话框的同时,继续对记事本的内容进行编辑。

Qt 支持模态对话框和非模态对话框。其中,Qt 有两种级别的模态对话框:应用程序级别的模态和窗口级别的模态,默认是应用程序级别的模态。应用程序级别的模态是指,当该种模态的对话框出现时,用户必须首先对对话框进行交互,直到关闭对话框,然后才能访问程序中其他的窗口。窗口级别的模态是指,该模态仅仅阻塞与对话框关联的窗口,但是依然允许用户与程序中其它窗口交互。窗口级别的模态尤其适用于多窗口模式,更详细的讨论可以看以前发表过的文章

Qt 使用QDialog::exec()实现应用程序级别的模态对话框,使用QDialog::open()实现窗口级别的模态对话框,使用QDialog::show()实现非模态对话框。回顾一下我们的代码,在上面的示例中,我们调用了exec()将对话框显示出来,因此这就是一个模态对话框。当对话框出现时,我们不能与主窗口进行任何交互,直到我们关闭了该对话框。

下面我们试着将exec()修改为show(),看看非模态对话框:

 
 
1
2
3
4
5
6
void MainWindow::open()
{
    QDialog dialog(this);
    dialog.setWindowTitle(tr("Hello, dialog!"));
    dialog.show();
}

是不是事与愿违?对话框竟然一闪而过!这是因为,show()函数不会阻塞当前线程,对话框会显示出来,然后函数立即返回,代码继续执行。注意,dialog 是建立在栈上的,show()函数返回,MainWindow::open()函数结束,dialog 超出作用域被析构,因此对话框消失了。知道了原因就好改了,我们将 dialog 改成堆上建立,当然就没有这个问题了:

 
 
1
2
3
4
5
6
void MainWindow::open()
{
    QDialog *dialog = new QDialog;
    dialog->setWindowTitle(tr("Hello, dialog!"));
    dialog->show();
}

对比一下这个非模态对话框和之前的模态对话框。我们在对话框出现的时候可以与主窗口交互,因此我们可以建立多个相同的对话框:

如果你足够细心,应该发现上面的代码是有问题的:dialog 存在内存泄露!dialog 使用 new 在堆上分配空间,却一直没有 delete。解决方案也很简单:将 MainWindow 的指针赋给 dialog 即可。还记得我们前面说过的 Qt 的对象系统吗?

不过,这样做有一个问题:如果我们的对话框不是在一个界面类中出现呢?由于QWidget的 parent 必须是QWidget指针,那就限制了我们不能将一个普通的 C++ 类指针传给 Qt 对话框。另外,如果对内存占用有严格限制的话,当我们将主窗口作为 parent 时,主窗口不关闭,对话框就不会被销毁,所以会一直占用内存。在这种情景下,我们可以设置 dialog 的WindowAttribute

 
 
1
2
3
4
5
6
7
void MainWindow::open()
{
    QDialog *dialog = new QDialog;
    dialog->setAttribute(Qt::WA_DeleteOnClose);
    dialog->setWindowTitle(tr("Hello, dialog!"));
    dialog->show();
}

setAttribute()函数设置对话框关闭时,自动销毁对话框。另外,QObject还有一个deleteLater()函数,该函数会在当前事件循环结束时销毁该对话框(具体到这里,需要使用exec()开始一个新的事件循环)。关于事件循环,我们会在后面的文章中详细说明。

Qt 学习之路 2(13):对话框简介的更多相关文章

  1. QT学习之路--创建一个对话框

    Q_OBJECT:这是一个宏,凡是定义信号槽的类都必须声明这个宏. 函数tr()全名是QObject::tr(),被他处理过的字符串可以使用工具提取出来翻译成其他语言,也就是做国际化使用. 对于QT学 ...

  2. Arm开发板+Qt学习之路-析构函数和对话框一起时

    先记录一下代码 一:先将指针释放掉,在显示对话框 void MainWindow::canResponseError(SendCanMsgThread *sendCanMsgThread ){ std ...

  3. Qt 学习之路 2(58):编辑数据库外键

    Qt 学习之路 2(58):编辑数据库外键(skip) 豆子 2013年7月12日 Qt 学习之路 2 13条评论 前面几章我们介绍了如何对数据库进行操作以及如何使用图形界面展示数据库数据.本章我们将 ...

  4. Qt 学习之路 2(56):使用模型操作数据库

    Qt 学习之路 2(56):使用模型操作数据库 (okgogo: skip) 豆子 2013年6月20日 Qt 学习之路 2 13条评论 前一章我们使用 SQL 语句完成了对数据库的常规操作,包括简单 ...

  5. Qt 学习之路 2(53):自定义拖放数据

    Qt 学习之路 2(53):自定义拖放数据 豆子  2013年5月26日  Qt 学习之路 2  13条评论上一章中,我们的例子使用系统提供的拖放对象QMimeData进行拖放数据的存储.比如使用QM ...

  6. Qt 学习之路 2(50):自定义可编辑模型

    Home / Qt 学习之路 2 / Qt 学习之路 2(50):自定义可编辑模型 Qt 学习之路 2(50):自定义可编辑模型 豆子 2013年5月13日 Qt 学习之路 2 13条评论 上一章我们 ...

  7. Qt 学习之路 2(71):线程简介

    Qt 学习之路 2(71):线程简介 豆子 2013年11月18日 Qt 学习之路 2 30条评论 前面我们讨论了有关进程以及进程间通讯的相关问题,现在我们开始讨论线程.事实上,现代的程序中,使用线程 ...

  8. Qt 学习之路 2(24):Qt 绘制系统简介

    Qt 学习之路 2(24):Qt 绘制系统简介 豆子 2012年10月30日 Qt 学习之路 2 77条评论 Qt 的绘图系统允许使用相同的 API 在屏幕和其它打印设备上进行绘制.整个绘图系统基于Q ...

  9. Qt 学习之路 2(17):文件对话框

    Home / Qt 学习之路 2 / Qt 学习之路 2(17):文件对话框 Qt 学习之路 2(17):文件对话框  豆子  2012年9月24日  Qt 学习之路 2  85条评论 在前面的章节中 ...

随机推荐

  1. Linux常用的编辑保存退出命令

    Vi Vim进入编辑后退出 按ESC后 1.保存退出 :wq :x 最快捷的方法:直接按shift+zz,或者切换到大写模式按ZZ,就可以保存退出了,即是按2下大写的Z.区别::wq 强制性写入文件并 ...

  2. 问题:C# ToString("P");结果:c#中的常用ToString()方法总结

    c#中的常用ToString()方法总结   很多类都重写了ToString方法, 导致很多类的tostring到底执行了什么,有哪些参数,都不清楚 对于int,double等的tostring: C ...

  3. Anaconda 安装教程(Win10环境) Tensorflow安装

    序 Python易用,但用好却不易,其中比较头疼的就是包管理和Python不同版本的问题,特别是当你使用Windows的时候.为了解决这些问题,有不少发行版的Python,比如WinPython.An ...

  4. javascript变量声明提升(hoisting)

    javascript的变量声明具有hoisting机制,JavaScript引擎在执行的时候,会把所有变量的声明都提升到当前作用域的最前面. 先看一段代码 1 2 3 4 5 var v = &quo ...

  5. 使用ServerSocket建立聊天服务器(二)

    -------------siwuxie095                         工程名:TestMyServerSocket 包名:com.siwuxie095.socket 类名:M ...

  6. 项目一:在线下单(补充) activeMQ使用(重点) 重构客户注册功能,发短信功能分离

    1 课程计划 1.在线下单(补充) 2.activeMQ使用(重点) n 简介和安装 n activeMQ入门案例 n spring整合activeMQ应用 3.重构客户注册功能,发短信功能分离 n  ...

  7. Linux wine

    一.简介 Wine是Wine Is Not an Emulator(Wine不是模拟器)的缩写,其实是一个转换层(或程序装入器),能够在Linux及与POSIX兼容的其他类似操作系统上运行Window ...

  8. R: 控制流: if & for & while

    ################################################### 问题:if 判断   18.4.29 if 的应用与??...... 解决方案: # if(){ ...

  9. 718C Sasha and Array

    传送门 题目 Sasha has an array of integers a1, a2, ..., an. You have to perform m queries. There might be ...

  10. Luogu 2824 [HEOI2016/TJOI2016]排序

    BZOJ 4552 挺妙的解法. 听说这题直接用一个桶能拿到$80 \ pts$ 发现如果是一个排列的话,要对这个序列排序并不好做,但是假如是$01$序列的话,要对一个区间排序还是很简单的. 发现最后 ...