Qt学习笔记(六)——各种栏,对话框

一、菜单栏、工具栏和状态栏

QMainWindow通常只作为“主窗口”,对话框窗口则更多地使用QDialog类。我们会在后面看到,QDialog类会缺少一些QMainWindow类提供方便的函数,比如menuBar()以及toolBar()。使用menuBar()函数,Qt 为我们创建了一个菜单栏。menuBar()QMainWindow提供的函数,因此你是不会在QWidget或者QDialog中找到它的。这个函数会返回窗口的菜单栏,如果没有菜单栏则会新创建一个。

Qt 中,表示菜单的类是QMenuBar。QMenuBar代表的是窗口最上方的一条菜单栏。我们使用其addMenu()函数为其添加菜单。尽管我们只是提供了一个字符串作为参数,但是 Qt 为将其作为新创建的菜单的文本显示出来。至于 & 符号,我们已经解释过,这可以为菜单创建一个快捷键。当我们创建出来了菜单对象时,就可以把QAction添加到这个菜单上面,也就是addAction()函数的作用。

QToolBar就是工具栏。我们使用的是addToolBar()函数添加新的工具栏。一个窗口只有一个菜单栏,但是却可能有多个工具栏。工具栏可以设置成固定的、浮动的等等,具体设置可以参考 Qt 文档。

使用QAction::setStatusTip()可以设置该动作在状态栏上的提示文本。QMainWindow有一个statusBar()函数可以添加状态栏。

QStatusBar继承了QWidget,因此,我们可以将其它任意QWidget子类添加到状态栏,从而实现类似 Photoshop 窗口底部那种有比例显示、有网格开关的复杂状态栏。

二、对话框简介

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

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

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

Qt 使用QDialog::exec()实现应用程序级别的模态对话框,使用QDialog::open()实现窗口级别的模态对话框,使用QDialog::show()实现非模态对话框。

三、对话框数据传递

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

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

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

类似的代码片段如下所示:

// in dialog:
void UserAgeDialog::accept()
{
    emit userAgeChanged(newAge); // newAge is an int
    QDialog::accept();
}

// in main window:
void MainWindow::showUserAgeDialog()
{
    UserAgeDialog *dialog = new UserAgeDialog(this);
    connect(dialog, &UserAgeDialog::userAgeChanged, this, &MainWindow::setUserAge);
    dialog->show();
}

// ...

void MainWindow::setUserAge(int age)
{
    userAge = age;
}

四、标准对话框 QMessageBox

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

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

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:

if (QMessageBox::Yes == QMessageBox::question(this,
                                              tr("Question"),
                                              tr("Are you OK?"),
                                              QMessageBox::Yes | QMessageBox::No,
                                              QMessageBox::Yes)) {
    QMessageBox::information(this, tr("Hmmm..."), tr("I'm glad to hear that!"));
} else {
    QMessageBox::information(this, tr("Hmmm..."), tr("I'm sorry!"));
}

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

QMessageBox类的 static 函数优点是方便使用,缺点也很明显:非常不灵活。我们只能使用简单的几种形式。为了能够定制QMessageBox细节,我们必须使用QMessageBox的属性设置 API。

例如,如果我们希望制作一个询问是否保存的对话框,我们可以使用如下的代码:

QMessageBox msgBox;
msgBox.setText(tr("The document has been modified."));
msgBox.setInformativeText(tr("Do you want to save your changes?"));
msgBox.setDetailedText(tr("Differences here..."));
msgBox.setStandardButtons(QMessageBox::Save
                          | QMessageBox::Discard
                          | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Save);
int ret = msgBox.exec();
switch (ret) {
case QMessageBox::Save:
    qDebug() << "Save document!";
    break;
case QMessageBox::Discard:
    qDebug() << "Discard changes!";
    break;
case QMessageBox::Cancel:
    qDebug() << "Close document!";
    break;
}

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

猜你喜欢

转载自blog.csdn.net/zhao2018/article/details/82712218