Qt4读书笔记5
第二章 创建对话框
本章将教你如何用Qt创建对话框。对话框呈献给用户一些选项(options and choices),运行用户设置这些选项。这就叫对话框(dialog boxes,or simply "dialogs"),它提供了用户和应用互相交谈的方式。
许多GUI应用包括一个主窗口(a main window)和一个菜单,一个工具条,还有成打的对话框。当然也可以做一个只有对话框的应用,如计算器。
我们将创建一个纯粹的对话框。然后看看如何使用Qt Designer创建对话框。使用Qt Designer比手工编码如影并易于修改。
QDialogde的子类
源代码分为两个文件:finddialog.h和finddialog.cpp,我们先看看finddialog.h
#ifndef FINDDIALOG_H
#define FINDDIALOG_H
保护头文件,避免多次包含
#include <QDialog>
QDialog类继承自QWidge
class QCheckBox;
class QLabel;
class QLineEdit;
class QPushButton;
声明后面用到的Qt类。forward declaration是C++的惯用做法。
然后我们定义了FindDialog作为QDialog的子类
class FindDialog : public QDialog
{
Q_OBJECT
public:
FindDialog(QWidget *parent = 0);
Q_OBJECT宏必须定义在类的开始处,这是使用signals or slot的要求。
FindDialog构造方法是典型的,parent参数指明其父控件。缺省为null,表示这个对话框无父控件。
signals:
void findNext(const QString &str, Qt::CaseSensitivity cs);
void findPrevious(const QString &str, Qt::CaseSensitivity cs);
signals区域声明两个signal,当用户点击find button时,对话框发出这两个signal.如果search backward选项enabled,对话框发出findPrevious(),否则发出findNext().
signals关键字实际是一个宏。C++预处理器会将其转换成标准C++. Qt::CaseSensitivity是一个enum类型,有两个值:Qt::CaseSensitive和Qt::CaseInsensitive
private slots:
void findClicked();
void enableFindButton(const QString &text);
private:
QLabel *label;
QLineEdit *lineEdit;
QCheckBox *caseCheckBox;
QCheckBox *backwardCheckBox;
QPushButton *findButton;
QPushButton *closeButton;
};
#endif
定义了两个slot.slots也是一个宏
下面我们看看finddialog.cpp,这个文件是FindDialog类的实现
#include <QtGui>
#include "finddialog.h"
首先包含<QtGui>,这个头文件包括Qt GUI类的定义。Qt包含许多模块,每个模块都有自己的library。最重要的模块是QtCore, QtGui,QtNetwork, QtOpenGL, QtScript, QtSql, QtSvg, QtXml. <QtGui>头文件包括QtCore和QtGui模块所有的类。这样避免了我们自己去找包含的类,减少麻烦。
FindDialg::FindDialog(QWidget *parent) : QDialog(parent)
{
label = new QLabel(tr("Find &what:"));
lineEdit = new QLineEdit;
label->setBuddy(lineEdit);
caseCheckBox = new QCheckBox(tr("Match &case"));
backwardCheckBox = new QCheckBox(tr("Search &backward"));
findButton = new QPushButton(tr("&Find"));
findButton->setDefault(true);
findButton->setEnabled(false);
closeButton = new QPushButton(tr("Close"));
其中的tr() function是为了翻译成其他语言做准备。&用于标识快捷键。
label->setBuddy(lineEdit);设置伙伴。当alt+w快键按下时,焦点将转移到lineEdit控件上。
connect(lineEdit, SIGNAL(textChanged(const QString &)),
this, SLOT(enableFindButton(const QString &)));
connect(findButton, SIGNAL(clicked()), this, SLOT(findClicked()));
connect(closeButton, SIGNAL(clicked()), this, SLOT(close()));
private slot enableFindButton(const QString &)当line editor的文本改变时被调用。private findClicked()当用户点击Find按钮时被调用。close() slot继承自QWidget,缺省的行为是隐藏widget但不删除。(这与java类似)
因为QObject是FindDialog的祖先,我们可以省略connect()调用中的QObject::前缀。
QHBoxLayout *topLeftLayout = new QHBoxLayout;
topLeftLayout->addWidget(label);
topLeftLayout->addWidget(lineEdit);
QVBoxLayout * leftLayout = new QVBoxLayout;
leftLayout->addLayout(topLeftLayout);
leftLayout->addWidget(caseCheckBox);
leftLayout->addWidget(backwardCheckBox);
QVBoxLayout *rightLayout = new QVBoxLayout;
rightLayout->addWidget(findButton);
rightLayout->addWidget(closeButton);
rightLayout->addStretch();
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addLayout(leftLayout);
mainLayout->addLayout(rightLayout);
setLayout(mainLayout);
使用布局管理器。布局管理器可以包含widget或者其他布局管理器。通过嵌套使用QHBoxLayout,QVBoxLayout和QGridLayout可以生成很复杂的对话框。
其中addStrech()是在下面增加了spacer item(or stretch).这样可以保证上面的两个按钮在顶部。
setWindowTitle(tr("Find"));
setFixedHeight(sizeHint().height());
}
QWidget::sizeHint()函数返回一个widget的实际大小。
我们创建了很多对象,没有写相关的delete,只是不需要的,因为当父对象destroyed,Qt自动删除子对象.
下面看看dialog's slots:
void FindDialog::findClicked()
{
QString text = lineEdit->text();
Qt::CaseSensitivity cs = caseCheckBox->isChecked() ?
Qt::CaseSensitive : Qt::CaseInsensitive;
if(backwardCheckBox->isChecked())
{
emit findPrevious(text, cs);
}
else
{
emit findNext(text, cs);
}
}
void FindDialog::enableFindButton(const QString &text)
{
findButton->setEnabled(!text.isEmpty());
}
其中的emit是qt的关键字,预处理器会将其变成C++代码。
最后是main.cpp来测试FindDialog控件
#include <QApplication>
#include "finddialog.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
FindDialog *dialog = new FindDialog;
dialog->show();
return app.exec();
}
编译问题:
由于使用了Q_OBJECT宏,所以qmake将包含特殊的规则来运行moc(Qt's meta-object compiler)。
使用Q_OBJECT宏的类必须有moc运行。qmake会自动增加这些规则到makefile.