首页 > 代码库 > 第二章 创建对话框
第二章 创建对话框
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平台上显得更加圆润。