首页 > 代码库 > 第二章 创建对话框

第二章 创建对话框

1、子类化QDialog

第一个例子是完全使用C++编写的Find对话框。

finddialog.h:

 1 #ifndef FINDDIALOG_H 2 #define FINDDIALOG_H 3  4 #include <QDialog> 5  6 class QCheckBox; 7 class QLabel; 8 class QLineEdit; 9 class QPushButton;10 11 class FindDialog : public QDialog12 {13     Q_OBJECT14 public:15     FindDialog(QWidget *parent = 0);16 signals:17     void findNext(const QString &str, Qt::CaseSensitivity cs);18     void findPrevious(const QString &str, Qt::CaseSensitivity cs);19 private slots:20     void findClicked();21     void enableFindButton(const QString &text);22 private:23     QLabel *label;24     QLineEdit *lineEdit;25     QCheckBox *caseCheckBox;26     QCheckBox *backwardCheckBox;27     QPushButton *findButton;28     QPushButton *closeButton;29 };30 31 #endif // FINDDIALOG_H

头部的预编译指令是为了防止对这个头文件的多重包含

对于定义了信号与槽的类来说在类定义的开始处的Q_OBJECT宏都是必须的,它给出了一些函数的声明

FindDialog类的构造函数是典型的Qt窗口部件类的定义方式。parent参数指定了它的父窗口部件。该参数的默认值是一个空指针,意味着该对话框没有父对象。

signals关键字实际上是一个宏,C++预处理器会在编译程序找到它之前把它转换成标准C++代码。我的疑问是为什么槽的声明是私有的

finddialog.cpp:

 1 #include <QtGui> 2 #include <QLabel> 3 #include <QCheckBox> 4 #include <QLineEdit> 5 #include <QPushButton> 6 #include <QHBoxLayout> 7 #include <QVBoxLayout> 8 #include "finddialog.h" 9 10 FindDialog::FindDialog(QWidget *parent)11     :QDialog(parent)12 {13     label = new QLabel(tr("Find &what:"));14     lineEdit = new QLineEdit;15     label->setBuddy(lineEdit);16 17     caseCheckBox = new QCheckBox(tr("Match &case"));18     backwardCheckBox = new QCheckBox(tr("Search &backward"));19 20     findButton = new QPushButton(tr("&Find"));21     findButton->setDefault(true);22     findButton->setEnabled(false);23 24     closeButton = new QPushButton("Close");25     connect(lineEdit, SIGNAL(textChanged(const QString &)),26             this, SLOT(enableFindButton(const QString &)));27     connect(findButton, SIGNAL(clicked()),28             this, SLOT(findClicked()));29     connect(closeButton, SIGNAL(clicked()),30             this, SLOT(close()));31 32     QHBoxLayout *topLeftLayout = new QHBoxLayout;33     topLeftLayout->addWidget(label);34     topLeftLayout->addWidget(lineEdit);35 36     QVBoxLayout *leftLayout = new QVBoxLayout;37     leftLayout->addLayout(topLeftLayout);38     leftLayout->addWidget(caseCheckBox);39     leftLayout->addWidget(backwardCheckBox);40 41     QVBoxLayout *rightLayout = new QVBoxLayout;42     rightLayout->addWidget(findButton);43     rightLayout->addWidget(closeButton);44     rightLayout->addStretch();45 46     QHBoxLayout *mainLayout = new QHBoxLayout;47     mainLayout->addLayout(leftLayout);48     mainLayout->addLayout(rightLayout);49     setLayout(mainLayout);50 51     setWindowTitle(tr("Find"));52     setFixedHeight(sizeHint().height());53 }54 55 void FindDialog::findClicked()56 {57     QString text = lineEdit->text();58     Qt::CaseSensitivity cs =59             caseCheckBox->isChecked() ? Qt::CaseSensitive60                                       : Qt::CaseInsensitive;61     if(backwardCheckBox->isChecked())62     {63         emit findPrevious(text, cs);64     }65     else66     {67         emit findNext(text, cs);68     }69 }70 71 void FindDialog::enableFindButton(const QString &text)72 {73     findButton->setEnabled(!text.isEmpty());74 }

在字符串周围的tr函数调用时把它们翻译成其他语言的标记,即使现在没有需要将程序翻译成其它语言,但是这样做也是有好处的。

在部件的text字符创中使用了符号“&”表示快捷键,使用alt+“&”后的第一个字母可以实现快捷的选中该部件。

所谓buddy,就是一个窗口部件,它可以再按下标签的快捷键时接受焦点输入。

setDefault让Find按钮称为默认按钮,默认按钮即当用户按下回车时能够按下对应的键。

omit是Qt中的关键字,它会被C++预处理器转换成标准C++代码。

main.cpp:

 1 #include <QApplication> 2 #include "finddialog.h" 3  4 int main(int argc, char** argv) 5 { 6     QApplication app(argc, argv); 7     FindDialog *dialog = new FindDialog; 8     dialog->show(); 9     return app.exec();10 }

运行效果:

2、深入介绍槽与信号

信号与槽是Qt编程的基础。它可以让编程人员将这些互不了解的对象绑定在一起。

槽和普通的C++函数几乎是一样的,可以使虚函数、可以被重载、可以使公有的、保护的、私有的。并且也可以被其他C++成员函数直接调用,还有它们的参数可以使任意类型,唯一不同的是:槽还可以和信号连接在一起,在这种情况下,每当发射这个信号的时候,就会自动调用这个槽。

connect(sender, SIGNAL(signal), receiver,SLOT(slot));

这里的sender和receiver是指向QObject的指针,signal和slot是不带参数的函数名。实际上,SIGNAL和SLOT宏会把它们的参数转换成相应的字符串。

  • 一个信号可以连接多个槽

在发射这个信号的时候会以不确定的顺序一个接一个的调用这些槽

  • 多个信号可以连接同一个槽

无论发射哪一个信号都会调用这个槽

  • 一个信号可以与另外一个信号连接

当发射第一个信号的时候也会发射第二个信号

  • 连接可以被移除

这种情况很少用

注意:要把信号连接到槽,它们的参数必须具有相同的顺序和相同的类型。例外:如果信号比连接的槽的参数多,那么后面多余的参数将被忽略。

3、快速设计对话框

这一节会使用Qt Designer来可视化的设计一个对话框。

操作步骤就是使用Qt Designer来设计需要的对话框,然后保存为.ui的格式。

在编译的时候会将.ui格式的文件转换为C++并且存储在ui_name.h和ui_name.cpp中。

生成的类没有任何基类,当在程序中使用它时,可以创建一个QDialog类的对象,然后把它传递给setupUi()函数。

现在定义一个新的类继承自QDialog和Ui::GoToCellDialog类(我填写的Ui文件生成的类名)。

gotocelldialog.h:

 1 #ifndef GOTOCELLDIALOG_H 2 #define GOTOCELLDIALOG_H 3  4 #include <QDialog> 5 #include "ui_gocelldialog.h" 6  7 class GotoCellDialog : public QDialog, public Ui::GoToCellDialog 8 { 9     Q_OBJECT10 public:11     GotoCellDialog(QWidget *parent = 0);12 private slots:13     void on_lineEdit_textChanged();14 };15 16 #endif // GOTOCELLDIALOG_H

该类继承自两个类:QDialog、Ui::GoToCellDialog

gotocelldialog.cpp:

 1 #include <QtGui> 2 #include "gotocelldialog.h" 3  4 GotoCellDialog::GotoCellDialog(QWidget *parent) 5     : QDialog(parent) 6 { 7     setupUi(this); 8  9     // QRegExp regExp("[A-Za-z][1-9][0-9]{0, 2}");10     QRegExp regExp("[A-Za-z][1-9][0-9]{0,2}");11     lineEdit->setValidator(new QRegExpValidator(regExp, this));12 13     connect(okButton, SIGNAL(clicked()), this, SLOT(accept()));14     connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject()));15 }16 17 void GotoCellDialog::on_lineEdit_textChanged()18 {19     okButton->setEnabled(lineEdit->hasAcceptableInput());20 }

实现文件中绑定了需要绑定的信号与槽。

对编辑框的输入进行了验证,使用正则表达式的方法来验证。

accept()槽可以讲对话框返回的结果变量设置为QDialog::Accepted,其值为1、而reject()槽会把对话框的值设置为QDialog::Rejected,其值为0。可以根据对话框的返回值来判断是否点击了OK按钮。

main.cpp:

 1 #include <QApplication> 2  3 #include "gotocelldialog.h" 4  5 int main(int argc, char *argv[]) 6 { 7     QApplication a(argc, argv); 8  9     GotoCellDialog *dialog = new GotoCellDialog;10     dialog->show();11 12     return a.exec();13 }

实例化一个该类的对象并显示出来。

使用QDialogButtonBox来制作这个对话框,以使它在MAC平台上显得更加圆润。

 

4、