This is a repost from my previous Qt learning series, based on Qt 4.3.
今天说一下Qt的事件处理(event processing)机制.
我们之前已经用过了, 当一个QPushButton被点击的时候, 它的clicked() signal就会被emit, 这还是一个signal/slot的关系. 那么Qt中的event到底是干嘛的呢?
书上有这么一句话: As a rule, signals are useful when using a widget, whereas events are useful when implementing a widget. 也就是说一般的话, 调用signal就可以了, 如果要自定义控件, 那么还是需要用到event的. Qt的event相当于系统native的事件的抽象. 比如windows的话就是对应于message.
还是根据源码来剖析event和signal的关系. 下图是点击了一个QPushButton之后的call stack:
In previous articles, I was not able to use Qt’s debug package provided by Ubuntu. Now, I will explain how to use them.
Our simple application:
C++
1
2
3
4
5
6
7
// main.cpp
#include <QtCore/QString>
intmain(){
QStrings="1234567";
inti=s.indexOf('3');
returni!=2;
}
Our *.pro file, you should enable the debug build:
1
2
3
4
5
6
# DebugQt.pro
TARGET = DebugQt
TEMPLATE = app
SOURCES += main.cpp
QT -= gui
CONFIG += console debug_and_release
1. Build your debug version of application:
1
2
# qmake-qt4
# make debug
2. Install Qt’s debug package:
1
# sudo apt-get install libqt4-debug
3. Install the Qt source:
1
# sudo apt-get source libqt4-debug
Now you can start debugging your application. Since Qt’s debug symbols are installed in /usr/lib, It does not follow the GDB’s global debug directory described here. We should tell GDB to load these symbols manually:
We set a breakpoint at the beginning of main function to load all shared libraries. Next, we will load symbols for libQtCore.so.4. The symbol will be loaded in the start address of it (0xb7652510):
From the last series of GObject library, we know the approach of OOP using C. Now, I just want to have a comparison of OO implementation in all leading programming languages: C, C++, Java and C#. I will use C++/Qt in this article. Apart from basic features like encapsulation, inheritance, polymorphism, I will demonstrate how to use advanced features including properties, meta info and event-driven programming.
Now, let’s start. Since C++ supports inheritance and polymorphism in language level. They are not the problem. When encounter encapsulation, it does not do well. We CAN declare member variables as private to prohibit their directly access. But the internal implementation is still exposed. When adding/removing private member variables, the class structure is changed. This can cause binary compatible issues. According to the guide of Qt, we define a private class to hold all private member variables, and add the pointer of it to our public class. The size of pointer is constant in all platforms, so this will not break the binary compatibility. Here’s the code:
NOTE: To use Qt’s object mechanism, your class should inherit QObject class and include the Q_OBJECT macro.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// qfakebase.h
#ifndef QFAKEBASE_H
#define QFAKEBASE_H
#include <QtCore/QObject>
#include <QtCore/QString>
namespaceFake{
classQBasePrivate;
classQBase:publicQObject
{
Q_OBJECT
Q_DECLARE_PRIVATE(QBase)
Q_CLASSINFO("Author","gonwan")
Q_CLASSINFO("Version","1.0.0")
Q_PROPERTY(intid READ id WRITE setId)
Q_PROPERTY(QString name READ name WRITE setName)
public:
explicitQBase(QObject*parent=0);
virtual~QBase();
intid();
voidsetId(intid);
QString name();
voidsetName(QString name);
virtualvoidvirtualDump();
voidnonvirtualDump();
/*
* All signals are defined protected, they can be only emit by
* themselves or their subclasses. So we add these two help function
Just note the forward declaration of QBasePrivate private class. It is define in *.c file, and cannot be used by client applications. We defined a d_ptr protected member variable of this type to hold all private data values. Qt library provideds a series of easy-to-use macros to support this scheme to implementation:
#define Q_D(Class) Class##Private * const d = d_func()
#define Q_Q(Class) Class * const q = q_func()
Qt library supports properties and meta info. properties are defined with Q_PROPERTYmacro, while class meta info are defined with Q_CLASSINFO. Both of them can be inherited by derived classes. Last is Qt’s event-driven mechanism: signals/slots. Since they are also based on QObject, we had to define a test class to include all slots:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// mytestclass.h
#ifndef MYTESTCLASS_H
#define MYTESTCLASS_H
#include <QtCore/QObject>
#include <stdio.h>
/*
* Qt's signal/slot mechanism only works with
* QObject-derived classes. So we define a test class here.