【VC++开源代码栏目提醒】:网学会员鉴于大家对VC++开源代码十分关注,论文会员在此为大家搜集整理了“Qt_Introduction - 编程语言”一文,供大家参考学习
----------------------------------------------QT简介Qt是一个著名的 C库 ——或许并不能说这只是一个 GUI库,因为 Qt十分庞大,并不仅仅是 GUI。
使用 Qt,在一定程序上你获得的是一个 “一站式 ”的服务:不再需要研究 STL,不再需要 C的 ltstringgt,因为 Qt有它自己的QString等等。
或许这样说很偏激,但 Qt确实是一个 “伟大的 C库 ”。
我们所使用的 Qt,确切地说也就是它的 GUI编程部分。
C的 GUI编程同 Java不同: GUI并不是 C标准的一部分。
所以,如果使用 Java,那么你最好的选择就是 AWT/Swing,或者也可以使 SWT/JFace,但是, C的 GUI编程给了你更多的选择: wxWidget gtk以及 Qt。
这几个库我都有接触,但是接触都不是很多,只能靠一些资料和自己的一点粗浅的认识说一下它们之间的区别 PS: 更详尽的比较在前面的文章中有 。
首先说 wxWidget,这是一个标准的 C库,和 Qt一样庞大。
它的语法看上去和 MFC类似,有大量的宏。
据说,一个 MFC程序员可以很容易的转换到 wxWidget上面来。
wxWidget有一个很大的优点,就是它的界面都是原生风格的。
这是其他的库所不能做到的。
wxWidget的运行效率很高,据说在 Windows平台上比起微软自家的 MFC也不相上下。
gtk其实是一个 C库,不过由于 C和 C之间的关系,这点并没有很大的关系。
但是, gtk是一个使用 C语言很优雅的实现了面向对象程序设计的范例。
不过,这也同样带来了一个问题 ——它的里面带有大量的类型转换的宏来模拟多态,并且它的函数名 “又臭又长 不过这点我倒是觉得无所谓,因为它的函数名虽然很长,但是同样很清晰 ”,使用下划线分割单词,看上去和 Linux如出一辙。
由于它是 C语言实现,因此它的运行效率当然不在话下。
gtk并不是模拟的原生界面,而有它自己的风格,所以有时候就会和操作系统的界面显得格格不入。
再来看 Qt,和 wxWidget一样,它也是一个标准的 C库。
但是它的语法很类似于 Java的 Swing,十分清晰,而且 SIGNAL/SLOT机制使得程序看起来很明白 ——这也是我首先选择 Qt的一个很重要的方面,因为我是学 Java出身的 : 。
不过,所谓 “成也萧何,败也萧何 ”,这种机制虽然很清楚,但是它所带来的后果是你需要使用 Qt的qmake对程序进行预处理,才能够再使用 make或者 nmake进行编译。
并且它的界面也不是原生风格的,尽管 Qt使用 style机制十分巧妙的模拟了本地界面。
另外值得一提的是, Qt不仅仅运行在桌面环境中, Qt已经被Nokia收购,它现在已经会成为 Symbian系列的主要界面技术 ——Qt是能够运行于嵌入式平台的。
以往人们对 Qt的授权多有诟病。
因为 Qt的商业版本价格不菲,
开源版本使用的是 GPL协议。
但是现在 Qt的
开源协议已经变成 LGPL。
这意味着,你可以将 Qt作为一个库连接到一个闭源软件里面。
可以说,现在的 Qt协议的争议已经不存在了 ——因为 wxWidgets或者 gtk同样使用的是类似的协议发布的。
--------------------------------------------------QT源码解析 一 QT创建窗口程序、消息循环和 WinMain函数使用 QT也有一段时间了,有的时候需要跟踪
代码到 QT的源码中去查找问题。
在这里我将记录一下我跟踪 QT源码学习到的一些知识。
我的开发环境是
VC6.0QT4.3.3。
QT已经不为
VC6.0提供 addin了,所以有的时候我也会使用 EclipseCDT来编写
代码,因为有了 QT for Eclipse的 plugin写
代码会方便一些。
我们在学习 QT的时候,接触的第一个程序就是下面的 helloworld程序:include ltQApplicationgtinclude ltQPushButtongtint mainint argc char argv QApplication appargc argv QPushButton helloquotHello worldquot hello.resize100 30 hello.show return app.execinclude ltQApplicationgtinclude ltQPushButtongtint mainint argc char argv QApplication appargc argv QPushButton helloquotHello worldquot hello.resize100 30 1 hello.show return app.exec这个程序的作用很多手册和文档都已经讲了,讲的也都很细致,非常不错。
但是喜欢钻研,深入的童鞋也许开始注意了 int mainint argc char argv,这个 main函数是标准的main函数,而 windows应用程序的入口是 winmain函数,而 main函数是命令行程序的入口。
win下窗口程序都有RegisterClass,和消息循环 QT是如何 RegisterClass和创建消息循环的?下面我们将来一起学习一下 QT的源码来解释一下这个 main函数和整个窗口程序的创建过程:设置好路径后,我们先 F10一下,看看这个程序到底是从哪里开始运行的。
程序跳到了 winmainqtmain_win.cpp文件的 WinMain函数中,再看这个文件上面的宏定义: define mainqMain继续看:在 WinMain函数中调用了我们自己定义的 main函数: int result mainargc argv.data哇塞,原来如此啊。
原来我们写的 main函数是假的。
哈哈。
再来看一下 QT是如何创建窗体和消息循环的首先我们来到 QApplication的构造函数:QApplication::QApplicationint ampargc char argv int _internal : QCoreApplicationnew QApplicationPrivateargc argv GuiClient Q_DQApplication d-gtconstruct QApplicationPrivate::app_compile_version _internal很明显,首先调用的是 QApplicationPrivate的构造函数。
大家注意第三个参数: QApplication::Typetype这事 Type类型的定义: enum Type Tty GuiClient GuiServer 下面是
代码注释中对 Type类型的解释: enum QApplication::Type value Tty a console application value GuiClient a GUI client application value GuiServer a GUI server application for Qt for Embedded Linux当程序运行到 hello.show的时候调用了 QWidgetPrivate::create_sys函数。
在这里我们看到调用了类似 RegisterClass的函数: QString windowClassName qt_reg_winclassq这里的 q是指向 QWidget的指针 我们先忽略掉这里 。
以及包括后面的 CreateWindow, ShowWindow等等我们熟悉的 WindowsAPI函数const QString qt_reg_winclassQWidget w 函数的原型是在 qapplication_win.cpp中定义的。
我们转到qt_reg_winclass函数的实现中。
我们就看到了 windows的 API函数 RegisterClass和窗口消息处理函数:wc.lpfnWndProc WNDPROCQtWndProc我们看一下 QtWndProc的实现,原来窗口消息都是在这里进行处理的啊!至于最后一句 app.exec 调用了 QCoreApplication的 Exec函数,在这个函数中我们看到了下面创建消息循环的
代码 QEventLoop eventLoop self-gtd_func-gtin_exec true int returnCode eventLoop.exec在 QCoreApplication.cpp中的注释是这样解释的: The application will enter the event loop when exec is called. exit will not return 2 until the event loop exits e.g. when quit is called. 到这里, main和 WinMain函数到底是怎么回事,以及 QT是怎么创建窗口和消息循环的,我们已经非常清楚了。
---------------------------------------QT源码解析 二)深入剖析 QT元对象系统和信号槽机制QT的信号和槽机制是用来在对象间通讯的方法,当一个特定事件发生的时候, signal会被 emit 出来, slot调用是用来响应相应的 signal 的。
简单点说就是如何在一个类的一个函数中触发另一个类的另一个函数调用 而且还要把相关的参数传递过去 .好像这和回调函数也有点关系 但是消息机制可比回调函数有用多了 也复杂多了。
下面的
代码是我写的一个继承 QLabel的类,是 QLabel可以响应鼠标单击的消息。
view plaincopy to clipboardprintinclude ltQLabelgtinclude ltQWidgetgtinclude ltQMessageBoxgtinclude ltQApplicationgtclass ClickedLabel : public QLabel Q_OBJECTsignals: void ClickedClickedLabel clickedpublic: ClickedLabelconst QString amptextQWidget parent0: QLabeltextparent ClickedLabel protected: void mouseReleaseEvent QMouseEvent emit Clickedthispublic slots: void OnCLicked ClickedLabel QMessageBox::informationtopLevelWidgetquotMessage fromQtquot quotLabel Clickedquot include quotmain.mocquotint mainint argcchar argv QApplication appargcargv ClickedLabel labelquotlth2gttestlt/h2gtquot QObject::connect amplabel SIGNAL ClickedClickedLabel amplabel SLOTOnCLickedClickedLabel label.show return app.execinclude ltQLabelgtinclude ltQWidgetgtinclude ltQMessageBoxgtinclude ltQApplicationgtclass ClickedLabel : public QLabel Q_OBJECTsignals: void ClickedClickedLabel clickedpublic: ClickedLabelconst QString amptextQWidget parent0: QLabeltextparent ClickedLabel protected: void mouseReleaseEvent QMouseEvent emit Clickedthispublic slots: void OnCLicked ClickedLabel QMessageBox::informationtopLevelWidgetquotMessagefrom Qtquot quotLabel Clickedquot 3include quotmain.mocquotint mainint argcchar argv QApplication appargcargv ClickedLabel labelquotlth2gttestlt/h2gtquot QObject::connect amplabel SIGNAL ClickedClickedLabel amplabel SLOTOnCLickedClickedLabel label.show return app.exec这段
代码很简单,讲述了 QT的 singal和 slot的使用。
下面我们就深入 QT的源码内部,来看一看 QT是如何实现singal和 slots的。
include “main.moc” 的意思就是使编译器找到 moc对 Q_OBJECT处理后的标准 C文件。
编译的时候我们需要首先在该目录中使用 qmake -project 生成一个 .pro 文件,该文件含有工程细节,然后使用 qmake 产生Makefile,最后 nmake 就可以产生可执行文件了。
我们看看在 nmake之后除了生成目标
代码和可执行文件之外,还有一个 main.moc文件,这个文件是 moc产生的一个中间文件。
现在我们要看一下 Q_OBJECT宏到底是什么?他与 main.moc有什么关联呢?相信我介绍完了 Q_OBJECT宏之后,再看 main.moc就能明白其所有函数的含义了。
我们先到 objectdefs.h 文件中看一下 Q_OBJECT宏的定义:define Q_OBJECT public: Q_OBJECT_CHECK static const QMetaObject staticMetaObject virtual const QMetaObject metaObject const virtual void qt_metacastconst char QT_TR_FUNCTIONS virtual int qt_metacallQMetaObject::Call int void private:1首先调用了 Q_OBJECT_CHECK (插入了一个 qt_check_for_QOBJECT_macro 的 template function)2 然后是全局常量 QMetaObject 对象,因此可以用 QClassname::staticMetaObject 直接访问,另外提供了两个接口函数 metaObject 用于不同的 class 返回自己的 staticMetaObject、 qt_metacast 用于转换,我们在 moc 产生的文件里面可以找到这两个接口的实现:const QMetaObject ClickedLabel::metaObject const return ampstaticMetaObjectvoid ClickedLabel::qt_metacastconst char _clname if _clname return 0 4 if strcmp_clname qt_meta_stringdata_ClickedLabel return static_castltvoidgtconst_castlt ClickedLabelgtthis return QLabel::qt_metacast_clname3 宏 QT_TR_FUNCTIONS是和 i18n相关的,我们暂时不用去管它。
define QT_TR_FUNCTIONS static inline QString trconst char s const char c 0 return staticMetaObject.trs c 4 最后是接口函数 qt_metacall,他的作用是查表,调用函数int ClickedLabel::qt_metacallQMetaObject::Call _c int _id void _a _id QLabel::qt_metacall_c _id _a if _id lt 0 return _id if _c QMetaObject::InvokeMetaMethod switch _id case 0: Clickedreinterpret_castlt ClickedLabelgt_a1 break case 1: OnCLickedreinterpret_castlt ClickedLabelgt_a1 break _id - 2 return _id我们来仔细看看 QMetaObject,这就是 meta-object的数据结构定义struct Q_CORE_EXPORT QMetaObject const char className const const QMetaObject superClass const QObject castQObject obj const // ... struct // private data 5 const QMetaObject superdata const char stringdata const uint data const void extradata d 下面看看我们生成的具体的
代码:static const uint qt_meta_data_ClickedLabel // content: 1 // revision 0 // classname 0 0 // classinfo 2 10 // methods 0 0 // properties 0 0 // enums/sets // signals: signature parameters type tag flags 22 14 13 13 0x05 // slots: signature parameters type tag flags 45 13 13 13 0x0a 0 // eodstatic const char qt_meta_stringdata_ClickedLabel quotClickedLabel00clicked0ClickedClickedLabel0quot quotOnCLickedClickedLabel0quotconst QMetaObject ClickedLabel::staticMetaObject ampQLabel::staticMetaObject qt_meta_stringdata_ClickedLabel 6 qt_meta_data_ClickedLabel 0 这就是 meta-object的初始化
代码, meta-object包含所有继承 QObject类的元对象信息。
包括 class namesuperclass name properties signals and slots等等。
ClickedLabel的 staticMetaObject初始化用到了 QLabel::staticMetaObject,qt_meta_stringdata_ClickedLabel是元数据的签名qt_meta_data_ClickedLabel是元数据的索引数组指针。
qt_meta_data_ClickedLabel中这些莫名其妙的数字是如何变成 QMetaObject的呢?在 qmetaobject.cpp中我们找到了 QMetaObjectPrivate的定义:struct QMetaObjectPrivate int revision int className int classInfoCount classInfoData int methodCount methodData int propertyCount propertyData int enumeratorCount enumeratorData很明显,利用 qt_meta_data_ClickedLabel中存储的索引和 qt_meta_stringdata_ClickedLabel中存储的值,我们很容易将 QMetaObject构建起来。
这中间的转换是通过static inline const QMetaObjectPrivate privconst uint data return reinterpret_castltconst QMetaObjectPrivategtdata 这个函数来完成的。
下面我们着重看看几个与 signal/slot 相关的
代码qobject.cpp 文件中关于 QObject::connect 函数的
代码,bool QObject::connectconst QObject sender const char signal const QObject receiver const char method Qt::ConnectionType type const void cbdata sender signal receiver method amptype if QInternal::activateCallbacksQInternal::ConnectCallback void cbdata return true 7 ifndef QT_NO_DEBUG bool warnCompat trueendif if type Qt::AutoCompatConnection type Qt::AutoConnectionifndef QT_NO_DEBUG warnCompat falseendif //判断是否是 NULL if sender 0 receiver 0 signal 0 method 0 qWarningquotQObject::connect: Cannot connect s::s to s::squot sender sender-gtmetaObject-gtclassName : quotnullquot signal ampamp signal signal1 : quotnullquot receiver receiver-gtmetaObject-gtclassName : quotnullquot method ampamp method method1 : quotnullquot return false QByteArray tmp_signal_name if check_signal_macrosender signal quotconnectquot quotbindquot return false const QMetaObject smeta sender-gtmetaObject signal //skip code int signal_index smeta-gtindexOfSignalsignal if signal_index lt 0 // check for normalized signatures tmp_signal_name QMetaObject::normalizedSignaturesignal.prependsignal -1 signal tmp_signal_name.constData 1 signal_index smeta-gtindexOfSignalsignal if signal_index lt 0 err_method_notfoundQSIGNAL_CODE sender signal quotconnectquot 8 err_info_about_objectsquotconnectquot sender receiver return false QByteArray tmp_method_nameint membcode method0 - 0if check_method_codemembcode receiver method quotconnectquot return falsemethod // skip codeconst QMetaObject rmeta receiver-gtmetaObjectint method_index -1switch membcode case QSLOT_CODE: method_index rmeta-gtindexOfSlotmethod breakcase QSIGNAL_CODE: method_index rmeta-gtindexOfSignalmethod breakif method_index lt 0 // check for normalized methods tmp_method_name QMetaObject::normalizedSignaturemethod method tmp_method_name.constData switch membcode case QSLOT_CODE: method_index rmeta-gtindexOfSlotmethod break case QSIGNAL_CODE: method_index rmeta-gtindexOfSignalmethod break 9 if method_index lt 0 err_method_notfoundmembcode receiver method quotconnectquot err_info_about_objectsquotconnectquot sender receiver return false if QMetaObject::checkConnectArgssignal method qWarningquotQObject::c.
上一篇:
论文文库
下一篇:
关于大学英语教学