#ifndef FINDDIALOG_H // 防止多重包含 #define FINDDIALOG_H #include <QDialog> // QT 对话框基类 // 前置声明,不提供类细节使编译过程更快一些。 class QCheckBox; class QLabel; class QLineEdit; class QPushButtom; class FindDialog : public QDialog { Q_OBJECT // 对于所有定义了 信号和槽的类,在类定义开始处的 Q_OBJECT 宏 都是必需的。 public: // parent 默认为空指针即没有父对象 FindDialog(QWidget *parent = 0); // signals关键字是一个宏, 信号 signals: // CaseSensitivity 是一个枚举类型,包含Qt::CaseSensitive与Qt::CaseInsensitive void findNext(const QString &str, Qt::CaseSensitivity cs); void findPrevious(const QString &str, Qt::CaseSensitivity cs); // slots也是一个宏, 槽 private slots: void findClicked(); void enableFindButton(const QString &text); // 私有变量,类前置说明。QCheckBox、QLabel 未包含头文件,属于前置声明 private: QLabel *label; QLineEdit *lineEdit; QCheckBox *caseCheckBox; QCheckBox *backwardCheckBox; QPushButton *findButton; QPushButton *closeButton; }; #endif
finddialog.cpp
#include <QtGui> #include <QLabel> #include <QCheckBox> #include <QLineEdit> #include <QPushButton> #include <QHBoxLayout> #include "finddialog.h" FindDialog::FindDialog(QWidget *parent) : QDialog(parent) { // tr()函数调用是把他们翻译成其他语言的标记,在用户可见的字符串周围使用tr()函数是好习惯 label = new QLabel(tr("Find &what:")); // & 快捷键 lineEdit = new QLineEdit; // 设置行编辑器作为标签的伙伴。伙伴(buddy)为一个窗口部件,可在按下【标签】快捷键时接收焦点 label->setBuddy(lineEdit); caseCheckBox = new QCheckBox(tr("Match &case")); backwardCheckBox = new QCheckBox(tr("Search &backward")); findButton = new QPushButton(tr("&Find")); // 使Find按钮成为对话框默认按钮,当按下 Enter 会按下默认按钮 findButton->setDefault(true); findButton->setEnabled(false); closeButton = new QPushButton(tr("Close")); // QObject::connect,因QObject是FindDialog父对象之一,故可省略前缀QObject:: 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() 计算窗口部件“理想”的尺寸大小 setFixedHeight(sizeHint().height()); //setMinimumHeight(sizeHint().height()); } void FindDialog::findClicked() { QString text = lineEdit->text(); Qt::CaseSensitivity cs = caseCheckBox->isChecked() ? Qt::CaseSensitive : Qt::CaseInsensitive; if (backwardCheckBox->isChecked()) { //emit Qt关键字 emit findPrevious(text, cs); } else { emit findNext(text, cs); } } void FindDialog::enableFindButton(const QString &text) { findButton->setEnabled(!text.isEmpty()); // 不为空可以使用 }
布局管理类不是窗口部件,它们派生自 QLayout,故也是派生自QObject。在一个运行的应用程序中,布局是不可见的。
不使用“弹簧”分隔符时:
对话框中窗口部件和布局时使用了new , 故需要一个调用delete的析构函数,以便删除所创建的每一个窗口部件与布局。
Qt自身会在删除父对象时,自动删除其所属的子对象(子窗体子布局)。
由于类中包含 Q_OBJECT 宏,故qmake生成的makefile会自动包含一些运行moc的规则。moc指Qt的元对象编辑器,即meta-object compiler。
信号和槽
Qt编程的基础。槽和普通c++成员函数几乎是一样的,可以是虚函数;可以被重载;可以是共有的;保护的或者私有的,也可以直接被其他成员函数调用;参数可以是任意类型的。不同点在于:槽可以和信号连接在一起,即当发射信号时。会自动调用这个槽。
connect(sender, SIGNAL(signal), receiver, SLOT(slot));
sender和receiver是指向QObject的指针,signal和slot是不带参数的函数名,SIGNAL()宏和SLOT()宏会把它们的参数转换成相应的字符串。
一个信号连接多个槽,触发信号时会以不确定的顺序调用这些槽。
connect(slider, SIGNAL(valueChange(int)), spinBox, SLOT(setValue(int))); connect(slider, SIGNAL(valueChange(int)), this, SLOT(update(int)));
多个信号连接同一个槽
connect(lcd, SIGNAL(overflow()), this, SLOT(handleMathError())); connect(calculator, SIGNAL(divisionByZero()), this, SLOT(handleMathError()));
一个信号连接另一个信号,发射第一个信号时会发射第二个信号。
connect(lineEdit, SIGNAL(textChanged(const QString &)), this, SIGNAL(updateRecord(const QString &)));
连接可以被移除。较少使用。删除对象时,Qt会自动移除和这个对象相关的所有连接
disconnect(lcd, SIGNAL(overflow()), this, SLOT(handleMathError()));
信号连接到槽或者另一个信号时,需保证它们的参数具有相同的顺序和相同的类型。
connect(ftp, SIGNAL(raw(int, const QString &)), this, SIGNAL(proc(int, const QString &)));
例外情况:当信号参数比槽参数多时,多余的参数会被简单的忽略
connect(ftp, SIGNAL(raw(int, const QString &)), this, SIGNAL(proc(int)));
若信号和槽的名字中包含了参数名,若参数类型不匹配或信号(槽)不存在。Qt会警告。
信号和槽是在QObject中实现的,不局限于图形用户界面编程。可以用于QObject的子类中。
Qt元对象系统
对c++进行了扩展,并创建了独立的软件组件。组件可以绑定在一起,但任何一个组件对于它所要连接的组件的情况事先都一无所知。
元系统两项关键技术:信号-槽 以及 内省(introspection)。内省对于实现信号和槽是必须的,同时允许开发人员在运行时获取关于QObject子类的元信息(meta-information),包含一个含有对象的类名以及它所支持的信号和槽的列表。
C++标准没有对Qt元对象系统所需要的动态元信息提供支持。Qt通过独立的moc工具解决了此问题。moc解析Q_OBJECT类的定义并通过c++来提供可使用的信息。 由于moc使用纯c++实现所有功能,故qt元对象系统可在任意c++编译器上工作。
机制工作:
Q_OBJECT宏声明了在每一个QObject子类中必须实现的一些内省函数:metaObject()、tr()、qt_metacall(),以及其他函数
qt的moc工具生成了由Q_OBJECT声明的所有函数和所有信号的实现
像connect()和disconnect()这样的QObject的成员函数使用这些内省函数来完成它们的工作。
others
快捷键:
文章评论