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习惯的对话框。

 

posted @ 2017-04-09 20:31  黑夜里的猫  阅读(2605)  评论(1编辑  收藏  举报