|
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,或者幫助文檔,(究竟是不是我的文檔里面沒有還是怎么的)
|