Qt源码初窥

 

今天,在给同学讲东西的时候,谈到了Qt源代码的问题,才发现自己对Qt机制的了解是在太少了,而Qt的魅力也在于它的开源。因此,决定,从今天起,每天坚持进行1小时以上的源码分析,无论如何,不能间断。

看到那无数的工程,从什么地方开始呢?想想看,也就是从自己写的程序的运行机制作为入口点吧,希望可以窥探到一些Qt的架构知识。

所有的Qt GUI程序都是从QApplication开始的,那么我们就从QApplication的构造函数开始吧。

最初的一个基于MainWindowGUI应用程序是这样的:

QApplication a(argc, argv);

MainWindow w;

w.show();

return a.exec();

从头文件#include <QtGui/QApplication>可以看出来,程序时从QtGui工程中开始的,让我们来一看究竟喽。

找到了QApplication的真实路径:

gui/kernel/qapplication.h

这里是头文件:

#include <QtCore/qcoreapplication.h>

#include <QtGui/qwindowdefs.h>

#include <QtCore/qpoint.h>

#include <QtCore/qsize.h>

#include <QtGui/qcursor.h>

可以看出来,该类使用了来自QtCore中的一些程序。QPoint,QSize这些数据结构,以及QCoreApplication(这个会有些什么内容呢,比较好奇)。

这里猜测qwindowdefs.h文件应该是用于存放全局定义的,qcursor.h这个比较明显,就是光标。

后面还有一些比较奇怪的宏定义:

QT_BEGIN_HEADER

QT_BEGIN_NAMESPACE

这两个宏的定义是空的,不知道有什么用,有待以后考究,暂时认为是为了做标识吧。

QT_MODULE(Gui)

这个会是什么意思呢?等待以后研究了……

下面是一些前向声明:

class QSessionManager;

class QDesktopWidget;

class QStyle;

class QEventLoop;

class QIcon;

class QInputContext;

template <typename T> class QList;

class QLocale;

#if defined(Q_WS_QWS)

class QDecoration;

#endif

class QApplication;

class QApplicationPrivate;

模板类的前向声明还是头一次见到:template <typename T> class QList;现在不会用……以后研究,看样子Qt的源码真的非常复杂哦。

看下接下来的部分:

#if defined(qApp)

#undef qApp

#endif

#define qApp (static_cast<QApplication *>(QCoreApplication::instance()))

这里将qApp宏定义为一个QApplication类型的指针。在此猜测,QCoreApplication的设计采用了单例设计模式。

终于看到类定义了:

class Q_GUI_EXPORT QApplication : public QCoreApplication

原来QApplicationQCoreApplication的子类哦,怪不得要做类型转换,但是这样的转换安全吗?有待考证。

Q_OBJECT

这个宏定义了元对象系统的支持,替换了如下代码:

public: /

Q_OBJECT_CHECK /

static const QMetaObject staticMetaObject; /

virtual const QMetaObject *metaObject() const; /

virtual void *qt_metacast(const char *); /

QT_TR_FUNCTIONS /

virtual int qt_metacall(QMetaObject::Call, int, void **); /

private:

/* tmake ignore Q_OBJECT */

对于这些代码的详细分析,以后进行。代码才qobjectdefs.h中。

下面是一些属性的定义,也是利用了元对象系统:

Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection)

Q_PROPERTY(QIcon windowIcon READ windowIcon WRITE setWindowIcon)

Q_PROPERTY(int cursorFlashTime READ cursorFlashTime WRITE setCursorFlashTime)

Q_PROPERTY(int doubleClickInterval READ doubleClickInterval WRITE setDoubleClickInterval)

Q_PROPERTY(int keyboardInputInterval READ keyboardInputInterval WRITE setKeyboardInputInterval)

#ifndef QT_NO_WHEELEVENT

Q_PROPERTY(int wheelScrollLines READ wheelScrollLines WRITE setWheelScrollLines)

#endif

Q_PROPERTY(QSize globalStrut READ globalStrut WRITE setGlobalStrut)

Q_PROPERTY(int startDragTime READ startDragTime WRITE setStartDragTime)

Q_PROPERTY(int startDragDistance READ startDragDistance WRITE setStartDragDistance)

Q_PROPERTY(bool quitOnLastWindowClosed READ quitOnLastWindowClosed WRITE setQuitOnLastWindowClosed)

#ifndef QT_NO_STYLE_STYLESHEET

Q_PROPERTY(QString styleSheet READ styleSheet WRITE setStyleSheet)

详细的分析,以后进行,我们今天得主要目的是探究构造函数是如何运行的。

看到了如下的枚举类型,不知道有何用意,以后详细研究。

public:

enum Type { Tty, GuiClient, GuiServer };

终于 看到构造函数了:

QApplication(int &argc, char **argv, int = QT_VERSION);

QApplication(int &argc, char **argv, bool GUIenabled, int = QT_VERSION);

QApplication(int &argc, char **argv, Type, int = QT_VERSION);

通常情况下,都忽略了还有版本信息这样一个参数,会有什么用呢?……

先不去看下面的类定义了,需要什么再看,要不然,光类定义都搞不定了。

现在深入到构造函数当中看个究竟:

首先是文档内容:

Initializes the window system and constructs an application object with

/a argc command line arguments in /a argv.

/warning The data referred to by /a argc and /a argv must stay valid for

the entire lifetime of the QApplication object. In addition, /a argc must

be greater than zero and /a argv must contain at least one valid character

string.

警告中提到了传递参数的生存期问题,由此可以知道,Qt并不负责保存命令行参数的数据,而是简单的保留了对象的指针。

The global /c qApp pointer refers to this application object. Only one

application object should be created.

看来之前的猜测没有错误,QtQCoreApplication的创建上采用了单例模式。

This application object must be constructed before any /l{QPaintDevice}

{paint devices} (including widgets, pixmaps, bitmaps etc.).

现在只能先注意这个问题,等以后探究其原因。

/note /a argc and /a argv might be changed as Qt removes command line

arguments that it recognizes.

再下面的文档是QtDebug选项

Qt debugging options (not available if Qt was compiled without the QT_DEBUG

flag defined):

/list

/o -nograb, tells Qt that it must never grab the mouse or the

keyboard.

/o -dograb (only under X11), running under a debugger can cause an

implicit -nograb, use -dograb to override.

/o -sync (only under X11), switches to synchronous mode for

debugging.

/endlist

See /l{Debugging Techniques} for a more detailed explanation.

在文档中查找Debugging Techniques会有很详细的解释。

QApplication::QApplication(int &argc, char **argv)

: QCoreApplication(*new QApplicationPrivate(argc, argv, GuiClient))

{ Q_D(QApplication); d->construct(); }

QApplication::QApplication(int &argc, char **argv, int _internal)

: QCoreApplication(*new QApplicationPrivate(argc, argv, GuiClient))

{ Q_D(QApplication); d->construct(); QApplicationPrivate::app_compile_version = _internal;}

终于看到构造函数了,不过时间都已经过去一个多小时……可以好好研究下了。

QApplication::QApplication(int &argc, char **argv)

: QCoreApplication(*new QApplicationPrivate(argc, argv, GuiClient))

{ Q_D(QApplication); d->construct(); }

不能理解的是,这个构造函数能被调用到吗?

QApplication(int &argc, char **argv, int = QT_VERSION);

QApplication(int &argc, char **argv, bool GUIenabled, int = QT_VERSION);

QApplication(int &argc, char **argv, Type, int = QT_VERSION);

声明是上面的样子。去测试一下。

原来Qt还有其他的一些构造函数:

#if defined(Q_INTERNAL_QAPP_SRC) || defined(qdoc)

QApplication(int &argc, char **argv);

QApplication(int &argc, char **argv, bool GUIenabled);

QApplication(int &argc, char **argv, Type);

#if defined(Q_WS_X11)

QApplication(Display* dpy, Qt::HANDLE visual = 0, Qt::HANDLE cmap = 0);

QApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap= 0);

#endif

#endif

经过追踪之后,发现程序的构造顺序是这样的:

QObjectData->QObjectPrivate->QCoreApplicationPrivate->QApplicationPrivate->QObjectPrivate->QObject->QCoreApplication->QApplication

时间差不多了,接下来的明天继续分析,休息了。

 

20091012日星期一 0001

 

 

 

 

 

 

 

 

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐