Qt教程] Qt学习之路第14篇 对话框数据传递

楼主
  发表于 2013-9-9 11:51:05  | 查看: 180 | 回复: 0

[Q
楼主
  发表于 2013-9-9 11:58:06  | 查看: 178 | 回复: 0
版权声明

该文章原创于 Qter 开源社区( www.qter.org ),作者 devbean ,博客 www.devbean.net ,转载请注明出处!


所谓标准对话框,是 Qt 内置的一系列对话框,用于简化开发。事实上,有很多对话框都是通用的,比如打开文件、设置颜色、打印设置等。这些对话框在所有程序中几乎相同,因此没有必要在每一个程序中都自己实现这么一个对话框。


Qt 的内置对话框大致分为以下几类:



  • QColorDialog:选择颜色;
  • QFileDialog:选择文件或者目录;
  • QFontDialog:选择字体;
  • QInputDialog:允许用户输入一个值,并将其值返回;
  • QMessageBox:模态对话框,用于显示信息、询问问题等;
  • QPageSetupDialog:为打印机提供纸张相关的选项;
  • QPrintDialog:打印机配置;
  • QPrintPreviewDialog:打印预览;
  • QProgressDialog:显示操作过程。


这里我们简单地介绍一下标准对话框 QMessageBox 的使用。在前面有了关于对话框的基础之上,应该可以结合文档很轻松地学习如何使用 Qt 的标准对话框。其它种类的标准对话框,我们将在后面的章节中再一一介绍。


QMessageBox 用于显示消息提示。我们一般会使用其提供的几个 static 函数:



  • void about(QWidget * parent, const QString & title, const QString & text):显示关于对话框。这是一个最简单的对话框,其标题是 title,内容是 text,父窗口是 parent。对话框只有一个 OK 按钮。

  • void aboutQt(QWidget * parent, const QString & title = QString()):显示关于 Qt 对话框。该对话框用于显示有关 Qt 的信息。

  • StandardButton critical(QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton):显示严重错误对话框。这个对话框将显示一个红色的错误符号。我们可以通过 buttons 参数指明其显示的按钮。默认情况下只有一个 Ok 按钮,我们可以使用 StandardButtons 类型指定多种按钮。

  • StandardButton information(QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton):QMessageBox::information() 函数与 QMessageBox::critical() 类似,不同之处在于这个对话框提供一个普通信息图标。

  • StandardButton question(QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = StandardButtons( Yes | No ), StandardButton defaultButton = NoButton):QMessageBox::question() 函数与 QMessageBox::critical() 类似,不同之处在于这个对话框提供一个问号图标,并且其显示的按钮是“是”和“否”两个。

  • StandardButton warning(QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton):QMessageBox::warning() 函数与 QMessageBox::critical() 类似,不同之处在于这个对话框提供一个**叹号图标。


我们可以通过下面的代码来演示下如何使用 QMessageBox。

  1. if (QMessageBox::Yes == QMessageBox::question(this,
  2.                                               tr("Question"),
  3.                                               tr("Are you OK?"),
  4.                                               QMessageBox::Yes | QMessageBox::No,
  5.                                               QMessageBox::Yes)) {
  6.     QMessageBox::information(this, tr("Hmmm..."), tr("I'm glad to hear that!"));
  7. } else {
  8.     QMessageBox::information(this, tr("Hmmm..."), tr("I'm sorry!"));
  9. }
复制代码

我们使用 QMessageBox::question() 来询问一个问题。这个对话框的父窗口是 this,也就是我们的 MainWindow(或者其他 QWidget 指针)。QMessageBox 是 QDialog 的子类,这意味着它的初始显示位置将会是在 parent 窗口的中央(我们在前面的章节中提到过这一点)。第二个参数是对话框的标题。第三个参数是我们想要显示的内容。这里就是我们需要询问的文字。下面,我们使用或运算符(|)指定对话框应该出现的按钮。这里我们希望是一个 Yes 和一个 No。最后一个参数指定默认选择的按钮。这个函数有一个返回值,用于确定用户点击的是哪一个按钮。按照我们的写法,应该很容易的看出,这是一个模态对话框,因此我们可以直接获取其返回值。如果返回值是 Yes,也就是说用户点击了 Yes 按钮,我们显示一个普通消息对话框,显示“I’m glad to hear that!”,否则则显示“I’m sorry!”。运行一下我们的程序片段,就可以看到其中的不同:



QMessageBox 类的 static 函数优点是方便使用,缺点也很明显:非常不灵活。我们只能使用简单的几种形式。为了能够定制 QMessageBox 细节,我们必须使用 QMessageBox 的属性设置 API。如果我们希望制作一个询问是否保存的对话框,我们可以使用如下的代码:

  1. QMessageBox msgBox;
  2. msgBox.setText(tr("The document has been modified."));
  3. msgBox.setInformativeText(tr("Do you want to save your changes?"));
  4. msgBox.setDetailedText(tr("Differences here..."));
  5. msgBox.setStandardButtons(QMessageBox::Save
  6.                           | QMessageBox::Discard
  7.                           | QMessageBox::Cancel);
  8. msgBox.setDefaultButton(QMessageBox::Save);
  9. int ret = msgBox.exec();
  10. switch (ret) {
  11. case QMessageBox::Save:
  12.     qDebug() << "Save document!";
  13.     break;
  14. case QMessageBox::Discard:
  15.     qDebug() << "Discard changes!";
  16.     break;
  17. case QMessageBox::Cancel:
  18.     qDebug() << "Close document!";
  19.     break;
  20. }
复制代码

msgBox 是一个建立在栈上的 QMessageBox 实例。我们设置其标题为“The document has been modified.”,informationText 则是会在对话框中显示的文字。下面我们使用了一个 detailedText,也就是详细信息,当我们点击了详细信息按钮时,对话框可以自动显示更多信息。我们自己定义的对话框的按钮有三个:保存、丢弃和取消。然后我们使用了 exec() 是其成为一个模态对话框,根据其返回值进行相应的操作。


同时在 KDE 和 Windows 7 上编译运行一下上面的代码,我们可以看到一些区别:






除去对话框样式,我们值得注意的是 QMessageBox 下方按钮的排列顺序。KDE 上是 Show Details…、Save、Discard 和 Cancel;而 Windows 7 上则是 Save、Discard、Show Details… 和 Cancel。我们并没有指定按钮的顺序,Qt 已经帮我们按照不同平台的使用习惯对其进行了调整。这一点在 Mac OS 上也会有相应的体现。对于一个普通的 QDialog 而言,Qt 使用的是 QDialogButtonBox 这个类来实现不同平台的对话框按钮顺序的显示的。更多细节请参考这个类的文档。

楼主
  发表于 2013-9-9 11:58:06  | 查看: 178 | 回复: 0
版权声明

该文章原创于 Qter 开源社区( www.qter.org ),作者 devbean ,博客 www.devbean.net ,转载请注明出处!


所谓标准对话框,是 Qt 内置的一系列对话框,用于简化开发。事实上,有很多对话框都是通用的,比如打开文件、设置颜色、打印设置等。这些对话框在所有程序中几乎相同,因此没有必要在每一个程序中都自己实现这么一个对话框。


Qt 的内置对话框大致分为以下几类:



  • QColorDialog:选择颜色;
  • QFileDialog:选择文件或者目录;
  • QFontDialog:选择字体;
  • QInputDialog:允许用户输入一个值,并将其值返回;
  • QMessageBox:模态对话框,用于显示信息、询问问题等;
  • QPageSetupDialog:为打印机提供纸张相关的选项;
  • QPrintDialog:打印机配置;
  • QPrintPreviewDialog:打印预览;
  • QProgressDialog:显示操作过程。


这里我们简单地介绍一下标准对话框 QMessageBox 的使用。在前面有了关于对话框的基础之上,应该可以结合文档很轻松地学习如何使用 Qt 的标准对话框。其它种类的标准对话框,我们将在后面的章节中再一一介绍。


QMessageBox 用于显示消息提示。我们一般会使用其提供的几个 static 函数:



  • void about(QWidget * parent, const QString & title, const QString & text):显示关于对话框。这是一个最简单的对话框,其标题是 title,内容是 text,父窗口是 parent。对话框只有一个 OK 按钮。

  • void aboutQt(QWidget * parent, const QString & title = QString()):显示关于 Qt 对话框。该对话框用于显示有关 Qt 的信息。

  • StandardButton critical(QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton):显示严重错误对话框。这个对话框将显示一个红色的错误符号。我们可以通过 buttons 参数指明其显示的按钮。默认情况下只有一个 Ok 按钮,我们可以使用 StandardButtons 类型指定多种按钮。

  • StandardButton information(QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton):QMessageBox::information() 函数与 QMessageBox::critical() 类似,不同之处在于这个对话框提供一个普通信息图标。

  • StandardButton question(QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = StandardButtons( Yes | No ), StandardButton defaultButton = NoButton):QMessageBox::question() 函数与 QMessageBox::critical() 类似,不同之处在于这个对话框提供一个问号图标,并且其显示的按钮是“是”和“否”两个。

  • StandardButton warning(QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton):QMessageBox::warning() 函数与 QMessageBox::critical() 类似,不同之处在于这个对话框提供一个**叹号图标。


我们可以通过下面的代码来演示下如何使用 QMessageBox。

  1. if (QMessageBox::Yes == QMessageBox::question(this,
  2.                                               tr("Question"),
  3.                                               tr("Are you OK?"),
  4.                                               QMessageBox::Yes | QMessageBox::No,
  5.                                               QMessageBox::Yes)) {
  6.     QMessageBox::information(this, tr("Hmmm..."), tr("I'm glad to hear that!"));
  7. } else {
  8.     QMessageBox::information(this, tr("Hmmm..."), tr("I'm sorry!"));
  9. }
复制代码

我们使用 QMessageBox::question() 来询问一个问题。这个对话框的父窗口是 this,也就是我们的 MainWindow(或者其他 QWidget 指针)。QMessageBox 是 QDialog 的子类,这意味着它的初始显示位置将会是在 parent 窗口的中央(我们在前面的章节中提到过这一点)。第二个参数是对话框的标题。第三个参数是我们想要显示的内容。这里就是我们需要询问的文字。下面,我们使用或运算符(|)指定对话框应该出现的按钮。这里我们希望是一个 Yes 和一个 No。最后一个参数指定默认选择的按钮。这个函数有一个返回值,用于确定用户点击的是哪一个按钮。按照我们的写法,应该很容易的看出,这是一个模态对话框,因此我们可以直接获取其返回值。如果返回值是 Yes,也就是说用户点击了 Yes 按钮,我们显示一个普通消息对话框,显示“I’m glad to hear that!”,否则则显示“I’m sorry!”。运行一下我们的程序片段,就可以看到其中的不同:



QMessageBox 类的 static 函数优点是方便使用,缺点也很明显:非常不灵活。我们只能使用简单的几种形式。为了能够定制 QMessageBox 细节,我们必须使用 QMessageBox 的属性设置 API。如果我们希望制作一个询问是否保存的对话框,我们可以使用如下的代码:

  1. QMessageBox msgBox;
  2. msgBox.setText(tr("The document has been modified."));
  3. msgBox.setInformativeText(tr("Do you want to save your changes?"));
  4. msgBox.setDetailedText(tr("Differences here..."));
  5. msgBox.setStandardButtons(QMessageBox::Save
  6.                           | QMessageBox::Discard
  7.                           | QMessageBox::Cancel);
  8. msgBox.setDefaultButton(QMessageBox::Save);
  9. int ret = msgBox.exec();
  10. switch (ret) {
  11. case QMessageBox::Save:
  12.     qDebug() << "Save document!";
  13.     break;
  14. case QMessageBox::Discard:
  15.     qDebug() << "Discard changes!";
  16.     break;
  17. case QMessageBox::Cancel:
  18.     qDebug() << "Close document!";
  19.     break;
  20. }
复制代码

msgBox 是一个建立在栈上的 QMessageBox 实例。我们设置其标题为“The document has been modified.”,informationText 则是会在对话框中显示的文字。下面我们使用了一个 detailedText,也就是详细信息,当我们点击了详细信息按钮时,对话框可以自动显示更多信息。我们自己定义的对话框的按钮有三个:保存、丢弃和取消。然后我们使用了 exec() 是其成为一个模态对话框,根据其返回值进行相应的操作。


同时在 KDE 和 Windows 7 上编译运行一下上面的代码,我们可以看到一些区别:






除去对话框样式,我们值得注意的是 QMessageBox 下方按钮的排列顺序。KDE 上是 Show Details…、Save、Discard 和 Cancel;而 Windows 7 上则是 Save、Discard、Show Details… 和 Cancel。我们并没有指定按钮的顺序,Qt 已经帮我们按照不同平台的使用习惯对其进行了调整。这一点在 Mac OS 上也会有相应的体现。对于一个普通的 QDialog 而言,Qt 使用的是 QDialogButtonBox 这个类来实现不同平台的对话框按钮顺序的显示的。更多细节请参考这个类的文档。

t教程] Qt学习之路第15篇 标准对话框 QMessageBox

楼主
  发表于 2013-9-9 11:58:06  | 查看: 178 | 回复: 0
版权声明

该文章原创于 Qter 开源社区( www.qter.org ),作者 devbean ,博客 www.devbean.net ,转载请注明出处!


所谓标准对话框,是 Qt 内置的一系列对话框,用于简化开发。事实上,有很多对话框都是通用的,比如打开文件、设置颜色、打印设置等。这些对话框在所有程序中几乎相同,因此没有必要在每一个程序中都自己实现这么一个对话框。


Qt 的内置对话框大致分为以下几类:



  • QColorDialog:选择颜色;
  • QFileDialog:选择文件或者目录;
  • QFontDialog:选择字体;
  • QInputDialog:允许用户输入一个值,并将其值返回;
  • QMessageBox:模态对话框,用于显示信息、询问问题等;
  • QPageSetupDialog:为打印机提供纸张相关的选项;
  • QPrintDialog:打印机配置;
  • QPrintPreviewDialog:打印预览;
  • QProgressDialog:显示操作过程。


这里我们简单地介绍一下标准对话框 QMessageBox 的使用。在前面有了关于对话框的基础之上,应该可以结合文档很轻松地学习如何使用 Qt 的标准对话框。其它种类的标准对话框,我们将在后面的章节中再一一介绍。


QMessageBox 用于显示消息提示。我们一般会使用其提供的几个 static 函数:



  • void about(QWidget * parent, const QString & title, const QString & text):显示关于对话框。这是一个最简单的对话框,其标题是 title,内容是 text,父窗口是 parent。对话框只有一个 OK 按钮。

  • void aboutQt(QWidget * parent, const QString & title = QString()):显示关于 Qt 对话框。该对话框用于显示有关 Qt 的信息。

  • StandardButton critical(QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton):显示严重错误对话框。这个对话框将显示一个红色的错误符号。我们可以通过 buttons 参数指明其显示的按钮。默认情况下只有一个 Ok 按钮,我们可以使用 StandardButtons 类型指定多种按钮。

  • StandardButton information(QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton):QMessageBox::information() 函数与 QMessageBox::critical() 类似,不同之处在于这个对话框提供一个普通信息图标。

  • StandardButton question(QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = StandardButtons( Yes | No ), StandardButton defaultButton = NoButton):QMessageBox::question() 函数与 QMessageBox::critical() 类似,不同之处在于这个对话框提供一个问号图标,并且其显示的按钮是“是”和“否”两个。

  • StandardButton warning(QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton):QMessageBox::warning() 函数与 QMessageBox::critical() 类似,不同之处在于这个对话框提供一个**叹号图标。


我们可以通过下面的代码来演示下如何使用 QMessageBox。

  1. if (QMessageBox::Yes == QMessageBox::question(this,
  2.                                               tr("Question"),
  3.                                               tr("Are you OK?"),
  4.                                               QMessageBox::Yes | QMessageBox::No,
  5.                                               QMessageBox::Yes)) {
  6.     QMessageBox::information(this, tr("Hmmm..."), tr("I'm glad to hear that!"));
  7. } else {
  8.     QMessageBox::information(this, tr("Hmmm..."), tr("I'm sorry!"));
  9. }
复制代码

我们使用 QMessageBox::question() 来询问一个问题。这个对话框的父窗口是 this,也就是我们的 MainWindow(或者其他 QWidget 指针)。QMessageBox 是 QDialog 的子类,这意味着它的初始显示位置将会是在 parent 窗口的中央(我们在前面的章节中提到过这一点)。第二个参数是对话框的标题。第三个参数是我们想要显示的内容。这里就是我们需要询问的文字。下面,我们使用或运算符(|)指定对话框应该出现的按钮。这里我们希望是一个 Yes 和一个 No。最后一个参数指定默认选择的按钮。这个函数有一个返回值,用于确定用户点击的是哪一个按钮。按照我们的写法,应该很容易的看出,这是一个模态对话框,因此我们可以直接获取其返回值。如果返回值是 Yes,也就是说用户点击了 Yes 按钮,我们显示一个普通消息对话框,显示“I’m glad to hear that!”,否则则显示“I’m sorry!”。运行一下我们的程序片段,就可以看到其中的不同:



QMessageBox 类的 static 函数优点是方便使用,缺点也很明显:非常不灵活。我们只能使用简单的几种形式。为了能够定制 QMessageBox 细节,我们必须使用 QMessageBox 的属性设置 API。如果我们希望制作一个询问是否保存的对话框,我们可以使用如下的代码:

  1. QMessageBox msgBox;
  2. msgBox.setText(tr("The document has been modified."));
  3. msgBox.setInformativeText(tr("Do you want to save your changes?"));
  4. msgBox.setDetailedText(tr("Differences here..."));
  5. msgBox.setStandardButtons(QMessageBox::Save
  6.                           | QMessageBox::Discard
  7.                           | QMessageBox::Cancel);
  8. msgBox.setDefaultButton(QMessageBox::Save);
  9. int ret = msgBox.exec();
  10. switch (ret) {
  11. case QMessageBox::Save:
  12.     qDebug() << "Save document!";
  13.     break;
  14. case QMessageBox::Discard:
  15.     qDebug() << "Discard changes!";
  16.     break;
  17. case QMessageBox::Cancel:
  18.     qDebug() << "Close document!";
  19.     break;
  20. }
复制代码

msgBox 是一个建立在栈上的 QMessageBox 实例。我们设置其标题为“The document has been modified.”,informationText 则是会在对话框中显示的文字。下面我们使用了一个 detailedText,也就是详细信息,当我们点击了详细信息按钮时,对话框可以自动显示更多信息。我们自己定义的对话框的按钮有三个:保存、丢弃和取消。然后我们使用了 exec() 是其成为一个模态对话框,根据其返回值进行相应的操作。


同时在 KDE 和 Windows 7 上编译运行一下上面的代码,我们可以看到一些区别:






除去对话框样式,我们值得注意的是 QMessageBox 下方按钮的排列顺序。KDE 上是 Show Details…、Save、Discard 和 Cancel;而 Windows 7 上则是 Save、Discard、Show Details… 和 Cancel。我们并没有指定按钮的顺序,Qt 已经帮我们按照不同平台的使用习惯对其进行了调整。这一点在 Mac OS 上也会有相应的体现。对于一个普通的 QDialog 而言,Qt 使用的是 QDialogButtonBox 这个类来实现不同平台的对话框按钮顺序的显示的。更多细节请参考这个类的文档。


版权声明

该文章原创于 Qter 开源社区( www.qter.org ),作者 devbean ,博客 www.devbean.net ,转载请注明出处!
楼主
  发表于 2013-9-9 11:43:09  | 查看: 198 | 回复: 0
版权声明

该文章原创于 Qter 开源社区( www.qter.org ),作者 devbean ,博客 www.devbean.net ,转载请注明出处!


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


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

  1. MainWindow::MainWindow(QWidget *parent)
  2.     : QMainWindow(parent)
  3. {
  4.     setWindowTitle(tr("Main Window"));

  5.     openAction = new QAction(QIcon(":/images/doc-open"), tr("&Open..."), this);
  6.     openAction->setShortcuts(QKeySequence::Open);
  7.     openAction->setStatusTip(tr("Open an existing file"));
  8.     connect(openAction, &QAction::triggered, this, &MainWindow::open);

  9.     QMenu *file = menuBar()->addMenu(tr("&File"));
  10.     file->addAction(openAction);

  11.     QToolBar *toolBar = addToolBar(tr("&File"));
  12.     toolBar->addAction(openAction);
  13. }

  14. MainWindow::~MainWindow()
  15. {
  16. }

  17. void MainWindow::open()
  18. {
  19.     QDialog dialog;
  20.     dialog.setWindowTitle(tr("Hello, dialog!"));
  21.     dialog.exec();
  22. }
复制代码

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




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

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

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


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


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


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


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

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

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

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

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



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


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

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

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




对话框的出现用于完成一个简单的或者是短期的任务。对话框与主窗口之间的数据交互相当重要。本节将讲解如何在对话框和主窗口之间进行数据交互。按照前文的讲解,对话框分为模态和非模态两种。我们也将以这两种为例,分别进行阐述。



模态对话框使用了 exec() 函数将其显示出来。exec() 函数的真正含义是开启一个新的事件循环(我们会在后面的章节中详细介绍有关事件的概念)。所谓事件循环,可以理解成一个无限循环。Qt 在开启了事件循环之后,系统发出的各种事件才能够被程序监听到。这个事件循环相当于一种轮询的作用。既然是无限循环,当然在开启了事件循环的地方,代码就会被阻塞,后面的语句也就不会被执行到。因此,对于使用了 exec() 显示的模态对话框,我们可以在 exec() 函数之后直接从对话框的对象获取到数据值。



看一下下面的代码:

  1. void MainWindow::open()
  2. {
  3.     QDialog dialog(this);
  4.     dialog.setWindowTitle(tr("Hello, dialog!"));
  5.     dialog.exec();
  6.     qDebug() << dialog.result();
  7. }
复制代码

上面的代码中,我们使用 exec() 显示一个模态对话框。最后一行代码,qDebug() 类似于 std::cout 或者 Java 的 System.out.println(); 语句,将后面的信息输出到标准输出,一般就是控制台。使用 qDebug() 需要引入头文件。在 exec() 函数之后,我们直接可以获取到 dialog 的数据值。注意,exec() 开始了一个事件循环,代码被阻塞到这里。由于 exec() 函数没有返回,因此下面的 result() 函数也就不会被执行。直到对话框关闭,exec() 函数返回,此时,我们就可以取得对话框的数据。



需要注意的一点是,如果我们设置 dialog 的属性为 WA_DeleteOnClose,那么当对话框关闭时,对象被销毁,我们就不能使用这种办法获取数据了。在这种情况下,我们可以考虑使用 parent 指针的方式构建对话框,避免设置 WA_DeleteOnClose 属性;或者是利用另外的方式。



实际上,QDialog::exec() 是有返回值的,其返回值是 QDialog::Accepted 或者 QDialog::Rejected。一般我们会使用类似下面的代码:

  1. QDialog dialog(this);
  2. if (dialog.exec() == QDialog::Accepted) {
  3.     // do something
  4. } else {
  5.     // do something else
  6. }
复制代码

来判断对话框的返回值,也就是用户是点击了“确定”还是“取消”。更多细节请参考 QDialog 文档。



模态对话框相对简单,如果是非模态对话框,QDialog::show() 函数会立即返回,如果我们也这么写,就不可能取得用户输入的数据。因为 show() 函数不会阻塞主线程,show() 立即返回,用户还没有来得及输入,就要执行后面的代码,当然是不会有正确结果的。那么我们就应该换一种思路获取数据,那就是使用信号槽机制。



由于非模态对话框在关闭时可以调用 QDialog::accept() 或者 QDialog::reject() 或者更通用的 QDialog::done() 函数,所以我们可以在这里发出信号。另外,如果找不到合适的信号发出点,我们可以重写 QDialog::closeEvent() 函数,在这里发出信号。在需要接收数据的窗口(这里是主窗口)连接到这个信号即可。类似的代码片段如下所示:

  1. //!!! Qt 5
  2. // in dialog:
  3. void UserAgeDialog::accept()
  4. {
  5.     emit userAgeChanged(newAge); // newAge is an int
  6.     QDialog::accept();
  7. }

  8. // in main window:
  9. void MainWindow::showUserAgeDialog()
  10. {
  11.     UserAgeDialog *dialog = new UserAgeDialog(this);
  12.     connect(dialog, &UserAgeDialog::userAgeChanged, this, &MainWindow::setUserAge);
  13.     dialog->show();
  14. }

  15. // ...

  16. void MainWindow::setUserAge(int age)
  17. {
  18.     userAge = age;
  19. }
复制代码

上面的代码很简单,这里不再赘述。另外,上述代码的 Qt 4 版本也应该可以很容易地实现。



不要担心如果对话框关闭,是不是还能获取到数据。因为 Qt 信号槽的机制保证,在槽函数在调用的时候,我们始终可以使用 sender() 函数获取到 signal 的发出者。关于 sender() 函数,可以在文档中找到更多的介绍。顺便说一句,sender() 函数的存在使我们可以利用这个函数,来实现一个只能打开一个的非模态对话框(方法就是在对话框打开时在一个对话框映射表中记录下标记,在对话框关闭时利用 sender() 函数判断是不是该对话框,然后从映射表中将其删除)。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值