posts - 319, comments - 22, trackbacks - 0, articles - 11
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

cmake vs qmake

  • qmake 是为 Qt 量身打造的,使用起来非常方便
  • cmake 使用上不如qmake简单直接,但复杂换来的是强大的功能
    • 内置的 out-of source 构建。(目前QtCreator为qmake也默认启用了该功能,称:shadow build)

    • 为各种平台和场景提供条件编译
    • 可处理多个可执行文件情况,和很好配合 QtTest 工作

如何选择?

Using CMake to Build Qt Projects 一文中说:

  • 对简单的Qt工程,采用 qmake
  • 对复杂度超过 qmake 处理能力的,采用 cmake

尽管如此,如果简单Qt的工程都不知道怎么用 cmake 构建,复杂的工程,就更不知道如何使用 cmake 了。还是从简单的学起吧

简单的 Qt 程序

#include <QtCore/QCoreApplication>
#include <QtCore/QDebug>
int main(int argcchar** argv)
{
QCoreApplication app(argcargv);
qDebug()<<"hello qt!";
app.exec();
}

如果不使用构建工具,直接调用编译器来编译的话,只需要类似这样的一条命令:

g++ main.cpp -Ie:/Qt/4.7.0/include -o main -Le:/Qt/4.7.0/lib -lQtCore4

指定头文件目录,以及需要链接的库

qmake

qmake 需要一个 .pro 文件:

CONFIG += qt
QT -= gui
SOURCES += main.cpp
  • 因为我们需要 Qt的库和头文件,所以需要 CONFIG += qt 

    • 这是默认项,可直接去掉该行
  • 启用qt后,可以通过 QT -= gui 来进一步细调我们需要的模块
    • 默认是 core gui。我们不需要gui模块,故去掉。

cmake

cmake 需要一个 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
    • 这两行可以直接使用 FIND_PACKAGE(Qt4 COMPONENTS QtCore REQUIRED),未指定的模块将被禁用

  • 包含一个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
  • mainwindow.h 需要 moc 预处理

 

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

cmake

PROJECT(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 与 Release

qmake

使用 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自带的模式选择。

posted @ 2011-08-05 07:24 RTY 阅读(1803) | 评论 (0)编辑 收藏

Qt在线文档

http://doc.qt.nokia.com/4.7/

 

Qt e-Learning

http://qt.nokia.com/developer/learning/elearning

http://wikis.in.nokia.com/QtSoftware/LearnQt

http://www.ics.com/learning/icsnetwork/

 

官方Qt移动开发社区、资源、Wiki

Getting started with Git and GitHub

Nokia Forum projects

http://forum.nokia.com

http://forum.nokia.com.cn/ 

http://wiki.forum.nokia.com/index.php/Qt_%E5%BC%80%E5%8F%91

 

官方Qt论坛

http://developer.qt.nokia.com/forums

Qt for Symbian 开发资源

http://discussion.forum.nokia.com/forum/showthread.php?162323-Qt-for-Symbian-development-resources

 

中文Qt网站

http://qt.csdn.net

诺基亚论坛上的Qt for Symbian中文论坛

http://www.qtcn.org

www.qteverywhere.com

 

 

中文文档

http://forum.nokia.com.cn/document_1.html

http://qtdocs.sourceforge.net/index.php/%E5%88%86%E7%B1%BB:Qt_%E5%8F%82%E8%80%83%E6%89%8B%E5%86%8C


其他

 

如果在开发中遇到了技术细节上的问题,相信再下面两个论坛搜索相关关键字会比直接在baidu/google上搜强很多

http://lists.trolltech.com/qt-interest/

 

 

Qt在SlideShare的幻灯片

http://www.slideshare.net/tag/qt

 

非官方的优秀Qt论坛

http://www.qtcentre.org/forum/

 

 

posted @ 2011-08-05 07:22 RTY 阅读(400) | 评论 (1)编辑 收藏

请尊重原创作品和译文。转载请保持文章完整性,并以超链接形式注明原始作者地址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() 的定义如下:

     

    1. bool QMetaObject::invokeMethod ( QObject * obj, const char * member,Qt::ConnectionType type,  
    2. QGenericReturnArgument ret, QGenericArgument val0 = QGenericArgument( 0 ), …)  
     

     

     

invokeMethod的用法为,尝试调用对象obj的方法member(注意member可以为信号或者是槽),如何member可以被调用,则返回真,否则返回假。QMetaObject::invokeMethod可以是异步调用,也可以是同步调用。这取决与它的连接方式Qt::ConnectionType type。如果type为Qt::DirectConnection,则为同步调用,若为Qt::QueuedConnection,则为异步调用。例如:

     

    1. QMetaObject::invokeMethod(object, "methodName",   
    2. Qt::QueuedConnection,   
    3. Q_ARG(type1, arg1),   
    4. 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++定义的方法,如下代码所示:

 

  1. import Qt 4.7   
  2. import Shapes 5.0   //自定义模块  
  3. Item {   
  4.     width: 300; height: 200  
  5.     Ellipse {   
  6.          x: 50; y: 35; width: 200; height: 100   
  7.         color: "blue"   
  8.          MouseArea {   
  9.             anchors.fill: parent  
  10.             // 调用C++中定义的randomColor方法   
  11.             onClicked: parent.color = parent.randomColor()    
  12.         }   
  13.     }  
  14. }  
 

 

为了让上述QML代码成功的调用下面这段代码定义的randomColor()函数,最为关键的一点见randomColor方法用Q_INVOKABLE 修饰。

 

  1. #include <QDeclarativeItem >  
  2. class EllipseItem : public QDeclarativeItem   
  3. {   
  4.     Q_OBJECT   
  5. public:  
  6.       Q_INVOKABLE QColor randomColor() const;  
  7.       …  
  8. }  
 

 

更多细节,请参看我的另一篇博文:QML与C++混合编程使用

在跨线程编程中的使用

我们如何调用驻足在其他线程里的QObject方法呢?Qt提供了一种非常友好而且干净的解决方案:向事件队列post一个事件,事件的处理将以调用我们所感兴趣的方法为主(当然这需要线程有一个正在运行的事件循环)。而触发机制的实现是由moc提供的内省方法实现的。因此,只有信号、槽以及被标记成Q_INVOKABLE的方法才能够被其它线程所触发调用。如果你不想通过跨线程的信号、槽这一方法来实现调用驻足在其他线程里的QObject方法。另一选择就是将方法声明为Q_INVOKABLE,并且在另一线程中用invokeMethod唤起。

 

更多细节,译文事件循环与线程

Qt Service Framework

Qt服务框架是Qt Mobility 1.0.2版本推出的,一个服务(service)是一个独立的组件提供给客户端(client)定义好的操作。客户端可以通过服务的名称,版本号和服务的对象提供的接口来查找服务。 查找到服务后,框架启动服务并返回一个指针。

服务通过插件(plug-ins)来实现。为了避免客户端依赖某个具体的库,服务必须继承自QObject。这样QMetaObject 系统可以用来提供动态发现和唤醒服务的能力。要使QmetaObject机制充分的工作,服务必须满足,其所有的方法都是通过 signal,slot,property 或invokable methodQ_INVOKEBLE来实现

其中,最常见的与servicer交互的方法如下:

  1. QServiceManager manager;QObject *storage ;  
  2. 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 methodQ_INVOKEBLE 是跨进城、跨线程对象之间通信的重要利器。

 

serivceFramework

有关Qt Service Framework的更多讨论和用例,请参见Qt Service Framework文档

posted @ 2011-08-05 07:19 RTY 阅读(1764) | 评论 (0)编辑 收藏

Qt GPL, LGPL & Commercial License

From:

http://www.qteverywhere.com/

 

Qt 4.5中提供了三种授权协议,分别是GPL, LGPL和Commercial,可能很多人要问,为什么同样的一个产品要提供三种授权协议,什么情况下使用什么的样的授权协议最合适?在这里我就大致解释一下:

 

GPL全称是The GNU General Public License,是目前大多数的GNU程序和超过半数的自由软件使用的许可协议。GPL的出发点是代码的开源/免费使用和引用/修改/衍生代码的开源/免 费使用,但不允许修改后和衍生的代码做为闭源的商业软件发布和销售。
GPL协议的主要内容是只要在一个软件中使用(”使用”指类库引用,修改后的代码或者衍生代码)GPL 协议的产品,则该软件产品必须也采用GPL协议,既必须也是开源和免费。这就是所谓的”传染性”。GPL协议的产品作为一个单独的产品使用没有任何问题, 还可以享受免费的优势。

 

回到LGPL,LGPL的全称是 GNU Lesser General Public License,GNU 较宽松公共许可证,也是由协议是由自由软体基金会发布的许可证,是一个主要为类库使用设计的开源协议,和GPL要求任何使用/修改/衍生之GPL类库的的 软件必须采用GPL协议不同。LGPL允许商业软件通过类库引用(link)方式使用LGPL类库而不需要开源商业软件的代码。这使得采用LGPL协议的 开源代码可以被商业软件作为类库引用并发布和销售。

 

除了GPL和LGPL两种开源协议之外,Qt还提供了Commercial商业协议,Qt的商业协议是由Nokia定义的,由Nokia和购买方签 订的,具有法律效应的Qt产品授权协议。 Commercial License相教与GPL和LGPL,对于商业客户提供了更多的灵活性,客户可以任意的修改Qt的源代码,开发商业软件,而不需要公开任何源代码。并 且,在Commercial License中,我们还提供了技术支持服务。当然,商业授权协议是需要费用的。

到底什么时候需要选择GPL和LGPL呢?一个最显而易见的理由就是他们都是免费的,使用LGPL和GPL版本的Qt是不需要支付任何费用的,当然 我们也相应的不会提供技术支持。如果你打算开发真正的开源软件,并希望使用者也可以保持开源,那么GPL是更好的选择,因为所有人,不论你自己还是将来基 于你的代码进行再次开发都必须开源。如果你打算开发闭源(不开放源代码)的商业软件,那么LGPL则更适合,但必须满足下面两个条件:
1. 你的应用程序应该动态链接Qt函数库,并使你的应用程序与未做修改的LGPL库分开发布。同时必须确保使用者(接受者)知道应用程序使用了LGPL版本的Qt;
2. 如果你对LGPL版本的Qt进行了任何修改,并发布,则必须遵循LGPL 条款发布。任何使用者有权利得到这些修改(通常情况下是源代码),并且确保使用者可以通过这些修改自己生成相应你修改过的Qt版本。

相信到这里大家已经对Qt提供的这三种协议有了基本的了解,通常大家还会有一个疑问,就是基于这三种授权协议的Qt产品到底由多少功能上的区别,是 不是商业版本的会更完整,性能更好一些?这里我可以负责任的说:99%的代码都是一样的,无论是GPL, LGPL还是Commercial,功能,性能都没有区别,唯一的区别就在于授权协议的不同。

还有一点需要说明的就是,由于LGPL是在Qt4.5这个版本里面才引入的,所以之前的Qt版本,4.4或者3.x的版本,并不提供LGPL协议,是不可逆的。同时未来发布的Qt版本,就一直会提供三种不同的授权协议版本。

 

下面有一些链接,有兴趣想深入了解这些授权协议的同学,可以学习学习

GPL协议原文 - http://www.gnu.org/copyleft/gpl.html
GPL协议中文译文 - http://bergwolf.googlepages.com/gplv3_zh
LGPL协议原文 - http://www.gnu.org/copyleft/lesser.html
LGPL协议中文译文 - http://www.thebigfly.com/gnu/lgpl/lgpl-v3.php
58种不同的开源协议 - http://www.fsf.org/licensing/licenses/
什么是动态链接 - http://zh.wikipedia.org/wiki/%E5%8A%A8%E6%80%81%E9%93%BE%E6%8E%A5%E5%BA%93
官方声明 - http://www.qtsoftware.com/about/news/lgpl-license-option-added-to-qt
官方Q&A - http://www.qtsoftware.com/about/licensing/frequently-asked-questions

posted @ 2011-08-05 07:18 RTY 阅读(889) | 评论 (0)编辑 收藏

请尊重原创作品和译文。转载请保持文章完整性,并以超链接形式注明原始作者地址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方法时用到:

 

  1. QObject::connect(myButton, SIGNAL(clicked()),   
  2.                   label,  SLOT(showText()));  
 

 

那么宏SIGNAL和SLOT为我们做了那些事情呢,看一下源代码:

 

  1. $QTDIR/src/corelib/kernel/qobjectdefs.h  
  2. # define SLOT(a)     qFlagLocation("1"#a QLOCATION)   
  3. # define SIGNAL(a)   qFlagLocation("2"#a QLOCATION)  
  4. $QTDIR/src/corelib/kernel/qobject.cpp  
  5. const char *qFlagLocation(const char *method)   
  6. {   
  7.     static int idx = 0;   
  8.     flagged_locations[idx] = method;   
  9.     idx = (idx+1) % flagged_locations_count;   
  10.     return method;   
  11. }  
 

 

原来它会基于把我们定义的信号、槽的名称返回一个字符串,比如SIGNAL(clicked()) 返回字符串 “2clicked()”, SLOT(showText())返回字符串“1showText()”

  1. Q_SIGNALS 与 Q_SLOTS  
  2. #  define slots   
  3. #  define signals protected   
  4. # define Q_SLOTS   
  5. # 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)的写法也许会惹怒你的同事。

 

  1. void method()  
  2. {  
  3.       1) emit signalA();  
  4.       2) signalA();    
  5. }  
 

 

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)

 


 

接下来,让我们结合代码来看一下上述宏的使用以及元对象编译器是如何利用这些宏的。

 

 

  1. #include <QDeclarativeItem >  
  2. class EllipseItem : public QDeclarativeItem   
  3. {   
  4.     Q_OBJECT   
  5.     Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)  
  6. public:   
  7.     EllipseItem(QDeclarativeItem *parent = 0);   
  8.     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,   
  9.                QWidget *widget = 0);  
  10.     const QColor &color() const;   
  11.     void setColor(const QColor &newColor);  
  12.     Q_INVOKABLE QColor randomColor() const;  
  13. public Q_SLOTS:   
  14.     void try1();   
  15.     void try2() {}  
  16. Q_SIGNALS:   
  17.     void colorChanged();   
  18.     void ready();  
  19. private:   
  20.     QColor m_color;   
  21. };  
 

 

 

以下代码由元对象编译器moc根据上述头文件自动生成:

 

 

  1. static const uint qt_meta_data_EllipseItem[] = {  
  2. // content:   
  3.        5,       // revision   
  4.        0,       // classname   
  5.        0,    0, // classinfo   
  6.        5,   14, // methods   
  7.        1,   39, // properties   
  8.        0,    0, // enums/sets   
  9.        0,    0, // constructors   
  10.        0,       // flags   
  11.        2,       // signalCount  
  12. // signals: signature, parameters, type, tag, flags   
  13.       13,   12,   12,   12, 0x05,   
  14.       28,   12,   12,   12, 0x05,  
  15. // slots: signature, parameters, type, tag, flags   
  16.       36,   12,   12,   12, 0x0a,   
  17.       43,   12,   12,   12, 0x0a,  
  18. // methods: signature, parameters, type, tag, flags   
  19.       57,   12,   50,   12, 0x02,  
  20. // properties: name, type, flags   
  21.       71,   50, 0x43495103,  
  22. // properties: notify_signal_id   
  23.        0,  
  24.        0        // eod   
  25. };  
  26. static const char qt_meta_stringdata_EllipseItem[] = {   
  27.     "EllipseItem/0/0colorChanged()/0ready()/0"   
  28.     "try1()/0try2()/0QColor/0randomColor()/0"   
  29.     "color/0"   
  30. };  
 

 

 

从上面代码实例我们可以看到, 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)

posted @ 2011-08-05 07:16 RTY 阅读(805) | 评论 (0)编辑 收藏

请尊重原创作品和译文。转载请保持文章完整性,并以超链接形式注明原始作者地址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中。

  1. QDeclarativeView *qmlView = new QDeclarativeView;  
  2. qmlView->setSource(QUrl::fromLocalFile("myqml.qml"));  
  3.   
  4. QWidget *widget = myExistingWidget();  
  5. QVBoxLayout *layout = new QVBoxLayout(widget);  
  6. 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的组件中。举例说明:

>

  1. QGraphicsScene* scene = myExistingGraphicsScene();  
  2. QDeclarativeEngine *engine = new QDeclarativeEngine;  
  3. QDeclarativeComponent component(engine, QUrl::fromLocalFile("myqml.qml"));  
  4. QGraphicsObject *object =  
  5.     qobject_cast(component.create());  
  6. 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

posted @ 2011-08-04 22:38 RTY 阅读(2659) | 评论 (0)编辑 收藏

本文介绍的是Qt 内省机制,关于内省,新手的原因,我们一块学习,所谓内省是指面向对象语言的一种在运行期间查询对象信息的能力, 比如如果该语具有运行期间检查对象型别的能力,那么我们称它是型别内省(type intropection)的,型别内省可以用来实施多态。

c++内省比较有限,它仅支持上面所说的型别内省, C++的型别内省是通过运行时类型识别(RTTI)(Run-Time Type Information)中的typeid 以及 dynamic_case关键字来实现的,举例说明:

  1. // rabbit 派生于 Animal, jump为虚函数
  2. if ( rabbit *p = dynamic_case<Animal*>(obj))
  3. {
  4. p->jump();
  5. }
  6. //我们还可以通过typeid萃取到对象的型别信息,比如对象的名称
  7. std::cout << typeid(obj).name() << std::endl

Qt拓展了C++的内省机制,(实际上,它并没有采用c++的RTTI),而是提供了更为强大的元对象(meta object)机制,来实现内省。接下来,就让我们看看,Qt是如何扩展c++内省机制的。

要深刻理解Qt的内省机制,首先理解QObject,QObject类是整个Qt对象模型的心脏,Qt对象模型最为核心的功能是提供一种无缝的对象通讯机制,即就是我们所熟知的信号和槽。QObject主要有三大职责: 内存管理、内省(intropection)与事件处理。本文将集中在在内省的讨论。以下代码介绍了QObject类提供的内省方法:

  1. //每个对象可以通过QObject::setObjectName()和QObject::objectName()设置、取得类的实例的名字
  2. FirstQtApp obj;
  3. obj.setObjectName("instanceName");
  4. QString name1 = obj.objectName(); // return instanceName
  5. //每个对象还可以通过它的元对象className方法得到类的名字
  6. QString name2 = obj.metaObject()->className(); // return FirtstQtApp
  7. //每个对象可以通过QObject::inherits方法来查询是否对前对象类派生于量一个类
  8. bool isherited = obj.inherits("QObject"); // returns true
  9. isherited = obj.inherits("QWideget"); // returns true

让我们再来一下QObject::inherits方法的底层实现:

  1. inline bool inherits(const char *classname) const
  2. { 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的子类中的内省方法。

  1. // defined at ..\Qt\src\corelib\kernel\qobjectdefs.h
  2. /* tmake ignore Q_OBJECT */
  3. #define Q_OBJECT \
  4. public: \
  5. Q_OBJECT_CHECK \
  6. static const QMetaObject staticMetaObject; \
  7. Q_OBJECT_GETSTATICMETAOBJECT \
  8. virtual const QMetaObject *metaObject() const; \
  9. virtual void *qt_metacast(const char *); \
  10. QT_TR_FUNCTIONS \
  11. 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声明的源代码:

  1. struct Q_CORE_EXPORT QMetaObject
  2. {
  3. const char *className() const;
  4. const QMetaObject *superClass() const;
  5. QObject *cast(QObject *obj) const;
  6. ....
  7. int methodOffset() const;
  8. int enumeratorOffset() const;
  9. int propertyOffset() const;
  10. int classInfoOffset() const;
  11. int constructorCount() const;
  12. int methodCount() const;
  13. int enumeratorCount() const;
  14. int propertyCount() const;
  15. int classInfoCount() const;
  16. int indexOfConstructor(const char *constructor) const;
  17. int indexOfMethod(const char *method) const;
  18. int indexOfSignal(const char *signal) const;
  19. int indexOfSlot(const char *slot) const;
  20. int indexOfEnumerator(const char *name) const;
  21. int indexOfProperty(const char *name) const;
  22. int indexOfClassInfo(const char *name) const;
  23. ...
  24. }

上述方法主要是实现对元对象表的访问及其操作,对元对象表(由moc实现)实例如下所示:

  1. // defined at ..\Qt\src\corelib\kernel\qobjectdefs.h
  2. /* tmake ignore Q_OBJECT */
  3. #define Q_OBJECT \
  4. public: \
  5. Q_OBJECT_CHECK \
  6. static const QMetaObject staticMetaObject; \
  7. Q_OBJECT_GETSTATICMETAOBJECT \
  8. virtual const QMetaObject *metaObject() const; \
  9. virtual void *qt_metacast(const char *); \
  10. QT_TR_FUNCTIONS \
  11. 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 内省机制剖析的内容介绍完了,希望本文对你有所帮助!

posted @ 2011-08-04 22:33 RTY 阅读(693) | 评论 (0)编辑 收藏

本文适合于对Qt Quick有基本了解的读者。首先回答一个比较常会被问到的问题:什么是QML,它与Quick的关系是什么?

Qt QuickQt User Interface Creation Kit的缩写,而QMLQt 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 ”。

  1. //main.qml
  2. import Qt 4.7
  3. import MyItems 1.0
  4. Item {
  5. width: 300; height: 200
  6. MyButton {
  7. //注意:x, y, width, height是继承自item的属性,无需再自定义的item中实现
  8. x: 50; y: 50
  9. width: 200; height: 100
  10. color: "gray" //自定义属性
  11. onMySignals: dosth //自定义信号mySignals
  12. MouseArea {
  13. anchors.fill: parent
  14. onClicked: parent.myColor() // 调用C++定义的方法myColor
  15. }
  16. }
  17. }
  18. //main.qml
  19. import Qt 4.7
  20. import MyItems 1.0
  21. Item {
  22. width: 300; height: 200
  23. MyButton {
  24. //注意:x, y, width, height是继承自item的属性,无需再自定义的item中实现
  25. x: 50; y: 50
  26. width: 200; height: 100
  27. color: "gray" //自定义属性
  28. onMySignals: dosth //自定义信号mySignals
  29. MouseArea {
  30. anchors.fill: parent
  31. onClicked: parent.myColor() // 调用C++定义的方法myColor
  32. }
  33. }
  34. }

为了能够上述qml代码工作,需要为在Qt C++代码中注册MyButton及其所属的模块,对应的main.cpp代码如下:

  1. #include <QtGui/QApplication>
  2. #include "qmlapplicationviewer.h"
  3. int main(int argc, char *argv[])
  4. {
  5. QApplication app(argc, argv);
  6. QmlApplicationViewer viewer;
  7. // MyButtonItem是与QML中MyButton相对应的C++实现的类名称
  8. // 1,0是版本信息;MyItems是MyButton所属的模块名称
  9. qmlRegisterType<MyButtonItem>("MyItems", 1, 0, "MyButton ");
  10. viewer.setOrientation(QmlApplicationViewer::Auto);
  11. viewer.setMainQmlFile(QLatin1String("qml/untitled/main.qml"));
  12. viewer.show();
  13. return app.exec();
  14. }
  15. #include <QtGui/QApplication>
  16. #include "qmlapplicationviewer.h"
  17. int main(int argc, char *argv[])
  18. {
  19. QApplication app(argc, argv);
  20. QmlApplicationViewer viewer;
  21. // MyButtonItem是与QML中MyButton相对应的C++实现的类名称
  22. // 1,0是版本信息;MyItems是MyButton所属的模块名称
  23. qmlRegisterType<MyButtonItem>("MyItems", 1, 0, "MyButton ");
  24. viewer.setOrientation(QmlApplicationViewer::Auto);
  25. viewer.setMainQmlFile(QLatin1String("qml/untitled/main.qml"));
  26. viewer.show();
  27. return app.exec();
  28. }

上面我们在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信号

  1. class MyButtonItem : public QDeclarativeItem
  2. {
  3. Q_OBJECT
  4. Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
  5. signals:
  6. void colorChanged();
  7. void mySignals();
  8. public:
  9. MyButtonItem(QDeclarativeItem *parent = 0);
  10. void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
  11. QWidget *widget = 0);
  12. public:
  13. const QColor &color() const;
  14. void setColor(const QColor &newColor);
  15. Q_INVOKABLE QColor myColor() const;
  16. // Alternatives for myColor to be called from QML
  17. //public slots
  18. //QColor myColor() const;
  19. private:
  20. QColor m_color;
  21. };

原始作者地址http://blog.csdn.net/changsheng230

小结:关于详解QMLC++混合编程使用的内容介绍完了,希望本文对你有所帮助!

posted @ 2011-08-04 22:31 RTY 阅读(918) | 评论 (0)编辑 收藏

posted @ 2011-08-04 22:29 RTY 阅读(595) | 评论 (0)编辑 收藏

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 idmainWidget的节点
    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();
}





说明:

这里的根节点是idmainWidget的矩形元素,那么在C++中获取根节点后就可以,直接的设置他的属性了。其他属性也可以同样,调用指定节点内的函数是通过QMetaObject中的invokeMethod 来进行调用的。


最后所有关于QMLc++交互部分就基本写完,如果想要更多的东西,或者一些其他方法,强烈看看

http://doc.qt.nokia.com/4.7-snapshot/qtbinding.html,或者帮助文档,(究竟是不是我的文档里面没有还是怎么的)

posted @ 2011-08-04 22:05 RTY 阅读(1647) | 评论 (2)编辑 收藏

仅列出标题
共31页: First 9 10 11 12 13 14 15 16 17 Last