本节内容主要介绍完全手写代码的方式创建第一个对话框。
子类话QDialog
完全使用C++编写一个Find(查找)对话框。创建文件finddialog.h和finddialog.cpp文件。首先是finddialog.h文件说起:
#ifndef FINDDIALOG_H
#define FINDDIALOG_H
#include <QDialog>
class QCheckBox;
class QLabel;
class QLineEidt;
class QPushButton;
第1、2行能够防止对这个头文件的多重包含。
第3行包含了QDialog的定义,它是QT中对话框的基类。QDialog从QWidget类中派生出来。
第4行到第7行前置声明了一些用于这个对话框实现的QT类。前置声明会告诉C++编译程序类的存在,而不用提供类定义中所有细节。
然后定义FindDialog,并让他成为QDialog的子类:
class FindDialog: public QDialog{
Q_OBJECT
public:
findDialog(QWidget *parent=0);
FindDialog的构造函数就是一个典型的QT窗口部件的定义方式。parent参数指定了它的父窗口部件。该参数的默认值是一个空指针,意味着该对话框没有父对象。
signals:
void findNext(const QString &str,Qt::CaseSensitivity cs);
void findPrevious(const QString &str,Qt::CaseSensitivity cs);
signals部分声明了当用户单击Find按钮时对话框所发射的两个信号。如果向前查询(search backward)选项生效,对话框就发射findPrevious()信号,否则它就发射findNext()信号。signals关键字实际上是一个宏,C++预处理器会在编译程序找到它之前把它转换成标准C++代码。
private slots:
void findClicked();
void enableFindButton(const QString &text);
private:
QLabel *label;
QLineEidt *lineEidt;
QCheckBox *caseCheckBox;
QCheckBox *backwardCheckBox;
QPushButton *findButton;
QPushButton *closeButton;
在这个类中private段中声明了两个槽,为了实现这两个槽,几乎需要访问这个对话框的所有子窗口部件,所以也保留了指向它们的指针。关键字slots也是一个宏。
finddialog.cpp中包含了对FindDialog类的实现:
#include <QtGui>
#include "finddialog.h"
首先,需要包含
在finddialog.h文件中,**本可以简单地添加一个
finddialog::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")); //创建关闭按钮
第1行,把parent参数传递给了基类的构造函数,然后创建子窗口部件。
第9行创建了一个Find按钮,用户可在那些支持快捷键的平台下通过按下Alt+F快捷键来激活它。
符号“&”可以用来控制焦点:在第4行创建了一个带有快捷点(Alt + W)的标签,而在第6行设置了行编辑器作为标签的伙伴。所谓伙伴,就是一个窗口部件,它可以按下标签的快捷键时接收焦点。所以当用户按下Alt+W,也就是按下该标签的快捷键,焦点就会移动到这个行编辑器上。
第10行,通过调用setDefault(true)让Find按钮成为对话框的默认按钮。默认按钮就是当用户按下Enter键是能够按下对应的按钮。
第11行,禁用了Find按钮。当禁用一个窗口部件时,它通常会显示为灰色,并且不能和用户发生交互操作。
//当编辑框中文本发生改变时候,会触发槽函数enableFindButton()
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()));
只要行编辑器中的文本发生变化,就会调用私有槽enableFindButton(const QString &)。
当用户单击Find按钮时,会调用findClicked()私有槽。
当用户单击Close时,对话框就会关闭,close()槽是从QWidget中继承而来,并且它的默认行为就是把窗口部件从用户视野中隐藏起来。
由于QObject是FindDialog的父对象之一,所以可以省略connect()函数前面的QObject::前缀。
对话框中所用到的槽:
void finddialog::findClicked()
{
QString text = lineEdit->text();
Qt::CaseSensitivity cs =
caseCheckBox->isChecked() ? Qt::CaseSensitive
: Qt::CaseInsensitive;
if(backwardCheckBox->isChecked()){ //search的CheckBox是否被勾选
emit findPrevious(text, cs);
} else{
emit findNext(text, cs);
}
}
void finddialog::enableFindButton(const QString &text)
{
findButton->setEnabled(!text.isEmpty());
}
当用户单击Find按钮时,就会调用findClicked()槽。而该槽将会发射findPrevious()或findNext()信号,这取决于Search backward选项的取值。emit是Qt中的关键字,像其他Qt扩展一样,它也会被C++预处理器转换成标准的C++代码。
只要用户改变了行编辑器中的文本,就会调用enableFindButton()槽,如果行编辑器中有中文,该槽就会启用Find按钮,否则它就会禁用Find按钮。
//布局管理器
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);
布局中既可以包含多个窗口部件,也可包含其他子布局。对于Find对话框,使用了两个QHBoxLayout布局和两个QVBoxLayout布局。如下图为对话框的布局:
图右下角的小“小弹簧”是一个分隔符,或者称为“伸展器”,用它来占据Find按钮和Close按钮所余下的空白区域,这样可以确保这些按钮完全占用它们所在布局的上部空间。
当将子布局对象添加到父布局对象中时,子布局对象就会自动重定义自己的父对象,也就是说,当将主布局装到对话框中去时,它就会成为对话框的子对象了,于是它的所有窗口部件会重定义自己的父对象,从而变成对话框的子对象。如图为父子层次关系的最终结果:
最后设置显示在对话框标题栏的标题内容,并让窗口具有一个固定的高度,QWidget::sizeHint()函数可以返回一个窗口部件所“理想”尺寸大小。
setWindowTitle(tr("Find"));
setFixedHeight(sizeHint().height()); //返回一个窗口部件所理想的尺寸大小
由于在创建这个对话框中的窗口部件和布局时使用的new,所以需要写一个能够调用delete的析构函数,以便可以删除所创建的每一个窗口部件和布局。但是这样做并不是必须的,因为QT会在删除父对象的时候自动删除其所属的所有子对象,也就会删除FindDialog中作为子孙的所有子窗口部件和子布局。
完整代码
finddialog.h:
#ifndef FINDDIALOG_H
#define FINDDIALOG_H
#include <qdialog.h>
class QCheckBox;
class QLabel;
class QLineEdit;
class QPushButton; //前置声明告诉C++编译程序类的存在
class finddialog : public QDialog
{
Q_OBJECT //对于定义了信号和槽的类,在类定义开始处的Q_OBJECT宏是必须
public:
finddialog(QWidget *parent = 0); //类的构造函数,parent指定了父窗口部件
~finddialog(); //类的析构函数
signals:
//单击Find按钮时对话框发射两个信号,当search backward生效时
//发射findPrevious()信号,否则发射findNext信号
void findNext(const QString &str,Qt::CaseSensitivity cs);
void findPrevious(const QString &str,Qt::CaseSensitivity cs);
private slots:
//声明两个槽
void findClicked();
void enableFindButton(const QString &text);
private:
QLabel *label; //标签
QLineEdit *lineEdit; //行编辑框
QCheckBox *caseCheckBox; //check选择框
QCheckBox *backwardCheckBox;
QPushButton *findButton; //find按钮
QPushButton *closeButton;//关闭按钮
};
#endif // FINDDIALOG_H
finddialog.cpp:
#include <QtGui>
#include "finddialog.h"
finddialog::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 关闭")); //创建关闭按钮
//当编辑框中文本发生改变时候,会触发槽函数enableFindButton()
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()));
//布局管理器
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);
setWindowTitle(tr("Find"));
setFixedHeight(sizeHint().height()); //返回一个窗口部件所理想的尺寸大小
}
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());
}
finddialog::~finddialog()
{
}
main.cpp:
#include "finddialog.h"
#include <QTextCodec>
#include <QtGui/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTextCodec::setCodecForTr(QTextCodec::codecForLocale()); //设置中文字体
finddialog *dialog = new finddialog;
dialog->show();
return a.exec();
}