QML中使用C++类的实现
之前用Qt写过串口的小软件。STM32 IAP工具 和 用qt写的一个简单到不能在简单的上位机 。后来接触了QML,觉得传统的那种界面太那个了,写样式也麻烦。所以很早就想过用QML来为串口上位机做界面。无奈没搞懂QML到底是如何去调用C++的。百度了一堆文章,多半是翻译官方的例子。不知所云。直到最近在csdn上看到一篇文章 Qt Quick 之 QML 与 C++ 混合编程详解 ,终于有点懂了。不过,文章似乎有点长了。博客园上面也有见过,有朋友写过类似的文章。今天,总算实现了QML访问一个自定义类中的属性。故写下这篇文章。
例子很简单,main.qml访问stringt类中的一个属性并显示其内容:m_String
注意:Qt版本 5.4.0 | Creater版本 3.3.0
首先创建一个新的 Qt Quick Application-->选择controls 1.3。选择带controls的,生成的main.qml的根是ApplicationWindow 而另一种则是Window,其他的看起来没什么区别。具体要查文档咯
项目中有个MainForm.ui.qml。把他删掉。然后修改main.qml文件。
1 ApplicationWindow { 2 title: qsTr("Hello World") 3 width: 640 4 height: 480 5 visible: true //显示窗口 6 7 8 }
然后创建一个stringt类继承QObject。如果想要让一个类可以被qml访问。这个类必须是继承QObject或其派生类。
使用宏Q_PROPERTY可以让方法被moc感知。stringt类的代码如下
1 #ifndef STRINGT_H 2 #define STRINGT_H 3 4 #include <QObject> 5 6 class stringt : public QObject 7 { 8 Q_OBJECT 9 Q_PROPERTY(QString Ttext READ Ttext WRITE setTtext) 10 public: 11 explicit stringt(QObject *parent = 0); 12 ~stringt(); 13 14 QString Ttext(void) const; 15 void setTtext(const QString str); 16 signals: 17 18 public slots: 19 20 private: 21 QString m_String; 22 }; 23 24 #endif // STRINGT_H
上边是头文件,接下来是源文件
1 #include "stringt.h" 2 3 stringt::stringt(QObject *parent) 4 : QObject(parent) 5 , m_String("Text just") 6 { 7 8 } 9 10 stringt::~stringt() 11 { 12 13 } 14 15 QString stringt::Ttext() const 16 { 17 return m_String; 18 } 19 20 void stringt::setTtext(const QString str) 21 { 22 m_String = str; 23 }
接着就是main文件里面,注册这个类就可以了,用qmlRegisterType这个函数
1 #include <QApplication> 2 #include <QQmlApplicationEngine> 3 #include <QtQml> 4 #include "stringt.h" 5 6 int main(int argc, char *argv[]) 7 { 8 QApplication app(argc, argv); 9 10 qmlRegisterType<stringt>("m.stringT", 1, 0, "StringT"); 11 //要导入的类 包名 主版本号 次版本号 元素名 12 QQmlApplicationEngine engine; 13 engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); 14 15 return app.exec(); 16 }
最后就是QML文件了。这里定义了两个矩形。点击左边的矩形后,右边的矩形会改变颜色和文本。
1 import QtQuick 2.4 2 import QtQuick.Controls 1.3 3 import QtQuick.Window 2.2 4 import QtQuick.Dialogs 1.2 5 import m.stringT 1.0 //导入类 6 7 ApplicationWindow { 8 title: qsTr("Hello World") 9 width: 640 10 height: 480 11 visible: true 12 13 StringT{ //创建一个元素 14 id: stringT 15 } 16 17 Rectangle { 18 id: rect1 19 x: 12; y: 12 20 width: 60; height: 60 21 color: "lightsteelblue" 22 MouseArea { 23 id: rect1_area 24 anchors.fill: parent 25 onClicked: 26 { 27 rect2.color = "lightgreen" 28 rect2_text.text = stringT.Ttext 29 } 30 } 31 } 32 33 Rectangle { 34 id: rect2 35 x: rect1.x + rect1.width + 10 36 y: rect1.y 37 width: rect1.width; height: rect1.height 38 border.color: "lightsteelblue" 39 border.width: 3 40 radius: 3 41 Text { 42 id: rect2_text 43 text: qsTr("Hello") 44 font.pixelSize: 12 45 anchors.centerIn: parent 46 } 47 } 48 }
效果大概是这样的。
---------------------------------传值给C++类---------------------------------
上面,我们将C++注册到QML,便使QML可以访问C++的内容。那怎样将QML中的值,比如Text传给C++呢。只要在函数开头使用Q_INVOKABLE宏便可以了。比如上面的类中的set方法。
1 //void setTtext(const QString str); 2 Q_INVOKABLE void setTtext(const QString str);
然后在main.qml中就可以使用这个set方法了
1 Rectangle { 2 id: rect1 3 x: 12; y: 12 4 width: 60; height: 60 5 color: "lightsteelblue" 6 Text { 7 id: rect1_text 8 text: qsTr("QML") 9 anchors.centerIn: parent 10 } 11 MouseArea { 12 id: rect1_area 13 anchors.fill: parent 14 onClicked: 15 { 16 rect2.color = "lightgreen" 17 stringT.setTtext(rect1_text.text) 18 rect2_text.text = stringT.Ttext 19 } 20 } 21 }
这段代码里面给第一个矩形里面设置了Text。然后在点击这个矩形的时候,第二个矩形的Text就会变成和第一个Text一样了。QML先是调用了类的write方法m_String,接着调用了Ttext这个read方法