Qt5处于过度阶段,架构繁琐,学习成本不低。尤其是UI代码竟然被重写,变了天。

Qt中的c++可能是连接OPENCV与QML的一个不错的桥梁,在此学习这部分实用的技术。

Reference: http://blog.csdn.net/foruok/article/details/32698603

一、在 QML 中调用 c++

  1. 实现 c++类

  2. 注册 QML 类型

  3. 在 QML 中导入类型

  4. 在 QML 创建由 C++ 导出的类型的实例并使用

Qt 提供了两种在 QML 环境中使用 C++ 对象的方式:

  1. 在 C++ 中实现一个,注册到 QML 环境中, QML 环境中使用该类型创建对象
  2. 在 C++ 中构造一个对象,将这个对象设置为 QML 的上下文属性,在 QML 环境中直接使用改属性

对要导出的 C++ 类都有要求,不是一个类的所有方法、变量都可以被 QML 使用。

因此我们先来看看怎样让一个方法属性可以被 QML 使用。


对要导出的 C++ 类都有要求,不是一个类的所有方法、变量都可以被 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 / WRITE / NOTIFY 三个选项。我们来看看都是什么含义。
  • 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);
...
};

  1. 实现 c++类 (define好了类,之后实现各函数)

  2. 注册 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++


  1. 实现 c++类

  2. 注册 QML 类型

  3. 在 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 对象

 
我们可以使用 QML 对象的信号、槽,访问它们的属性,都没有问题,因为很多 QML 对象对应的类型,原本就是 C++ 类型,比如
    • Image 对应 QQuickImage ,
    • Text 对应 QQuickText
但是,这些与 QML 类型对应的 C++ 类型都是私有的,你写的 C++ 代码也不能直接访问。怎么办?
 
Qt 最核心的一个基础特性,就是元对象系统。
通过元对象系统,你可以查询 QObject 的某个派生类的类名、有哪些信号、槽、属性、可调用方法等等信息
然后也可以使用 QMetaObject::invokeMethod() 调用 QObject 的某个注册到元对象系统中的方法。
而对于使用 Q_PROPERTY 定义的属性,可以使用 QObject 的 property() 方法访问属性,如果该属性定义了 WRITE 方法,还可以使用 setProperty() 修改属性。
 
所以只要我们找到 QML 环境中的某个对象,就可以通过元对象系统来访问它的属性、信号、槽等。
关键就是:查找对象!
 
查找如下QML的对象:
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";
}
}
我们给根元素起了个名字 "rootRect" ,给退出按钮起了个名字 "quitButton" ,给文本起了名字 "textLabel" 。
我们会在 C++ 代码中通过这些个名字来查找对应的对象并改变它们。
 
#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实现

[Qt5] How to connect c++ with QML的更多相关文章

  1. Qt5官方demo分析集29——Extending QML - Property Value Source Example

    此系列的所有文章都可以在这里查看http://blog.csdn.net/cloud_castle/article/category/2123873 接上文Qt5官方demo解析集28--Extend ...

  2. Qt5官方demo解析集30——Extending QML - Binding Example

    本系列全部文章能够在这里查看http://blog.csdn.net/cloud_castle/article/category/2123873 接上文Qt5官方demo解析集29--Extendin ...

  3. Qt5官方demo解析集28——Extending QML - Signal Support Example

    本系列全部文章能够在这里查看http://blog.csdn.net/cloud_castle/article/category/2123873 接上文Qt5官方demo解析集27--Extendin ...

  4. C语言 C++1X STL QT免费视频课程 QT5界面开发美化 式样表 QML

    C/C++/QT界面开发界面美化视频课程系列 课程1   C语言 C++1X STL QT免费视频课程 QT5界面开发美化 式样表 QML 返回顶部 课程1   C语言 C++1X STL QT免费视 ...

  5. Qt5官方demo解析集21——Extending QML - Adding Types Example

    本系列全部文章能够在这里查看http://blog.csdn.net/cloud_castle/article/category/2123873 又是一个新的系列了,只是这个系列和我们之前的Chapt ...

  6. [Code::Blocks] Install wxWidgets & openCV

    The open source, cross platform, free C++ IDE. Code::Blocks is a free C++ IDE built to meet the most ...

  7. 本人SW知识体系导航 - Programming menu

    将感悟心得记于此,重启程序员模式. js, py, c++, java, php 融汇之全栈系列 [Full-stack] 快速上手开发 - React [Full-stack] 状态管理技巧 - R ...

  8. qt5 connect问题

    参考资料:Qt学习之路2     在qt从4到5的升级过程中,connect的方法只是添加了一些重载的形式,qt5新增的connect添加了编译器类型检查,如果遇到匹配失败的,或者找不到信号/槽的地方 ...

  9. QML与C++混合编程详解(转)

    原文转自:http://blog.csdn.net/ieearth/article/details/42243553 原文转自:https://www.cnblogs.com/findumars/p/ ...

随机推荐

  1. PHP版微信公共平台消息主动推送,突破订阅号一天只能发送一条信息限制

    2013年10月06日最新整理. PHP版微信公共平台消息主动推送,突破订阅号一天只能发送一条信息限制 微信公共平台消息主动推送接口一直是腾讯的私用接口,相信很多朋友都非常想要用到这个功能. 通过学习 ...

  2. 【转载】NuGet镜像上线试运行

    原文链接: http://www.cnblogs.com/cmt/p/nuget-mirror.html 在Visual Studio中的添加方法: 由于目前带宽有限,如果出现下面的问题,说明当前带宽 ...

  3. asp.net identity 2.2.0 在MVC下的角色启用和基本使用(一)

    基本环境:asp.net 4.5.2 第一步:在App_Start文件夹中的IdentityConfig.cs中添加角色控制器. 在namespace xxx内(即最后一个“}”前面)添加 角色控制类 ...

  4. C#函数式编程

    提起函数式编程,大家一定想到的是语法高度灵活和动态的LISP,Haskell这样古老的函数式语言,往近了说ruby,javascript,F#也是函数式编程的流行语言.然而自从.net支持了lambd ...

  5. Android Studio 1.0.1 + Genymotion安卓模拟器打造高效安卓开发环境

    我们开发安卓大多是使用Eclipse和安卓SDK中自带的安卓模拟器.当然,Google早就推出了自己的安卓开发环境——Android studio,在不久前,Google发布了Android Stud ...

  6. 博客的QQ群群规

    本人博客园博客夏天的森林相关的QQ群一共有3个,它们分别是Web前端及Web开发技术群(群号:262413025).JS及Web前端技术群(群号:35079861)和Web服务端技术群(群号:3414 ...

  7. JavaScript思维导图—DOM基本操作

    JavaScript思维导图-来自@王子墨http://julying.com/blog/the-features-of-javascript-language-summary-maps/ DOM基本 ...

  8. 厚积薄发,拥抱 .NET 2016

    厚积薄发这个词是高三英语老师在高考前写在黑板上,高中三年努力这么久,是时候迎面而上,冲刺向前.所以,一想到.NET 2016,脑海里蹦出的第一个词就是它. .NET 2016 是 .NET 一次质的飞 ...

  9. Redis批量删除KEY的方法

    Redis 中有删除单个 Key 的指令 DEL,但好像没有批量删除 Key 的指令,不过我们可以借助 Linux 的 xargs 指令来完成这个动作. 代码如下: redis-cli keys “* ...

  10. Java-面向对象基础练习

    1.编写一个Java应用程序,该应用程序包括2个类:Print类和主类E.Print 类里有一个方法output()功能是输出100 ~ 999之间的所有水仙花数(各位数字的 立方和等于这个三位数本身 ...