在我的博文《在VS2008中使用Qt编程》中,介绍了在VS2008中搭建QT开发环境,并举了一个简单的例子。此篇将介绍信号与槽的使用。
信号与槽的使用,需要用到moc(即meta object compiler)。
这是因为:当要在GUI中用到信号与槽,就需在.h文件中的类里写入Q_OBJECT宏。而任何含有Q_Object的类都必须使用Qt的moc工具生成对应的cpp文件,然后在项目里面包含这个cpp,编译才能成功,否则会出错链接错误,如下。
总结:
1) Qt中的元对象系统是用来处理对象间通讯的信号/槽机制、运行时的类型信息和动态属性系统。
2) moc读取C++源文件(应该是.h头文件吧)。如果它发现其中包含一个或多个类的声明中含有Q_OBJECT宏,它就会给含有Q_OBJECT宏的类生成另一个含有元对象代码的C++源文件。这个生成的源文件可以被类的源文件包含(#include)到或者和这个类的实现一起编译和连接。
下面开始编程:
A 编写 main.cpp
- #include "stdafx.h"
- #include <QtGui/QApplication>
- #include "hello.h"
- int _tmain(int argc, _TCHAR* argv[])
- {
- QApplication app(argc,argv);
- Widget w;
- w.show();
- return app.exec();
- }
B 编写 hello.h
- #ifndef WIDGET_H
- #define WIDGET_H
- #include <QWidget>
- #include <stdio.h>
- namespace Ui {
- //class Widget; //1 把Widget换成Form (共3处)
- class Form;
- }
- class Widget : public QWidget {
- Q_OBJECT
- public:
- Widget(QWidget *parent = 0);
- ~Widget();
- protected:
- void changeEvent(QEvent *e);
- private:
- //Ui::Widget *ui; //2 把Widget换成Form (共3处)
- Ui::Form *ui;
- public slots:
- void on_pushButton_clicked(void);
- };
- #endif // WIDGET_H
C 编写 hello.cpp
- #include "stdafx.h"
- #include "hello.h"
- #include "ui_hello.h"
- //#include "moc_hello.cpp" //不是头文件,不可以加此句
- Widget::Widget(QWidget *parent) :
- QWidget(parent),
- //ui(new Ui::Widget) //3 把Widget换成Form (共3处)
- ui(new Ui::Form)
- {
- ui->setupUi(this);
- }
- Widget::~Widget()
- {
- delete ui;
- }
- void Widget::changeEvent(QEvent *e)
- {
- QWidget::changeEvent(e);
- switch (e->type()) {
- case QEvent::LanguageChange:
- ui->retranslateUi(this);
- break;
- default:
- break;
- }
- }
- void Widget::on_pushButton_clicked(void)
- {
- ui->label->setText("liangbing8612.blog.51cto.com");
- printf("liangbing8612.blog.51cto.com");
- }
D 制作.ui文件,并生成ui_hello.h
打开designer,拖入一个pushButton,一个label。保存为hello.ui。然后生成ui_hello.h,并添加到项目的源文件中。
编译运行,则出现如下错误:
错误 1 error LNK2001: 无法解析的外部符号 "public: virtual struct QMetaObject const * __thiscall Widget::metaObject(void)const " (?metaObject@Widget@@UBEPBUQMetaObject@@XZ)
错误 2 error LNK2001: 无法解析的外部符号 "public: virtual void * __thiscall Widget::qt_metacast(char const *)" (?qt_metacast@Widget@@UAEPAXPBD@Z)
错误 3 error LNK2001: 无法解析的外部符号 "public: virtual int __thiscall Widget::qt_metacall(enum QMetaObject::Call,int,void * *)" (?qt_metacall@Widget@@UAEHW4Call@QMetaObject@@HPAPAX@Z)
错误 4 fatal error LNK1120: 3 个无法解析的外部命令
这是因为在源文件中没有添加上moc_hello.cpp文件。
解决方法:右击hello.h,选择“自定义生成步骤”,“常规”
命令行:moc.exe hello.h -o moc_hello.cpp
输出:moc_hello.cpp
附加依赖项:moc.exe hello.h
确定,然后,右击hello.h,选择 “编译”,则在文件夹中生成moc_hello.cpp,再将其添加到源文件中。
然后,运行程序,出现错误:
错误 fatal error C1010: 在查找预编译头时遇到意外的文件结尾。是否忘记了向源中添加“#include "stdafx.h"”?
则在moc_hello.cpp文件的开头添加上:#include "stdafx.h"。
然后,再运行。仍然出现上面错误。这是因为当运行程序,又重新生成了moc_hello.cpp文件(这个新的文件的开头显然是没有#include "stdafx.h"),覆盖了已经修改过的文件。
解决方法:右击hello.h,选择“自定义生成步骤”,“常规”
清空“命令行” “输出” “附加依赖项” 里对应的内容。这样在运行程序时就不会再生成新的moc_hello.cpp文件了。然后确定。
这样再次运行程序,可以成功运行。运行结果如图。