一、效果展示
本篇文章還是帶來一個簡單的qt示例分析,且看圖1效果。
圖1 貝塞爾曲線
二、源碼分析
該示例代碼所在目錄quick\scenegraph\customgeometry,感興趣的同學可以自己去找,這篇文章我還是主要講解源碼,不涉及其他方面。
廢話不多述,下面開始源碼剖析。本篇講解的示例看似簡單,卻是在C++和qml之間的一座橋梁,他告訴我們C++和qml是怎么混合編程的,在這篇文章中有幾個重要的函數或者宏,例如:qmlRegisterType、Q_PROPERTY。
1、main文件
1 int main(int argc, char **argv) 2 { 3 QGuiApplication app(argc, argv); 4 5 qmlRegisterType<BezierCurve>("CustomGeometry", 1, 0, "BezierCurve");//注冊自定義Quick控件到qml系統環境中 6 7 QQuickView view; 8 QSurfaceFormat format = view.format(); 9 format.setSamples(16); 10 view.setFormat(format); 11 view.setSource(QUrl("qrc:///scenegraph/customgeometry/main.qml")); 12 view.show(); 13 14 app.exec(); 15 }
上述代碼第5行使用了qmlRegisterType函數將C++中自定義的QQuickItem類型注冊到qml環境中,4個參數分別是:包名、主版本號、子版本號和控件名稱
qml文件可以通過QQuickView對象來加載,并展示。參考Qml文件的兩種加載方式|啟動Qt quick app的兩種方法
2、自定義QQuickItem類型
1 class BezierCurve : public QQuickItem 2 { 3 Q_OBJECT 4 5 Q_PROPERTY(QPointF p1 READ p1 WRITE setP1 NOTIFY p1Changed)//使用Q_PROPERTY進行聲明的宏可以通過屬性系統進行操作,例如qss中qproperty-p1:1,1 qml中p1: Qt.point(0, 1) 6 Q_PROPERTY(QPointF p2 READ p2 WRITE setP2 NOTIFY p2Changed) 7 Q_PROPERTY(QPointF p3 READ p3 WRITE setP3 NOTIFY p3Changed) 8 Q_PROPERTY(QPointF p4 READ p4 WRITE setP4 NOTIFY p4Changed) 9 10 Q_PROPERTY(int segmentCount READ segmentCount WRITE setSegmentCount NOTIFY segmentCountChanged)//WRITE操作之后,發生NOTIFY指定的信號 11 12 public: 13 BezierCurve(QQuickItem *parent = 0); 14 ~BezierCurve(); 15 16 //! [2] 17 QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);//qml文件中通過SequentialAnimation動畫修改p2和p3的值,并觸發update函數 18 //! [2] 19 20 QPointF p1() const { return m_p1; } 21 QPointF p2() const { return m_p2; } 22 QPointF p3() const { return m_p3; } 23 QPointF p4() const { return m_p4; } 24 25 int segmentCount() const { return m_segmentCount; } 26 27 void setP1(const QPointF &p); 28 void setP2(const QPointF &p); 29 void setP3(const QPointF &p); 30 void setP4(const QPointF &p); 31 32 void setSegmentCount(int count); 33 34 signals: 35 void p1Changed(const QPointF &p); 36 void p2Changed(const QPointF &p); 37 void p3Changed(const QPointF &p); 38 void p4Changed(const QPointF &p); 39 40 void segmentCountChanged(int count); 41 42 private: 43 QPointF m_p1; 44 QPointF m_p2; 45 QPointF m_p3; 46 QPointF m_p4; 47 48 int m_segmentCount; 49 };
自定義QQuickItem類型頭文件函數中第5-8行都使用了Q_PROPERTY宏,該宏的作用是成員p可以用個p接口訪問、通過setP接口設置,當成員p發生變化的時候會有pChanged信號發出。訪問接口在頭文件中已經實現,下邊我們看一個設置接口的實現
1 void BezierCurve::setP1(const QPointF &p) 2 { 3 if (p == m_p1) 4 return; 5 6 m_p1 = p; 7 emit p1Changed(p); 8 update(); 9 }
設置接口也相對簡單,當調用該接口的時候,發出指定信號。
3、qml文件中使用自定義類型
1 import QtQuick 2.0 2 import CustomGeometry 1.0 //導入自定義包 3 //! [1] //! [2] 4 Item { 5 width: 300 6 height: 200 7 8 BezierCurve {//直接使用控件名稱 導入方式也可以改為import CustomGeometry 1.0 as MyCustom,那么控件使用方式改為MyCustom.BezierCurve 9 id: line 10 anchors.fill: parent 11 anchors.margins: 20 12 //! [2] //! [3] 13 property real t//自定義屬性 14 SequentialAnimation on t {//執行順序動畫 15 NumberAnimation { to: 1; duration: 2000; easing.type: Easing.InOutQuad } 16 NumberAnimation { to: 0; duration: 2000; easing.type: Easing.InOutQuad } 17 loops: Animation.Infinite//無限循環 18 } 19 20 p2: Qt.point(t, 1 - t)//只有通過Q_PROPERTY宏聲明過的屬性才可以這樣訪問 21 p3: Qt.point(1 - t, t) 22 } 23 //! [3] //! [4] 24 Text { 25 anchors.bottom: line.bottom 26 27 x: 20 28 width: parent.width - 40 29 wrapMode: Text.WordWrap 30 31 text: "This curve is a custom scene graph item, implemented using GL_LINE_STRIP" 32 } 33 }
總結:理解qmlRegisterType、Q_PROPERTY的功能非常重要, 他們是你學習qml很重要的一個環節。個人覺著C++和qml混編是一個趨勢,雖然QWidget目前開發比較流行,但視圖模型分離會讓開發效率更高效。
?
注:該文章是個人學習之用,僅供參考。錯誤之處還請大家諒解