Qt学习五 - 对话框
一、对话框简介
开发桌面程序,总会需要使用对话框来实现短期任务或者简洁的交互。在Qt中,提供了QDialog类来实现对话框。在QDialog和其子类中,对parent指针有额外的解释:当parent为NULL时,对话框会作为一个顶层窗口,否则则会作为其父组件的子对话框(此时默认显示在父组件的中心位置)。可以新建一个项目,在主窗口上添加一个push button,然后在相应的槽函数中添加如下代码:
QDialog dlg; dlg.setWindowTitle("hello dialog !"); dlg.exec();
运行程序查看效果,然后将其修改为:
QDialog dlg(this); dlg.setWindowTitle("hello dialog !"); dlg.exec();
再运行程序,对比两次的差别。
对话框分为模态对话框和非模态对话框两种。模态对话框又分为应用级别的模态对话框和窗口级别的模态对话框。应用级别的模态对话框会阻塞同一应用下的所有窗口,当对话框出现时,用户先要和对话框进行交互,直到对话框关闭才可以和访问其他窗口;窗口级别的模态对话框只会阻塞与对话框相关联的窗口,允许用户与其他窗口进行交互;非模态对话框则与模态对话框相反,它不会阻塞用户与任何窗口的交互。
Qt中,实现应用级别的模态对话框使用QDialog::exec()函数,例如我们上面写的代码,实现窗口级别的模态对话框使用QDialog::open()函数,实现非模态对话框使用QDialog::show()函数。将上面的代码改为非模态对话框方式:
QDialog dlg; dlg.setWindowTitle("hello dialog !"); dlg.show();
运行发现对话框一闪而过,这是因为对话框创建在栈上,并且show()函数不会阻塞当前线程,对话框显示后代码会继续向下执行,当执行完按钮的槽函数后,超出对话框的作用域,对话框就被析构了。所以需要将对话框创建在堆上,如下:
QDialog* dlg = new QDialog; dlg->setWindowTitle("hello dialog !"); dlg->show();
创建在堆上就会涉及到释放内存,我们可以指定对话框的parent 为主窗口
QDialog* dlg = new QDialog(this);
但是这样如果主窗口不关闭,dialog就不会被销毁,内存会一直被占用。并且QWidget类的parent只能是QWidget的指针,如果对话框不是显示在界面类上怎么办?针对这个问题,我们可以设置QDialog的WindowAttribute
QDialog* dlg = new QDialog; dlg->setWindowTitle("hello dialog !"); dlg->setAttribute(Qt::WA_DeleteOnClose); dlg->show();
这样当对话框关闭时会自动销毁,QObject类还有一个deleteLater()函数,该函数会在事件循环结束后销毁该对话框。
二、对话框数据传递
从模态对话框获取数据:
QDialog dlg;
dlg.exec();
qDebug() << dlg.result();
运行后,不会获取到结果,这是因为exec()(开启一个事件循环)会阻塞当前线程,当关闭对话框exec()函数返回时才会执行下面的代码,才可以获取到数据。如果设置了WA_DeleteOnClose,那么当对话框关闭时就会被销毁,就不能用这种方法获取数据了。exec()函数有两个返回值:QDialog::Accepted和QDialog::Rejected,通常我们会使用类似下面的代码:
QDialog dlg; if (dlg.exec() == QDialog::Accepted) { //do something } else { //do something }
从非模态对话框获取数据:
因为QDialog::show()函数不会阻塞线程,show()会立即返回,所以不能通过上面的方式来获取数据,否则不等用户输入,已经执行了下面的代码。我们可以使用信号和槽机制,来获取数据。非模态对话框在关闭时可以调用QDialog::accept()或者QDialog::reject或者QDialog::done()函数,所以我们可以重写QDialog::accept()函数,在这里发送信号。也可以重写QDialog::closeEvent()函数来发送信号。然后在需要接受数据的窗口链接这个信号即可。
在QDialog子类中:
void UserAgeDialog::accept() { emit userAgeChanged(newAge); // newAge is an int QDialog::accept(); }
在mainwindow中:
void MainWindow::showUserAgeDialog() { UserAgeDialog *dialog = new UserAgeDialog(this); connect(dialog, &UserAgeDialog::userAgeChanged, this, &MainWindow::setUserAge); dialog->show(); }
void MainWindow::setUserAge(int age) { userAge = age; }
三、标准对话框
标准对话框就是Qt内置的对话框,它们都是继承与QDialog类。打开帮助文档找到QDialog类,
可以看到当前版本Qt所支持的内置对话框。
- QColorDialog:选择颜色
- QErrorMessage:错误提示
- QFileDialog:选择文件
- QFontDialog:选择字体
- QinputDialog:允许用户输入一个值,并返回该值
- QMessageBox:模态对话框,用于提示信息,询问问题等
- QProgressDialog:显示操作过程
下面以QMessageBox为例,做个简单介绍,QMessageBox用于显示信息提示,我们通常会用到以下几个静态函数:
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的简单使用:
if (QMessageBox::Yes == QMessageBox::question(this,"question","are you ok?",QMessageBox::Yes|QMessageBox::No,QMessageBox::Yes)) { QMessageBox::information(this,"information","I'm glad to hear that"); } else { QMessageBox::information(this,"information","i'm sorry"); }
我们首先使用question来询问一个问题,然后根据用户点击的按钮不同作出相应的反应。QMessageBox类的static函数使用起来非常简单方便,如果我们需要进行定制QMessageBox,则可以通过设置其属性来实现。例如做一个询问是否需要保存的对话框:
//首先创建一个QMessagBox QMessageBox box; //设置对话框标题 box.setText("The document has been modified"); //设置对话框信息 box.setInformativeText("Do you want to save your changes?"); //设置详细信息,设置此属性,对话框会有一个show details的按钮,当点击该按钮时,显示详细信息 box.setDetailedText("this is detail information"); //设置对话框按钮 box.setStandardButtons(QMessageBox::Save|QMessageBox::Discard|QMessageBox::Cancel); //设置对话框默认按钮 box.setDefaultButton(QMessageBox::Save); //显示对话框并接受返回值 int ret = box.exec(); //根据返回值不同,作出相应的操作 switch (ret) { case QMessageBox::Save: qDebug() << "save"; break; case QMessageBox::Discard: qDebug() << "discard"; break; case QMessageBox::Cancel: qDebug() << "cancel"; break; default: break; }
运行结果如下:
我这是在Mac下,如果是在windows下,那么Qt会自动将其设置为适应windows习惯的对话框。