Qt5处于过度阶段,架构繁琐,学习成本不低。尤其是UI代码竟然被重写,变了天。
Qt中的c++可能是连接OPENCV与QML的一个不错的桥梁,在此学习这部分实用的技术。
Reference: http://blog.csdn.net/foruok/article/details/32698603
一、在 QML 中调用 c++
实现 c++类
注册 QML 类型
在 QML 中导入类型
在 QML 创建由 C++ 导出的类型的实例并使用
Qt 提供了两种在 QML 环境中使用 C++ 对象的方式:
- 在 C++ 中实现一个类,注册到 QML 环境中, QML 环境中使用该类型创建对象
- 在 C++ 中构造一个对象,将这个对象设置为 QML 的上下文属性,在 QML 环境中直接使用改属性
对要导出的 C++ 类都有要求,不是一个类的所有方法、变量都可以被 QML 使用。
因此我们先来看看怎样让一个方法或属性可以被 QML 使用。
从 QObject 或 QObject 的派生类继承
使用 Q_OBJECT 宏
信号,槽 可以直接被调用 (方法)
成员函数时使用 Q_INVOKABLE 宏来修饰,可以让该方法被元对象系统调用。
class ColorMaker : public QObject
{
Q_OBJECT public:
ColorMaker(QObject *parent = );
~ColorMaker(); Q_INVOKABLE GenerateAlgorithm algorithm() const;
Q_INVOKABLEvoid setAlgorithm(GenerateAlgorithm algorithm); signals:
void colorChanged(const QColor & color);
void currentTime(const QString &strTime); publicslots:
void start();
void stop();
};
QML 中使用 ${Object}.${method} 来访问:
Component.onCompleted: {
colorMaker.color = Qt.rgba(,,, );
colorMaker.setAlgorithm(ColorMaker.LinearIncrease);
changeAlgorithm(colorAlgorithm, colorMaker.algorithm());
}
Q_PROPERTY 宏 (属性)
Q_PROPERTY 宏用来定义可通过元对象系统访问的属性。
通过它定义的属性,可以在 QML 中访问、修改,也可以在属性变化时发射特定的信号。
要想使用 Q_PROPERTY 宏,你的类必须是 QObject 的后裔,必须在类首使用 Q_OBJECT 宏。
- READ 标记 如果你没有为属性指定 MEMBER 标记,则 READ 标记必不可少;声明一个读取属性的函数,该函数一般没有参数,返回定义的属性。
- WRITE 标记 可选配置。声明一个设定属性的函数。它指定的函数,只能有一个与属性类型匹配的参数,必须返回 void 。
- NOTIFY 标记 可选配置。给属性关联一个信号(该信号必须是已经在类中声明过的),当属性的值发生变化时就会触发该信号。信号的参数,一般就是你定义的属性。
class QQuickText : public QQuickImplicitSizeItem
{
Q_OBJECT
Q_ENUMS(HAlignment) Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged)
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
... public:
enum HAlignment { AlignLeft = Qt::AlignLeft,
AlignRight = Qt::AlignRight,
AlignHCenter = Qt::AlignHCenter,
AlignJustify = Qt::AlignJustify };
...
QString text() const;
void setText(const QString &); QFont font() const;
void setFont(const QFont &font); QColor color() const;
void setColor(const QColor &c);
...
};
实现 c++类 (define好了类,之后实现各函数)
注册 QML 类型 (下一步)
要注册一个 QML 类型,有多种方法可用,如
qmlRegisterSingletonType() 用来注册一个单例类型, qmlRegisterType() 注册一个非单例的类型, // 模板函数 qmlRegisterTypeNotAvailable() 注册一个类型用来占位, qmlRegisterUncreatableType() 通常用来注册一个具有附加属性的附加类
其中一个原型:
template<typename T> // 包名,主版本,次版本,类名
int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName);
#include <QtGui/QGuiApplication>
#include "qtquick2applicationviewer.h"
#include <QtQml>
#include "colorMaker.h" int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv); // 注册qml类型
qmlRegisterType<ColorMaker>("an.qt.ColorMaker", , , "ColorMaker"); QtQuick2ApplicationViewer viewer;
viewer.setMainQmlFile(QStringLiteral("qml/colorMaker/main.qml"));
viewer.showExpanded(); return app.exec();
}
import QtQuick 2.0
import QtQuick.Controls 1.1
import an.qt.ColorMaker 1.0 Rectangle {
width: ;
height: ;
Text {
id: timeLabel;
anchors.left: parent.left;
anchors.leftMargin: ;
anchors.top: parent.top;
anchors.topMargin: ;
font.pixelSize: ;
}
ColorMaker {
id: colorMaker;
color: Qt.green;
} Rectangle {
id: colorRect;
anchors.centerIn: parent;
width: ;
height: ;
color: "blue";
} Button {
id: start;
text: "start";
anchors.left: parent.left;
anchors.leftMargin: ;
anchors.bottom: parent.bottom;
anchors.bottomMargin: ;
onClicked: {
colorMaker.start();
}
}
Button {
id: stop;
text: "stop";
anchors.left: start.right;
anchors.leftMargin: ;
anchors.bottom: start.bottom;
onClicked: {
colorMaker.stop();
}
} function changeAlgorithm(button, algorithm){
switch(algorithm)
{
case :
button.text = "RandomRGB";
break;
case :
button.text = "RandomRed";
break;
case :
button.text = "RandomGreen";
break;
case :
button.text = "RandomBlue";
break;
case :
button.text = "LinearIncrease";
break;
}
} Button {
id: colorAlgorithm;
text: "RandomRGB";
anchors.left: stop.right;
anchors.leftMargin: ;
anchors.bottom: start.bottom;
onClicked: {
var algorithm = (colorMaker.algorithm() + ) % ;
changeAlgorithm(colorAlgorithm, algorithm);
colorMaker.setAlgorithm(algorithm);
}
} Button {
id: quit;
text: "quit";
anchors.left: colorAlgorithm.right;
anchors.leftMargin: ;
anchors.bottom: start.bottom;
onClicked: {
Qt.quit();
}
} Component.onCompleted: {
colorMaker.color = Qt.rgba(,,, );
colorMaker.setAlgorithm(ColorMaker.LinearIncrease);
changeAlgorithm(colorAlgorithm, colorMaker.algorithm());
} Connections {
target: colorMaker;
onCurrentTime:{
timeLabel.text = strTime;
timeLabel.color = colorMaker.timeColor;
}
} Connections {
target: colorMaker;
onColorChanged:{
colorRect.color = color;
}
}
}
qml中调用c++
实现 c++类
注册 QML 类型
在 QML 中导入类型 ( 下一步 )
将 对象 直接作为参数 传入 QML
把 C++ 中创建的对象作为属性传递到 QML 环境中,然后在 QML 环境中访问。就不需要 import 语句了!
将一个对象注册为属性:
#include <QtGui/QGuiApplication>
#include "qtquick2applicationviewer.h"
#include <QtQml>
#include "colorMaker.h" int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv); QtQuick2ApplicationViewer viewer;
// viewer.rootContext() 返回的是 QQmlContext 对象。
// QQmlContext 类代表一个 QML 上下文,它的 setContextProperty() 方法可以为该上下文设置一个全局可见的属性。
viewer.rootContext()->setContextProperty("colorMaker", new ColorMaker); // 从堆上分配了一个 ColorMaker 对象 viewer.setMainQmlFile(QStringLiteral("qml/colorMaker/main.qml"));
viewer.showExpanded(); return app.exec();
}
貌似,这个方法比较方便呐。
import QtQuick 2.0
import QtQuick.Controls 1.1
//[1]
//import an.qt.ColorMaker 1.0 Rectangle {
width: ;
height: ;
Text {
id: timeLabel;
anchors.left: parent.left;
anchors.leftMargin: ;
anchors.top: parent.top;
anchors.topMargin: ;
font.pixelSize: ;
}
/* [2]
ColorMaker {
id: colorMaker;
color: Qt.green;
}
*/ Rectangle {
id: colorRect;
anchors.centerIn: parent;
width: ;
height: ;
color: "blue";
} Button {
id: start;
text: "start";
anchors.left: parent.left;
anchors.leftMargin: ;
anchors.bottom: parent.bottom;
anchors.bottomMargin: ;
onClicked: {
colorMaker.start();
}
}
Button {
id: stop;
text: "stop";
anchors.left: start.right;
anchors.leftMargin: ;
anchors.bottom: start.bottom;
onClicked: {
colorMaker.stop();
}
} function changeAlgorithm(button, algorithm){
switch(algorithm)
{
case :
button.text = "RandomRGB";
break;
case :
button.text = "RandomRed";
break;
case :
button.text = "RandomGreen";
break;
case :
button.text = "RandomBlue";
break;
case :
button.text = "LinearIncrease";
break;
}
} Button {
id: colorAlgorithm;
text: "RandomRGB";
anchors.left: stop.right;
anchors.leftMargin: ;
anchors.bottom: start.bottom;
onClicked: {
var algorithm = (colorMaker.algorithm() + ) % ;
changeAlgorithm(colorAlgorithm, algorithm);
colorMaker.setAlgorithm(algorithm);
}
} Button {
id: quit;
text: "quit";
anchors.left: colorAlgorithm.right;
anchors.leftMargin: ;
anchors.bottom: start.bottom;
onClicked: {
Qt.quit();
}
} Component.onCompleted: {
colorMaker.color = Qt.rgba(,,, );
//[3]
//colorMaker.setAlgorithm(ColorMaker.LinearIncrease);
colorMaker.setAlgorithm();
changeAlgorithm(colorAlgorithm, colorMaker.algorithm());
} Connections {
target: colorMaker;
onCurrentTime:{
timeLabel.text = strTime;
timeLabel.color = colorMaker.timeColor;
}
} Connections {
target: colorMaker;
onColorChanged:{
colorRect.color = color;
}
}
}
对象作为参数
二、在c++中使用 QML 对象
- Image 对应 QQuickImage ,
- Text 对应 QQuickText
import QtQuick 2.0
import QtQuick.Controls 1.1 Rectangle {
objectName: "rootRect";
width: ;
height: ;
Text {
objectName: "textLabel";
text: "Hello World";
anchors.centerIn: parent;
font.pixelSize: ;
} Button {
anchors.right: parent.right;
anchors.rightMargin: ;
anchors.bottom: parent.bottom;
anchors.bottomMargin: ;
text: "quit";
objectName: "quitButton";
}
}
#include <QtGui/QGuiApplication>
#include "qtquick2applicationviewer.h"
#include <QQuickItem>
#include "changeColor.h"
#include <QMetaObject>
#include <QDebug>
#include <QColor>
#include <QVariant> int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv); QtQuick2ApplicationViewer viewer;
viewer.setMainQmlFile(QStringLiteral("qml/callQml/main.qml"));
viewer.showExpanded(); QQuickItem * rootItem = viewer.rootObject();
new ChangeQmlColor(rootItem); // 内部通过一个定时器,一秒改变一次传入对象的颜色
QObject * quitButton = rootItem->findChild<QObject*>("quitButton");
if(quitButton)
{
// clicked() 信号连接到 QGuiApplication 的 quit() 槽上
QObject::connect(quitButton, SIGNAL(clicked()), &app, SLOT(quit()));
} QObject *textLabel = rootItem->findChild<QObject*>("textLabel");
if(textLabel)
{
//1. failed call
bool bRet = QMetaObject::invokeMethod(textLabel, "setText", Q_ARG(QString, "world hello"));
qDebug() << "call setText return - " << bRet;
textLabel->setProperty("color", QColor::fromRgb(,,));
//2. good call
bRet = QMetaObject::invokeMethod(textLabel, "doLayout"); // 对应的c++中的接口 名词不同,所以上面的失败了
qDebug() << "call doLayout return - " << bRet;
} return app.exec();
}
#ifndef CHANGECOLOR_H
#define CHANGECOLOR_H
#include <QObject>
#include <QTimer> class ChangeQmlColor : public QObject
{
Q_OBJECT
public:
ChangeQmlColor(QObject *target, QObject *parent = );
~ChangeQmlColor(); protected slots:
void onTimeout(); private:
QTimer m_timer;
QObject *m_target;
}; #endif
ChangeQmlColor定义
#include "changeColor.h"
#include <QDateTime>
#include <QColor>
#include <QVariant> ChangeQmlColor::ChangeQmlColor(QObject *target, QObject *parent)
: QObject(parent)
, m_timer(this)
, m_target(target)
{
qsrand(QDateTime::currentDateTime().toTime_t());
connect(&m_timer, SIGNAL(timeout()), this, SLOT(onTimeout()));
m_timer.start();
} ChangeQmlColor::~ChangeQmlColor()
{} void ChangeQmlColor::onTimeout()
{
QColor color = QColor::fromRgb(qrand()%, qrand()%, qrand()%);
m_target->setProperty("color", color);
}
ChangeQmlColor实现