Qt例子:对话框
这是《C GUI Qt4编程》第二版中的一个例子(P18~P22),实现了一个对话框:当文本框中输入合适的字符串,OK按钮会自动使能,如下图所示。书中的做法对于初学者来说不是太清晰,我完全按照例子却没有让OK按钮奏效。本文是该例子的一个梳理。
开发环境:1. Win7 + Qt Creator
2. Ubuntu12.04 + Qt Creator
本文是在Win7下建立空项目,先用设计器划出图,逐步添加各种文件。Ubuntu下则是直接拷贝了cpp,h和ui文件,用命令qmake -project生成pro项目文件,再qmake gotocell.pro生成Makefile,最后make生成目标文件和可执行文件。
Windows下的开发步骤:
1. 在“编辑”空白区单击右键——>新建项目——>其他项目——>空的Qt项目——>命名gotocell,则自动生出gotocell.pro文件
2. 在项目目录上单击右键——>添加新文件——>Qt——>Qt设计师界面类——>Dialog without Buttons——>命名gotocelldialog.ui
3. 将该Dialog对象命名为GoToCellDialog,拖放Label,LineEdit,2个Pushbutton,并在属性栏里改名,将objectName的值依次改为label,lineEdit,okButton,cancelButton,将Text改为&Cell Location:,OK,Cancel,将label,lineEdit,cancelButton勾选enabled
4. 单击界面上的Cell Location:并按下Ctrl再单击输入框以便同时选中这2个控件,点击下图红框里的“编辑伙伴”,这样当按快捷键Ctrl+C时,输入框会自动获得焦点
5. 以Ctrl的方法,同时选中Cell Location和输入框,点击下图红框里的“水平布局”,使二者在同一水平线上。对OK和Cancel也“水平布局”
6. 单击窗体中的空白使整个大框选中,点击“垂直布局”
7. 点击“调整大小”,自由调整整个对话框大小
8. 点击“编辑Tab顺序”,则在每个可接受焦点的控件上出现带蓝色巨型的数字,按照所想顺序单击每个控件,可调整Tab顺序。到此为止界面就完成了。
9. 在项目目录上单击右键——>添加新文件——>C++——>C++源文件——>命名为main.cpp,代码如下所示,去掉7,15行,去掉第6,12,13,14行注释
1 //main.cpp 2 3 #include <QApplication> 4 #include <QDialog> 5 6 //#include "ui_gotocelldialog.h" 7 #include "gotocelldialog.h" 8 9 int main(int argc, char *argv[]) 10 { 11 QApplication app(argc, argv); 12 //Ui::GoToCellDialog ui; 13 //QDialog *dialog = new QDialog; 14 //ui.setupUi(dialog); 15 GoToCellDialog *dialog = new GoToCellDialog; 16 dialog->show(); 17 18 return app.exec(); 19 }
10. 点击“运行”,则自动生成文件ui_gotocelldialog.h,内容如下所示:
1 /******************************************************************************** 2 ** Form generated from reading UI file 'gotocelldialog.ui' 3 ** 4 ** Created: Mon Aug 20 00:22:30 2012 5 ** by: Qt User Interface Compiler version 4.8.1 6 ** 7 ** WARNING! All changes made in this file will be lost when recompiling UI file! 8 ********************************************************************************/ 9 10 #ifndef UI_GOTOCELLDIALOG_H 11 #define UI_GOTOCELLDIALOG_H 12 13 #include <QtCore/QVariant> 14 #include <QtGui/QAction> 15 #include <QtGui/QApplication> 16 #include <QtGui/QButtonGroup> 17 #include <QtGui/QDialog> 18 #include <QtGui/QHBoxLayout> 19 #include <QtGui/QHeaderView> 20 #include <QtGui/QLabel> 21 #include <QtGui/QLineEdit> 22 #include <QtGui/QPushButton> 23 #include <QtGui/QSpacerItem> 24 #include <QtGui/QVBoxLayout> 25 26 QT_BEGIN_NAMESPACE 27 28 class Ui_GoToCellDialog 29 { 30 public: 31 QVBoxLayout *verticalLayout; 32 QHBoxLayout *horizontalLayout; 33 QLabel *label; 34 QLineEdit *lineEdit; 35 QHBoxLayout *horizontalLayout_2; 36 QSpacerItem *horizontalSpacer; 37 QPushButton *okButton; 38 QPushButton *cancelButton; 39 40 void setupUi(QDialog *GoToCellDialog) 41 { 42 if (GoToCellDialog->objectName().isEmpty()) 43 GoToCellDialog->setObjectName(QString::fromUtf8("GoToCellDialog")); 44 GoToCellDialog->resize(310, 119); 45 verticalLayout = new QVBoxLayout(GoToCellDialog); 46 verticalLayout->setObjectName(QString::fromUtf8("verticalLayout")); 47 horizontalLayout = new QHBoxLayout(); 48 horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout")); 49 label = new QLabel(GoToCellDialog); 50 label->setObjectName(QString::fromUtf8("label")); 51 52 horizontalLayout->addWidget(label); 53 54 lineEdit = new QLineEdit(GoToCellDialog); 55 lineEdit->setObjectName(QString::fromUtf8("lineEdit")); 56 57 horizontalLayout->addWidget(lineEdit); 58 59 60 verticalLayout->addLayout(horizontalLayout); 61 62 horizontalLayout_2 = new QHBoxLayout(); 63 horizontalLayout_2->setObjectName(QString::fromUtf8("horizontalLayout_2")); 64 horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); 65 66 horizontalLayout_2->addItem(horizontalSpacer); 67 68 okButton = new QPushButton(GoToCellDialog); 69 okButton->setObjectName(QString::fromUtf8("okButton")); 70 okButton->setEnabled(false); 71 okButton->setDefault(true); 72 73 horizontalLayout_2->addWidget(okButton); 74 75 cancelButton = new QPushButton(GoToCellDialog); 76 cancelButton->setObjectName(QString::fromUtf8("cancelButton")); 77 78 horizontalLayout_2->addWidget(cancelButton); 79 80 81 verticalLayout->addLayout(horizontalLayout_2); 82 83 #ifndef QT_NO_SHORTCUT 84 label->setBuddy(lineEdit); 85 #endif // QT_NO_SHORTCUT 86 87 retranslateUi(GoToCellDialog); 88 89 QMetaObject::connectSlotsByName(GoToCellDialog); 90 } // setupUi 91 92 void retranslateUi(QDialog *GoToCellDialog) 93 { 94 GoToCellDialog->setWindowTitle(QApplication::translate("GoToCellDialog", "Go to Cell", 0, QApplication::UnicodeUTF8)); 95 label->setText(QApplication::translate("GoToCellDialog", "&Cell Location:", 0, QApplication::UnicodeUTF8)); 96 okButton->setText(QApplication::translate("GoToCellDialog", "OK", 0, QApplication::UnicodeUTF8)); 97 cancelButton->setText(QApplication::translate("GoToCellDialog", "Cancel", 0, QApplication::UnicodeUTF8)); 98 } // retranslateUi 99 100 }; 101 102 namespace Ui { 103 class GoToCellDialog: public Ui_GoToCellDialog {}; 104 } // namespace Ui 105 106 QT_END_NAMESPACE 107 108 #endif // UI_GOTOCELLDIALOG_H
现在运行程序,出现的对话框可以工作,但是没有想要的功能:OK失效,Cancel什么都做不了,输入框可接受任何文本。
要想让对话框具有适当的工呢个,最简捷的作法是创建一个新类,让该类同时从QDialog和Ui::GoToCellDialog中继承,由它来实现缺失的功能。命名惯例是将该类与uic所生成的类具有相同的名字,没有Ui前缀。
11. 在项目目录上单击右键——>添加新文件——>C++——>C++头文件——>命名为gotocelldialog.h,代码如下所示
1 //gotocelldialog.h 2 3 #ifndef GOTOCELLDIALOG_H 4 #define GOTOCELLDIALOG_H 5 6 #include <QDialog> 7 #include "ui_gotocelldialog.h" 8 9 class GoToCellDialog : public QDialog, public Ui::GoToCellDialog 10 { 11 Q_OBJECT 12 public: 13 GoToCellDialog(QWidget *parent = 0); 14 private slots: 15 void on_lineEidt_textChanged(); 16 }; 17 18 #endif // GOTOCELLDIALOG_H
12. 在项目目录上单击右键——>添加新文件——>C++——>C++源文件——>命名为gotocelldialog.cpp,代码如下所示
1 //gotocelldialog.cpp 2 3 #include <QtGui> 4 #include "gotocelldialog.h" 5 6 GoToCellDialog::GoToCellDialog(QWidget *parent) : QDialog(parent) 7 { 8 setupUi(this); 9 QRegExp regExp("[A-Za-z][1-9][0-9]{0,2}"); 10 lineEdit->setValidator(new QRegExpValidator(regExp, this)); 11 12 //connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); 13 //connect(okButton, SIGNAL(clicked()), this, SLOT(on_lineEidt_textChanged())); 14 connect(lineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(on_lineEidt_textChanged())); 15 connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); 16 } 17 18 void GoToCellDialog::on_lineEidt_textChanged() 19 { 20 okButton->setEnabled(lineEdit->hasAcceptableInput()); 21 }
代码注解:
setupUi()初始化窗体,由于使用了多重继承,可一直直接访问Ui::GoToCellDialog中的成员。创建了用户接口后,setupUi()还会自动将符合on_objectName_signalName()命名惯例的任意槽与相应的objectName的signalName()信号连接到一起。本例中意味着setuoUi()将建立如下所示的信号槽连接关系:
connect(lineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(on_lineEidt_textChanged()));
Qt有3个内置检验器类:QIntValidator,QDoubleValidator,QRegExpValidator。代码QRegExp regExp("[A-Za-z][1-9][0-9]{0,2}");的意思是允许一个大写或小写字母,后面跟着一个范围为1-9的数字,后面再跟0个、1个或2个0-9的数字。
13. 重写main.cpp,如第一段代码所示。
按照书上的方法,注释掉gotocelldialog.cpp里的14和13行,去掉12行注释,则正确输入后OK还是不起作用。书上的说法:accept()和reject()这两个槽都可以关闭对话框,但accept()槽可以讲对话框返回的结果变量设置为QDialog::Accepted(其值等于1),reject()槽会把对话框的值设置为QDialog::Rejected(其值等于0),当使用这个对话框的时候,可以利用这个结果变量判断客户是否单击了OK按钮从而执行相应的动作。