|
cmake vs qmake- qmake 是为 Qt 量身打造的,使用起来非常方便
- cmake 使用上不如qmake简单直接,但复杂换来的是强大的功能
如何选择? Using CMake to Build Qt Projects 一文中说: - 对简单的Qt工程,采用 qmake
- 对复杂度超过 qmake 处理能力的,采用 cmake
尽管如此,如果简单Qt的工程都不知道怎么用 cmake 构建,复杂的工程,就更不知道如何使用 cmake 了。还是从简单的学起吧 简单的 Qt 程序#include <QtCore/QCoreApplication> #include <QtCore/QDebug> int main(int argc, char** argv) { QCoreApplication app(argc, argv); qDebug()<<"hello qt!"; app.exec(); } 如果不使用构建工具,直接调用编译器来编译的话,只需要类似这样的一条命令: g++ main.cpp -Ie:/Qt/4.7.0/include -o main -Le:/Qt/4.7.0/lib -lQtCore4 指定头文件目录,以及需要链接的库 qmakeqmake 需要一个 .pro 文件: CONFIG += qt QT -= gui SOURCES += main.cpp cmakecmake 需要一个 CMakeLists.txt 文件: PROJECT(example) FIND_PACKAGE(Qt4 REQUIRED) SET(QT_DONT_USE_QTGUI TRUE) INCLUDE(${QT_USE_FILE}) ADD_EXECUTABLE(example main.cpp) TARGET_LINK_LIBRARIES(example ${QT_LIBRARIES}) - FIND_PACKAGE 来启用 Qt4
- 默认使用了core 和 gui,故手动禁用 QTGUI
- 包含一个CMake为Qt提供的配置文件,${QT_USE_FILE}变量是一个文件名
- 添加可执行程序目标
- 链接到 Qt 的库
复杂一点考虑一个常规Qt程序: - main.cpp
- mainwindows.ui
- mainwindows.h
- mainwindows.cpp
如果手动编译的话: - mainwindow.ui 需要使用 uic 预处理
uic mainwindow.ui -o ui_mainwindow.h moc mainwindow.h -o moc_mainwindow.cpp g++ main.cpp mainwindow.cpp moc_mainwindow.cpp -Ie:/Qt/4.7.0/include -o main -Le:/Qt/4.7.0/lib -lQtCore4 -lQtGui4 qmake使用 qmake 的的话,一个简单的 pro 文件 TARGET = example TEMPLATE = app SOURCES += main.cpp mainwindow.cpp HEADERS += mainwindow.h FORMS += mainwindow.ui HEADERS 中的文件是否需要 moc 进行预处理,qmake 运行时会根据其是否含有Q_OBJECT自动判断。 这也是为什么 很多人添加Q_OBJECT宏后不重新运行qmake会出错误的原因。 cmake看看相应的 cmake 的 CMakeLists.txt 文件 PROJECT(example) CMAKE_MINIMUM_REQUIRED(VERSION 2.6) FIND_PACKAGE(Qt4 REQUIRED) INCLUDE(${QT_USE_FILE}) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) QT4_WRAP_CPP(example_MOCS mainwindow.h) QT4_WRAP_UI(example_UIS mainwindow.ui) ADD_EXECUTABLE(example main.cpp mainwindow.cpp ${example_MOCS}) TARGET_LINK_LIBRARIES(example ${QT_LIBRARIES}) - 需要 moc 的文件,用 QT4_WRAP_CPP 处理
- 生成的文件放入变量 example_MOCS 中,最后一块链接到可执行程序
- 需要 uic 的文件,用 QT4_WRAP_UI 处理
Windows因为windows下链接时分为 console 和 windows 两个子系统,所以windows下有些问题需要特殊处理。 用 qmake 时: - 默认是 windows 子系统
- 可以通过 CONFIG += console 使用 console 子系统
用 cmake 是: - 默认是 console 子系统
- 使用 windows 子系统需要
SET(QT_USE_QTMAIN TRUE) ADD_EXECUTABLE(example WIN32 main.cpp mainwindow.cpp ${example_MOCS}) 前者启用 qtmain.lib 库来提供windows下的 WinMain 入口函数。后者链接 windows 子系统 再复杂一点- main.cpp
- mainwindows.ui
- mainwindows.h
- mainwindows.cpp
- main.qrc
- main.rc
前面已经用到了Qt的 moc 和 uic,这次增加了资源系统 需要用 rcc rcc main.qrc -o qrc_main.cpp 同时,使用了windows下的资源文件 .rc (比如给程序添加图标) - MVSC 中使用 rc.exe 对 .rc 文件进行处理
- MinGW 中使用 windres.exe 处理 .rc 文件
qmake TARGET = example TEMPLATE = lib HEADERS = mainwindow.h widget.h SOURCES = main.cpp widget.cpp mainwindow.cpp RESOURCES = main.qrc RC_FILE = main.rc cmakePROJECT(example) CMAKE_MINIMUM_REQUIRED(VERSION 2.6) FIND_PACKAGE(Qt4 REQUIRED) SET(QT_USE_QTMAIN TRUE) INCLUDE(${QT_USE_FILE}) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
if(MINGW) set(CMAKE_RC_COMPILER_INIT windres) ENABLE_LANGUAGE(RC) SET(CMAKE_RC_COMPILE_OBJECT "<CMAKE_RC_COMPILER> <FLAGS> -O coff <DEFINES> -i <SOURCE> -o <OBJECT>") endif(MINGW)
SET(example_SRCS main.cpp mainwindow.cpp widget.cpp res/main.rc) SET(example_MOC_SRCS mainwindow.h widget.h) QT4_WRAP_CPP(example_MOCS ${example_MOC_SRCS}) QT4_ADD_RESOURCES(example_RCC_SRCS main.qrc) SET(example_SRCS ${example_SRCS} ${example_MOCS} ${example_RCC_SRCS})
ADD_EXECUTABLE(example WIN32 main.cpp mainwindow.cpp ${example_SRCS}) TARGET_LINK_LIBRARIES(example ${QT_LIBRARIES}) - 对Qt的资源文件,使用 QT4_ADD_RESOURCES 来调用rcc进行预处理
- 对 Windows 资源文件,直接和源文件一样,添加到列表中即可。只是:
- MinGW 下仅仅这么做还不行,上面的 MinGW 块用来修复这个问题
Debug 与 Releaseqmake使用 qmake 时,可以在 pro 文件内分别为两种模式设置不同的选项。 使用时,可以直接 make release 或 make debug 来编译不同的版本 cmake不同于 qmake,由于 cmake 采用 out-of-source 方式。故: - 建立debug release两目录,分别在其中执行cmake -DCMAKE_BUILD_TYPE=Debug(或Release)
- 需要编译不同版本时进入不同目录执行make
对生成 msvc 工程的情况, CMAKE_BUILD_TYPE 不起作用。生成工程后使用IDE自带的模式选择。
请尊重原创作品和译文。转载请保持文章完整性,并以超链接形式注明原始作者地址http://blog.csdn.net/changsheng230,方便其他朋友提问和指正。 在Qt/Qt Quick宏浅议一文中,我们将介绍Qt中经常使用的几个宏: Q_OBJECT, SIGNAL与SLOT, Q_SIGNALS 与 Q_SLOTS, Q_EMIT ,Q_INVOKABLE, Q_PROPERTY。相比其他宏,Q_INVOKABLE 显得更加神秘,但Q_INVOKABLE的理解与使用变得越来越重要。本文将围绕Q_INVOKABLE以及相对应的invokeMethod展开讨论。 Q_INVOKABLE#define Q_INVOKABLE 重新回顾一下Q_INVOKABLE的定义,它在$QTDIR/src/corelib/kernel/qobjectdefs.h 中,简单被define,目的在于让moc识别。 使用Q_INVOKABLE来修饰成员函数,目的在于被修饰的成员函数能够被元对象系统所唤起。 QMetaObject::invokeMethod静态方法QMetaObject::invokeMethod() 的定义如下: - bool QMetaObject::invokeMethod ( QObject * obj, const char * member,Qt::ConnectionType type,
- QGenericReturnArgument ret, QGenericArgument val0 = QGenericArgument( 0 ), …)
invokeMethod的用法为,尝试调用对象obj的方法member(注意member可以为信号或者是槽),如何member可以被调用,则返回真,否则返回假。QMetaObject::invokeMethod可以是异步调用,也可以是同步调用。这取决与它的连接方式Qt::ConnectionType type。如果type为Qt::DirectConnection,则为同步调用,若为Qt::QueuedConnection,则为异步调用。例如: - QMetaObject::invokeMethod(object, "methodName",
- Qt::QueuedConnection,
- Q_ARG(type1, arg1),
- Q_ARG(type2, arg2));
上述调用为异步调用。请注意,因为上面所示的参数需要被在构建事件时进行硬拷贝,参数的自定义型别所对应的类需要提供一个共有的构造函数、析构函数以及拷贝构造函数。而且必须使用注册Qt型别系统所提供的qRegisterMetaType() 方法来注册这一自定义型别。 Q_INVOKABLE与QMetaObject::invokeMethod均由元对象系统唤起。这一机制在Qt C++/QML混合编程,跨线程编程,Qt Service Framework 以及 Qt/ HTML5混合编程以及里广泛使用。 Qt C++/QML混合编程QML中调用C++方法借助了Qt元对象系统。考虑在QML中使用Qt C++定义的方法,如下代码所示: - import Qt 4.7
- import Shapes 5.0
- Item {
- width: 300; height: 200
- Ellipse {
- x: 50; y: 35; width: 200; height: 100
- color: "blue"
- MouseArea {
- anchors.fill: parent
-
- onClicked: parent.color = parent.randomColor()
- }
- }
- }
为了让上述QML代码成功的调用下面这段代码定义的randomColor()函数,最为关键的一点见randomColor方法用Q_INVOKABLE 修饰。 - #include <QDeclarativeItem >
- class EllipseItem : public QDeclarativeItem
- {
- Q_OBJECT
- public:
- Q_INVOKABLE QColor randomColor() const;
- …
- }
更多细节,请参看我的另一篇博文:QML与C++混合编程使用 在跨线程编程中的使用我们如何调用驻足在其他线程里的QObject方法呢?Qt提供了一种非常友好而且干净的解决方案:向事件队列post一个事件,事件的处理将以调用我们所感兴趣的方法为主(当然这需要线程有一个正在运行的事件循环)。而触发机制的实现是由moc提供的内省方法实现的。因此,只有信号、槽以及被标记成Q_INVOKABLE的方法才能够被其它线程所触发调用。如果你不想通过跨线程的信号、槽这一方法来实现调用驻足在其他线程里的QObject方法。另一选择就是将方法声明为Q_INVOKABLE,并且在另一线程中用invokeMethod唤起。 更多细节,译文事件循环与线程 Qt Service FrameworkQt服务框架是Qt Mobility 1.0.2版本推出的,一个服务(service)是一个独立的组件提供给客户端(client)定义好的操作。客户端可以通过服务的名称,版本号和服务的对象提供的接口来查找服务。 查找到服务后,框架启动服务并返回一个指针。 服务通过插件(plug-ins)来实现。为了避免客户端依赖某个具体的库,服务必须继承自QObject。这样QMetaObject 系统可以用来提供动态发现和唤醒服务的能力。要使QmetaObject机制充分的工作,服务必须满足,其所有的方法都是通过 signal,slot,property 或invokable method和Q_INVOKEBLE来实现 其中,最常见的与servicer交互的方法如下: - QServiceManager manager;QObject *storage ;
- storage = manager.loadInterface("com.nokia.qt.examples.FileStorage"); if (storage) QMetaObject::invokeMethod(storage, "deleteFile", Q_ARG(QString, "/tmp/readme.txt"));
上面的代码通过service的元对象提供的invokeMethod方法,调用文件存储对象的deleteFile() 方法。客户端不需要知道对象的类型,因此也没有链接到具体的service库。 当然在服务端的deleteFile方法,一定要被标记为Q_INVOKEBLE,才能够被元对象系统识别 Qt服务框架的一个亮点是它支持跨进程通信,服务可以接受远程进程。在服务管理器上注册后 进程通过signal,slot,invokable method和property来通信,就像本地对象一样。服务可以设定为在客户端间共享,或针对一个客户端。 请注意,在Qt服务框架推出之前,信号、槽以及invokable method仅支持跨线程。 下图是跨进成的服务/客户段通信示意图(图片来自诺基亚论坛)。这里我们可以清楚的看到,invokable method和Q_INVOKEBLE 是跨进城、跨线程对象之间通信的重要利器。
有关Qt Service Framework的更多讨论和用例,请参见Qt Service Framework文档
Qt GPL, LGPL & Commercial License
请尊重原创作品和译文。转载请保持文章完整性,并以超链接形式注明原始作者地址http://blog.csdn.net/changsheng230,方便其他朋友提问和指正。 刚开始接触Qt的朋友可能对Qt在使用当中需要声明的各色各样的宏感到神秘而又陌生,本文将介绍Qt中经常使用的几个宏: Q_OBJECT, SIGNAL与SLOT, Q_SIGNALS 与 Q_SLOTS, Q_EMIT ,Q_INVOKABLE, Q_PROPERTY: 宏的头文件出处: $QTDIR/src/corelib/kernel/qobjectdefs.h Q_OBJECT#define Q_OBJECT / public: / Q_OBJECT_CHECK / static const QMetaObject staticMetaObject; / Q_OBJECT_GETSTATICMETAOBJECT / virtual const QMetaObject *metaObject() const; / virtual void *qt_metacast(const char *); / QT_TR_FUNCTIONS / virtual int qt_metacall(QMetaObject::Call, int, void **); / 宏Q_OBJECT是Qt所有宏中最为重要的一个,Q_OBJECT是使用信号槽机制以及其他所有元对象系统提供的服务(内省、invokeMethod,元对象property系统等等)的前提条件。有关Q_OBJECT的讨论请参考Qt源码分析之QObject。 SIGNAL与SLOT这两个宏是调用connect方法时用到: - QObject::connect(myButton, SIGNAL(clicked()),
- label, SLOT(showText()));
那么宏SIGNAL和SLOT为我们做了那些事情呢,看一下源代码: - $QTDIR/src/corelib/kernel/qobjectdefs.h
- # define SLOT(a) qFlagLocation("1"#a QLOCATION)
- # define SIGNAL(a) qFlagLocation("2"#a QLOCATION)
- $QTDIR/src/corelib/kernel/qobject.cpp
- const char *qFlagLocation(const char *method)
- {
- static int idx = 0;
- flagged_locations[idx] = method;
- idx = (idx+1) % flagged_locations_count;
- return method;
- }
原来它会基于把我们定义的信号、槽的名称返回一个字符串,比如SIGNAL(clicked()) 返回字符串 “2clicked()”, SLOT(showText())返回字符串“1showText()”
- Q_SIGNALS 与 Q_SLOTS
- # define slots
- # define signals protected
- # define Q_SLOTS
- # define Q_SIGNALS protected
Q_SIGNALS 与 Q_SLOTS是Qt 4.1引入的,它们用来替换关键字signals和slots,原因是更好的与第三方信号槽机制兼容,比如boost库。尽管Q_SIGNALS 与 Q_SLOTS看起来没有做什么。其实不然,QT的元对象编译器moc会识别声明在头文件中的宏Q_SIGNALS,Q_SLOTS。并做为依据,生成元对象模型数据,详见文中最后所示代码实例 Q_EMIT#define Q_EMIT #define emit Q_EMIT用来替换关键字emit,原因也是更好的与第三方信号槽机制兼容,比如boost库。 这里要注意,我们看到Q_EMIT看起来同样的简单, 但它们是有区别的!表面的区别在于Q_SIGNALS 与 Q_SLOTS用在头文件中,而Q_EMIT用在代码视线中。 本质的区别的在于,Q_SIGNALS 与 Q_SLOTS将被moc识别,是必须使用的。而Q_EMIT或者emit是可有可无的。它不会被moc识别,它存在的唯一理由是:增加代码的可读性。 也就是说如下代码都能正常工作,但2)的写法也许会惹怒你的同事。 - void method()
- {
- 1) emit signalA();
- 2) signalA();
- }
Q_INVOKABLE#define Q_INVOKABLE 使用Q_INVOKABLE来修饰成员函数,目的在于被修饰的成员函数能够被元对象系统所唤起。这一机制在Qt C++/QML混合编程,Qt service framework, 以及Qt/ HTML5混合编程里广泛使用。我会随后另撰写一文做深入探讨。 Q_PROPERTY #define Q_PROPERTY(text) 使用Q_PROPERTY用以声明属性,属性类似于成员变量,但它能够被元对象系统所访问。QML的属性便是利用该机制得以实现的。 Q_PROPERTY的用法如下: Q_PROPERTY(QString title READ title WRITE setTitle USER true)
接下来,让我们结合代码来看一下上述宏的使用以及元对象编译器是如何利用这些宏的。 - #include <QDeclarativeItem >
- class EllipseItem : public QDeclarativeItem
- {
- Q_OBJECT
- Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
- public:
- EllipseItem(QDeclarativeItem *parent = 0);
- void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
- QWidget *widget = 0);
- const QColor &color() const;
- void setColor(const QColor &newColor);
- Q_INVOKABLE QColor randomColor() const;
- public Q_SLOTS:
- void try1();
- void try2() {}
- Q_SIGNALS:
- void colorChanged();
- void ready();
- private:
- QColor m_color;
- };
以下代码由元对象编译器moc根据上述头文件自动生成: - static const uint qt_meta_data_EllipseItem[] = {
-
- 5,
- 0,
- 0, 0,
- 5, 14,
- 1, 39,
- 0, 0,
- 0, 0,
- 0,
- 2,
-
- 13, 12, 12, 12, 0x05,
- 28, 12, 12, 12, 0x05,
-
- 36, 12, 12, 12, 0x0a,
- 43, 12, 12, 12, 0x0a,
-
- 57, 12, 50, 12, 0x02,
-
- 71, 50, 0x43495103,
-
- 0,
- 0
- };
- static const char qt_meta_stringdata_EllipseItem[] = {
- "EllipseItem/0/0colorChanged()/0ready()/0"
- "try1()/0try2()/0QColor/0randomColor()/0"
- "color/0"
- };
从上面代码实例我们可以看到, QT的元对象编译器moc会识别声明在头文件中的宏Q_SIGNALS,Q_SLOTS, Q_PROPERTY, Q_PROPERTY。并以此做为依据,生成了元对象数据表。在这张元对象数据表中,我们已可以看到,moc根据头文件所声明的宏定义,识别出: - 两个信号:colorChanged(), ready(); (Q_SIGNALS)
- 两个槽: try1(), try2() (Q_SLOTS)
- 五个方法,其中被标记为Q_INVOKABLE的方法randomColor()被记录在元对象字符串数组qt_meta_stringdata_EllipseItem中。
- 一个属性:color (Q_PROPERTY)
请尊重原创作品和译文。转载请保持文章完整性,并以超链接形式注明原始作者地址http://blog.csdn.net/changsheng230,方便其他朋友提问和指正。 将QML整合到基于QWidget UI程序的方法有很多种,而具体采用哪种方法取决于现有UI代码的特性。 与基于QWidget的UI整合如果你已经有了一个基于QWidget的UI,QML widgets可以使用QDeclarativeView来进行集成。QDeclarativeView是QWidget的一个子类,所以你可以像加载其他QWidget一样把它加载进你的UI。 具体方法是使用QDeclarativeView::setSource()方法加载一个QML文件到视图中,然后将这个视图(即QDeclarativeView)加到你的UI中。 - QDeclarativeView *qmlView = new QDeclarativeView;
- qmlView->setSource(QUrl::fromLocalFile("myqml.qml"));
-
- QWidget *widget = myExistingWidget();
- QVBoxLayout *layout = new QVBoxLayout(widget);
- widget->addWidget(qmlView);
这种方法的缺点在于与QWidget相比,QDelarativeVeiw的初始化过程更慢,而且使用更多的内存。如果创建大量的QDelarativeVeiw对象可能会导致性能的下降。在这种情况下,更好的选择是用QML重写你的widgets,使用main QML widget来加载widget, 从而替代QDelarativeVeiw的滥用。 请注意,QWidgets的UI设计理念与QML并不相同,所以将基于QWidget的应用移植到QML并不总是一个好主意。如果你的UI是由少数几个复杂、静态的元素的组成,使用QWidgets是一个更好的选择。而如果你的UI是由大量简单、动态的元素组成,那么QML则是你的最佳选择。 与基于QGraphicsView的UI整合将QML widgets加入到QGraphicsScene如果你已经有了一个基于Graphics View Framework的UI,你可以直接将QML widgets集成到你的QGraphicsScene中。具体方法是使用QDeclarativeComponent 从QML文件中创建一个QGraphicsObject,并通过使用QGraphicsScene::addItem(), 方法把这个图形对象加到你的scene中,或者将其父化到已经存在与QGraphicsScene的组件中。举例说明: > - QGraphicsScene* scene = myExistingGraphicsScene();
- QDeclarativeEngine *engine = new QDeclarativeEngine;
- QDeclarativeComponent component(engine, QUrl::fromLocalFile("myqml.qml"));
- QGraphicsObject *object =
- qobject_cast(component.create());
- scene->addItem(object);
推荐使用下面的一些QGraphicsView选项来优化QML UIs的性能: 在QML中加载QGraphicsWidget 对象另一个可供选择的方法是将你现有的QGraphicsWidget 对象暴露给QML,并且在QML中构建你的scene。请参见图形布局示例,它展示了如何结合QGraphicsWidget 、QGraphicsLinearLayout 以及QGraphicsGridLayout的使用,将Qt图形布局类暴露给QML。 为了将现有的QGraphicsWidget类暴露给QML,需使用qmlRegisterType()。在QML中使用C++型别的进一步信息,请参见在C++中拓展QML。 (译者注:也看参阅QML与C++混合编程使用) 英文原文出处:integrating QML with existing Qt UI code
本文介绍的是Qt 内省机制,关于内省,新手的原因,我们一块学习,所谓内省是指面向对象语言的一种在运行期间查询对象信息的能力, 比如如果该语具有运行期间检查对象型别的能力,那么我们称它是型别内省(type intropection)的,型别内省可以用来实施多态。 c++的内省比较有限,它仅支持上面所说的型别内省, C++的型别内省是通过运行时类型识别(RTTI)(Run-Time Type Information)中的typeid 以及 dynamic_case关键字来实现的,举例说明: - // rabbit 派生于 Animal, jump为虚函数
-
- if ( rabbit *p = dynamic_case<Animal*>(obj))
- {
- p->jump();
- }
- //我们还可以通过typeid萃取到对象的型别信息,比如对象的名称
- std::cout << typeid(obj).name() << std::endl
Qt拓展了C++的内省机制,(实际上,它并没有采用c++的RTTI),而是提供了更为强大的元对象(meta object)机制,来实现内省。接下来,就让我们看看,Qt是如何扩展c++内省机制的。 要深刻理解Qt的内省机制,首先理解QObject,QObject类是整个Qt对象模型的心脏,Qt对象模型最为核心的功能是提供一种无缝的对象通讯机制,即就是我们所熟知的信号和槽。QObject主要有三大职责: 内存管理、内省(intropection)与事件处理。本文将集中在在内省的讨论。以下代码介绍了QObject类提供的内省方法: - //每个对象可以通过QObject::setObjectName()和QObject::objectName()设置、取得类的实例的名字
- FirstQtApp obj;
- obj.setObjectName("instanceName");
- QString name1 = obj.objectName(); // return instanceName
- //每个对象还可以通过它的元对象className方法得到类的名字
- QString name2 = obj.metaObject()->className(); // return FirtstQtApp
- //每个对象可以通过QObject::inherits方法来查询是否对前对象类派生于量一个类
- bool isherited = obj.inherits("QObject"); // returns true
- isherited = obj.inherits("QWideget"); // returns true
让我们再来一下QObject::inherits方法的底层实现: - inline bool inherits(const char *classname) const
- { return const_cast<QObject *>(this)->qt_metacast(classname) != 0; }
原来,QObject::inherits是通过qt_metacast()这个虚函数实现的, 事实上每个QObject的派生类都必须实现metaObject()以及其他qt_metacall()方法,从而满足自省方法className, inherits等方法的调用(当然还有其他用途)。 而所有有关派生从QObject的子类中的内省方法无须有用户实现,用户只要在类中声明宏Q_OBJECT即可,Qt的元对象编译器(moc)负责实现派生从QObject的子类中的内省方法。 - // defined at ..\Qt\src\corelib\kernel\qobjectdefs.h
- /* tmake ignore Q_OBJECT */
- #define Q_OBJECT \
- public: \
- Q_OBJECT_CHECK \
- static const QMetaObject staticMetaObject; \
- Q_OBJECT_GETSTATICMETAOBJECT \
- virtual const QMetaObject *metaObject() const; \
- virtual void *qt_metacast(const char *); \
- QT_TR_FUNCTIONS \
- virtual int qt_metacall(QMetaObject::Call, int, void **); \
此外,所有的Qt widgets类均继承自QObject, QObject所提供的isWidgetType自省方法可以很方便让QObject子对象查询自己是否是wideget, 而且它会比 qobject_cast<QWidget *>(obj) 或者 obj->inherits快很多。原因qobject_cast()t和inherits()都是借助元对象系统来实现其功能的,isWidgetType()是QObject本身的标志位得以实现。 更多自省方法定义在QMetaObject,以下是QMetaObject声明的源代码: - struct Q_CORE_EXPORT QMetaObject
- {
- const char *className() const;
- const QMetaObject *superClass() const;
- QObject *cast(QObject *obj) const;
-
- ....
- int methodOffset() const;
- int enumeratorOffset() const;
- int propertyOffset() const;
- int classInfoOffset() const;
- int constructorCount() const;
- int methodCount() const;
- int enumeratorCount() const;
- int propertyCount() const;
- int classInfoCount() const;
- int indexOfConstructor(const char *constructor) const;
- int indexOfMethod(const char *method) const;
- int indexOfSignal(const char *signal) const;
- int indexOfSlot(const char *slot) const;
- int indexOfEnumerator(const char *name) const;
- int indexOfProperty(const char *name) const;
- int indexOfClassInfo(const char *name) const;
- ...
- }
上述方法主要是实现对元对象表的访问及其操作,对元对象表(由moc实现)实例如下所示: - // defined at ..\Qt\src\corelib\kernel\qobjectdefs.h
- /* tmake ignore Q_OBJECT */
- #define Q_OBJECT \
- public: \
- Q_OBJECT_CHECK \
- static const QMetaObject staticMetaObject; \
- Q_OBJECT_GETSTATICMETAOBJECT \
- virtual const QMetaObject *metaObject() const; \
- virtual void *qt_metacast(const char *); \
- QT_TR_FUNCTIONS \
- virtual int qt_metacall(QMetaObject::Call, int, void **); \
总结: 1、Qt是通过QObject、QMetaObject类实现其内省机制, 2、QObject暴露给用户的共有自省方法有objectName(), inherits(), isWidgetType()等 3、大多数自省方法是QObject派发给QMetaObject实现 (e.g. QMetaObject::className,),元对象模型编译器moc负责自省方法的实现 4、更多自省方法定义在QMetaObject,而是为了等信号槽通讯、事件派发等机制, 小结:关于解析 Qt 内省机制剖析的内容介绍完了,希望本文对你有所帮助!
本文适合于对Qt Quick有基本了解的读者。首先回答一个比较常会被问到的问题:什么是QML,它与Quick的关系是什么? Qt Quick是Qt User Interface Creation Kit的缩写,而QML是Qt Quick最重要的组成部分,Qt Quick结合了如下技术: 组件集合,其中大部分是关于图形界面的 基于JavaScript陈述性语言:QML (Qt Meta-Object Language的缩写) 用于管理组件并与组件交互的C++ API - QtDeclarative模块 言归正传:通过Qt Creator,我们可以轻松生成一个Qt Quick的应用工程,从而为QML生成应用程序框架。具体操作详见:创建qt quick (qml) 应用程序。 C++与QML的交互是通过注册C++对象给QML环境得以实现的: 在C++实现中,非可视化的型别均为QObject的子类,可视化的类型均为QDeclarativeItem的子类。注意:QDeclarativeItem等同于QML的Item类。 如果用户想要定义自己的型别,做法如下: 在C++中,实现派生于QObject或QDeclarativeItem的子类,它是新定义item的实体对象; 在C++中,将1中实现的新item类型注册给QML; 在QML中,导入含有1中定义的新item的模块; 在QML中,向使用标准的item一样使用新定义的item 现举例说明,我们现尝试使用用Qt C++实现的MyButton对象(如下qml代码),它有自己的属性、方法以及信号的handler。用法如下(它与使用其它标准的QML item一样),所需要做的是 需要导入包含MyButton的对应模块名称及其版本“MyItems 1.0 ”。 - //main.qml
- import Qt 4.7
- import MyItems 1.0
- Item {
- width: 300; height: 200
- MyButton {
- //注意:x, y, width, height是继承自item的属性,无需再自定义的item中实现
- x: 50; y: 50
- width: 200; height: 100
- color: "gray" //自定义属性
- onMySignals: dosth //自定义信号mySignals
- MouseArea {
- anchors.fill: parent
- onClicked: parent.myColor() // 调用C++定义的方法myColor
- }
- }
- }
- //main.qml
- import Qt 4.7
- import MyItems 1.0
- Item {
- width: 300; height: 200
- MyButton {
- //注意:x, y, width, height是继承自item的属性,无需再自定义的item中实现
- x: 50; y: 50
- width: 200; height: 100
- color: "gray" //自定义属性
- onMySignals: dosth //自定义信号mySignals
- MouseArea {
- anchors.fill: parent
- onClicked: parent.myColor() // 调用C++定义的方法myColor
- }
- }
- }
为了能够上述qml代码工作,需要为在Qt C++代码中注册MyButton及其所属的模块,对应的main.cpp代码如下: - #include <QtGui/QApplication>
- #include "qmlapplicationviewer.h"
- int main(int argc, char *argv[])
- {
- QApplication app(argc, argv);
- QmlApplicationViewer viewer;
- // MyButtonItem是与QML中MyButton相对应的C++实现的类名称
- // 1,0是版本信息;MyItems是MyButton所属的模块名称
- qmlRegisterType<MyButtonItem>("MyItems", 1, 0, "MyButton ");
- viewer.setOrientation(QmlApplicationViewer::Auto);
- viewer.setMainQmlFile(QLatin1String("qml/untitled/main.qml"));
- viewer.show();
- return app.exec();
- }
- #include <QtGui/QApplication>
- #include "qmlapplicationviewer.h"
- int main(int argc, char *argv[])
- {
- QApplication app(argc, argv);
- QmlApplicationViewer viewer;
- // MyButtonItem是与QML中MyButton相对应的C++实现的类名称
- // 1,0是版本信息;MyItems是MyButton所属的模块名称
- qmlRegisterType<MyButtonItem>("MyItems", 1, 0, "MyButton ");
- viewer.setOrientation(QmlApplicationViewer::Auto);
- viewer.setMainQmlFile(QLatin1String("qml/untitled/main.qml"));
- viewer.show();
- return app.exec();
- }
上面我们在QML中MyButton对象,有自己的属性、方法以及信号的handler,其实现均来自Qt C++。Qt C++需要作以下工作:首先要定义 QML中MyButton相对应的C++实现MyButtonItem,它必须继承自QDeclarativeItem 为了让MyButton对象能够使用其Color属性,MyButtonItem类需要利用QT的PROPERTY系统,为Moc声明其属性 为了让MyButton对象能够使用其myColor方法,MyButtonItem类需要声明该方法,并标记为Q_INVOKABLE (另外一种解决方案是将myColor声明为槽。 为了让MyButton对象能够接受到C++所emit的信号,并在onMySignals,MyButtonItem类需要声明mySignals信号 - class MyButtonItem : public QDeclarativeItem
- {
- Q_OBJECT
- Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
- signals:
- void colorChanged();
- void mySignals();
- public:
- MyButtonItem(QDeclarativeItem *parent = 0);
- void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
- QWidget *widget = 0);
- public:
- const QColor &color() const;
- void setColor(const QColor &newColor);
- Q_INVOKABLE QColor myColor() const;
- // Alternatives for myColor to be called from QML
- //public slots
- //QColor myColor() const;
- private:
- QColor m_color;
- };
原始作者地址http://blog.csdn.net/changsheng230 小结:关于详解QML与C++混合编程使用的内容介绍完了,希望本文对你有所帮助!
1.这里主要是介绍,如何在c++中调用QML中的函数和设置QML中的属性的问题
2.具体代码
// UICtest.qml
import Qt 4.7
Rectangle {
id: mainWidget;
width: 640
height: 480
function callbyc(v)
{
mainWidget.color = v;
return "finish";
}
Rectangle{
id: secondRect;
x: 100;
y: 20;
width: 400;
height: 300;
Rectangle{
x: 10;
y: 20;
width: 30;
height: 40;
color: "#FF035721"
Text {
objectName: "NeedFindObj";
anchors.fill: parent;
text: "";
}
}
}
} |
// main.cpp
#include <QtGui/QApplication>
#include <QtDeclarative/QDeclarativeView>
#include <QtDeclarative/QDeclarativeEngine>
#include <QtDeclarative/QDeclarativeComponent>
#include <QtDeclarative/QDeclarativeContext>
#include <QtDeclarative/QDeclarativeItem>
#include <QMetaObject>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QDeclarativeView qmlView;
qmlView.setSource(QUrl::fromLocalFile("../UICtest/UICtest.qml"));
qmlView.show();
// 获取根节点,就是 QML中 id是mainWidget的节点
QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(qmlView.rootObject());
item->setProperty("color", QVariant("blue"));
// 查找到我们需要的节点根均objectname NeedFindObj 来获得,并设置他的文本属性
QDeclarativeItem *item1 = item->findChild<QDeclarativeItem *>("NeedFindObj");
if (item1)
{
item1->setProperty("text", QVariant("OK"));
}
// 调用QML中的函数, 分别是 函数所在的对象, 函数名,返回值, 参数
QVariant returnVar;
QVariant arg1 = "blue";
QMetaObject::invokeMethod(item, "callbyc",
Q_RETURN_ARG(QVariant, returnVar),Q_ARG(QVariant, arg1));
qDebug(" %s",returnVar.toString().toLocal8Bit().data());
return a.exec();
} |
说明: 这里的根节点是id为mainWidget的矩形元素,那么在C++中获取根节点后就可以,直接的设置他的属性了。其他属性也可以同样,调用指定节点内的函数是通过QMetaObject中的invokeMethod 来进行调用的。
最后所有关于QML和c++交互部分就基本写完,如果想要更多的东西,或者一些其他方法,强烈看看 http://doc.qt.nokia.com/4.7-snapshot/qtbinding.html,或者帮助文档,(究竟是不是我的文档里面没有还是怎么的)
|