魔方网表 让信息化更简单

 找回密码
 注册
查看: 6029|回复: 1

Qt系列教程【2.1】派生对话框类

[复制链接]
admin 发表于 2008-11-21 10:03:00 | 显示全部楼层 |阅读模式
第一个例子是一个用C++实现的查找对话框。我们把这个对话框实现为一个类,这样它就是一个独立的控件,并有自己的信号(signal)和slot函数
类的源代码分别放在finddialog.h和finddialog.cpp中。首先看finddialog.h的代码
  1. 1 #ifndef FINDDIALOG_H
  2. 2 #define FINDDIALOG_H
  3. 3 #include
  4. 4 class QCheckBox;
  5. 5 class QLabel;
  6. 6 class QLineEdit;
  7. 7 class QPushButton;
  8. 8 class FindDialog : public QDialog
  9. 9 {
  10. 10 Q_OBJECT
  11. 11 public:
  12. 12 FindDialog(QWidget *parent = 0);
  13. 13 signals:
  14. 14 void findNext(const QString &str, Qt::CaseSensitivity cs);
  15. 15 void findPrevious(const QString &str, Qt::CaseSensitivity cs);
  16. 16 private slots:
  17. 17 void findClicked();
  18. 18 void enableFindButton(const QString &text);
  19. 19 private:
  20. 20 QLabel *label;
  21. 21 QLineEdit *lineEdit;
  22. 22 QCheckBox *caseCheckBox;
  23. 23 QCheckBox *backwardCheckBox;
  24. 24 QPushButton *findButton;
  25. 25 QPushButton *closeButton;
  26. 26 };

  27. 27 #endif
复制代码
一共27行,第1,2,27行是为了避免头文件被多次包含。
第3行包含QDialog头文件,这个类从QDialog继承,QDialog从QWidget继承。
第4至7行是用到的Qt中类的前向声明。通过前向声明,编译器就知道这个类已经存在,而不用写出包含的头文件。这个问题稍后还要讲。
第8至26行是类FindDialog的定义。
第10行,Q_OBJECT是一个宏定义,如果类里面用到了signal或者slots,就要声明这个宏。
第12行, FindDialog(QWidget *parent = 0);构造函数是Qt控件类的标准格式,默认的父参数为NULL,说明没有父控件。
第13行,signals声明了这个对话框发出的两个信号,如果选择向前查找,那么对话框就发出findPrevious()信号,否则,发出findNext()信号。关键字signals也是一个宏,在编译之前,C++预处理把它变成标准的c++代码。Qt::CaseSensitivity是一个枚举类型,有Qt::CaseSensitive和Qt::CaseInsensitive两个值。
在类的私有部分,声明了两个slot函数。为了实现这两个函数,需要用到对话框的其他控件的信息,所以保存了一些控件的指针。slots关键字和signals一样,也是一个宏。
对于私有成员变量,我们只是使用了它们的指针,没有对它们进行存取操作,编译器不需要知道它们的详细定义,所以只使用了这些类的前向声明。当然,也可以使用<QCheckBox>,<QLabel>等,但是,使用前向声明会让编译速度更快一些。
下面看一下finddialog.cpp源文件代码:
文件头和构造函数部分
  1. 1 #include
  2. 2 #include "finddialog.h"
  3. 3 FindDialog::FindDialog(QWidget *parent)
  4. 4 : QDialog(parent)
  5. 5 {
  6. 6 label = new QLabel(tr("Find &what:"));
  7. 7 lineEdit = new QLineEdit;
  8. 8 label->setBuddy(lineEdit);
  9. 9 caseCheckBox = new QCheckBox(tr("Match &case"));
  10. 10 backwardCheckBox = new QCheckBox(tr("Search &backward"));
  11. 11 findButton = new QPushButton(tr("&Find"));
  12. 12 findButton->setDefault(true);
  13. 13 findButton->setEnabled(false);
  14. 14 closeButton = new QPushButton(tr("Close"));
  15. 15 connect(lineEdit, SIGNAL(textChanged(const QString &)),
  16. 16 this, SLOT(enableFindButton(const QString &)));
  17. 17 connect(findButton, SIGNAL(clicked()),
  18. 18 this, SLOT(findClicked()));
  19. 19 connect(closeButton, SIGNAL(clicked()),
  20. 20 this, SLOT(close()));
  21. 21 QHBoxLayout *topLeftLayout = new QHBoxLayout;
  22. 22 topLeftLayout->addWidget(label);
  23. 23 topLeftLayout->addWidget(lineEdit);
  24. 24 QVBoxLayout *leftLayout = new QVBoxLayout;
  25. 25 leftLayout->addLayout(topLeftLayout);
  26. 26 leftLayout->addWidget(caseCheckBox);
  27. 27 leftLayout->addWidget(backwardCheckBox);
  28. 28 QVBoxLayout *rightLayout = new QVBoxLayout;
  29. 29 rightLayout->addWidget(findButton);
  30. 30 rightLayout->addWidget(closeButton);
  31. 31 rightLayout->addStretch();
  32. 32 QHBoxLayout *mainLayout = new QHBoxLayout;
  33. 33 mainLayout->addLayout(leftLayout);
  34. 34 mainLayout->addLayout(rightLayout);
  35. 35 setLayout(mainLayout);
  36. 36 setWindowTitle(tr("Find"));
  37. 37 setFixedHeight(sizeHint().height());
  38. 38 }
复制代码
首先包含了<QtGui>, 这个头文件包含了Qt的GUI类的定义。Qt有几个模块,每个有其自己的库。最重要的模块是QtCore, QtGui, QtNetwork, QtOpenGL, QtSql, QtSvg, 及 QtXml.  <QtGui> 头文件包含了QtCore 及QtGui 模块的所有类的定义,因此包含该头文件可以避免单独包含每个类。然而包含这种大的头文件是个不好的风格,特别是对于大型应用程序.
第四行,将parent 参数传递给基类构造函数。接着创建子控件。tr()函数用以语言翻译,它在QObject 及每个包含Q_OBJECT宏的派生类中声明。这是个好习惯。
第8行,设置标签的buddy是行编辑。一个buddy是指当标签的快捷键按下时接收焦点的控件。如当用户按Alt+W (该标签的快捷键), 焦点会落在行编辑上(该标签的buddy).
第十二行,调用setDefault(true)将Find 按钮设为对话框的默认按钮。默认按钮指的是当用户按回车键时对应按下的按钮。
由于 QObject是FindDialog的一个祖先,因此我们在调用connect()时可以省略QObject:: 前缀。
布局管理器能包含控件及其它布局管理器。最外面的layout是主layout,负责对话框的整个区域,其余的是子layout。使用spacer或stretch保证按钮在其layout中的占位注:布局管理器不是控件,它们从QLayout派生,第25,33,34行,子布局管理器添加到父layout中,会自动为其指定父亲。
第37行,设置窗口的固定高度,因为对话框中没有任何控件能够明确占用任何其它垂直的空间。QWidget::sizeHint() 函数返回控件的理想大小。
到这里FindDialog的构造函数就完成了。在创建控件和布局时我们使用了new,一般情况下,我们还需要写析构函数delete这些控件。但是在Qt中这是不需要的,当父控件销毁时,Qt自动删除它所有的子控件和布局。
下面是FindDialog类的两个slot函数:
  1. 39 void FindDialog::findClicked()
  2. 40 {
  3. 41 QString text = lineEdit->text();
  4. 42 Qt::CaseSensitivity cs =
  5. 43 caseCheckBox->isChecked() ? Qt::CaseSensitive
  6. 44 : Qt::CaseInsensitive;
  7. 45 if (backwardCheckBox->isChecked()) {
  8. 46 emit findPrevious(text, cs);
  9. 47 } else {
  10. 48 emit findNext(text, cs);
  11. 49 }
  12. 50 }
  13. 51 void FindDialog::enableFindButton(const QString &text)
  14. 52 {
  15. 53 findButton->setEnabled(!text.isEmpty());
  16. 54 }
复制代码
当用户点击findButton按钮,findClicked()就会调用,根据backwardCheckBox状态,他发出findPrevious()或者findNext()信号。emit也是一个Qt的宏
当用户改变lineEdit中的文本,enableFindButton()slot函数就会调用。如果输入了文本,那么让findButton有效,否则就无效。
最后,创建main.cpp测试FindDialog对话框。
  1. 1 #include
  2. 2 #include "finddialog.h"
  3. 3 int main(int argc, char *argv[])
  4. 4 {
  5. 5 QApplication app(argc, argv);
  6. 6 FindDialog *dialog = new FindDialog;
  7. 7 dialog->show();
  8. 8 return app.exec();
  9. 9 }
复制代码
运行qmake编译程序。由于在FindDialog中包含了Q_OBJECT宏,由qmake生成的makefile会包含特殊的规则运行moc(Qt的原对象编译器)。
为了确保moc正确工作,类定义必须放在头文件而不能放在实现文件中。由moc生成的代码中包含这个头文件,并加入它自己实现的C++代码。
使用了Q_OBJECT宏的类必须运行moc。如果使用qmake,那么makefile里自动包含相关的规则。如果忘记了运行moc,就会发生连接错误,报函数声明了却没实现。不同的编译器给出的提示信息不同,有的会非常晦涩。GCC给出的错误信息如下:
  1. finddialog.o: In function 'FindDialog::tr(char const*, char const*)':
  2. /usr/lib/qt/src/corelib/global/qglobal.h:1430: undefined reference to
  3. 'FindDialog::staticMetaObject'
复制代码
Visual C++中的输出是这样:
  1. finddialog.obj : error LNK2001: unresolved external symbol
  2. "public:~virtual int __thiscall MyClass::qt_metacall(enum QMetaObject
  3. ::Call,int,void * *)"
复制代码
这时需要重新运行qmake,更新makefile,然后编译程序。
运行程序,如果看到了快捷键,测试ALT+W,ALT+C,ALT+B,ALT+F引发相应的处理程序。使用TAB键在将焦点改变到不同的控件上。默认的TAB键是控件创建的顺序。QWidget::setTabOrder()可以改变这个顺序。
提供合适的tab顺序和快捷键可以让用户不用鼠标也可以运行程序,通过键盘可以快速控制程序。
marsliao2 发表于 2013-4-9 10:11:59 | 显示全部楼层
顶一个先吧












qq皮肤 www.qqwo.cc/pifu
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|魔方软件 ( 京ICP备08008787号 )

京公网安备 11010702001722号

GMT+8, 2024-3-28 21:27 , Processed in 0.065554 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表