Qt5 QtQuick系列----QtQuick的Secne Graph剖析(2)--自定义QML类型 (继承QQuickItem)
“当下即永恒” --- 佚名
Qt用户可以方便地使用QML中的Rectangle等基本类型,但是当不够用时,或,需要开发更高级的界面时,可以自己定义QML类型。
自定义QML类型需要继承自QQuickItem类,首先,需要了解这个类:http://doc.qt.io/qt-5/qquickitem.html 官方文档讲得很清楚:
“The QQuickItem class provides the most basic of all visual items in Qt Quick.
All visual items in Qt Quick inherit from QQuickItem. Although a QQuickItem instance has no visual appearance, it defines all the attributes that are common across visual items, such as x and y position, width and height, anchoring and key handling support.
You can subclass QQuickItem to provide your own custom visual item that inherits these features.”
QML中的Item元素与C++中的QQuickItem类对应。
基本上所有的基本qml类型都可以通过用户继承QQuickItem来自己实现吧。实现自定义qml类型,需要注意以下几点:
函数的作用:允许你自己在函数内部定义QSGNode结构,允许你自己定义一个subtree,最后返回这个subtree的根节点。 在显示qml到屏幕的流程中(参考我的博文:https://blog.csdn.net/qq_35865125/article/details/86485008 ),qml最终会被转换成一个树,树的节点是QSGNode类型的,对于已经存在的qt给我们定义的qml基本类型,例如Rectangle,它们应该也是通过调用自己的updatePainNode来实现将自己转换成QSGNode的,只不过是qt公司的人帮我们写好了,这里我们自己定义节点的话,就需要自己实现这个函数了。另外,这个函数返回的QSGNode*是会被自动加入到一个更大的树结构中的。例如,你自己实现了一个类型myQMLType,然后,你在文件中将其放在一个Rectangle内部,于是乎你自己定义的这个类型对应的节点就是Rectangle对应的节点的子节点了。
- 自定义的类需要继承自QQuickItem。
- 需要自己实现QQuickItem的虚函数QQuickItem::updatePaintNode

- 需要设置QQuickItem::ItemHasContents标记。
我一般在在构造函数中进行设置:setFlags(QQuickItem::ItemHasContents); 只有设置了这个标记,你自己定义的updatePainNode才可以被自动执行。


从上面两处截图可以知道,设置了标识之后,QQuickItem::update才能够被调用,这个函数会最终导致你自己实现的updatePainNode函数被调用。
4) 需要调用qmlRegisterType函数来将你自己定义的c++类型注册到QML环境中,并在qml文件中机型import才能在qml文件中直接使用。
e.g:在main函数中: qmlRegisterType<SelfDefinedQMLType>("SelfDefinedQMLType", 1, 0, "SelfDefinedQMLType");
在qml文件中: import SelfDefinedQMLType 1.0
5)要弄清楚资源清理方式:

例如,在下面我给出的例子中,如果在析构函数中调用delete QSGSimNode,会报错,应该是qt会自动处理这个资源,无需手动。
5)要认识到QQuickItem类中有很多函数的,例如QQuickItem::keyPressEvent函数,可以在你的子类中重新实现这个函数,处理按键消息。具体可以自己细看官方文档。

6) 单独的QquickItem并不能单独被显示,需要借助QquickWindow来显示。--一个qml文件中包含很多个Rectangle,text等基本组件,它们对应的C++类都继承自quick的最基本类:QQuickItem,这些个qml文件中的控件被组织成一个树结构,树的每个节点的类型都可以看成是QQuickItem,然后,这个树由 QquickWindow负责显示出来,主要是 通过调用底层opengl渲染出来(渲染的过程一般是一个单独的线程。)::

请看下面的一个我的例子:(或许官网上还有其他更好的例子)
网盘:
自定义的类,头文件:
#ifndef SELFDEFINEDQMLTYPE_H
#define SELFDEFINEDQMLTYPE_H
#include <QSGSimpleRectNode>
#include <QtQuick/QQuickItem>
class SelfDefinedQMLType: public QQuickItem
{
Q_OBJECT
public:
SelfDefinedQMLType();
~SelfDefinedQMLType();
Q_INVOKABLE void changeColor();
protected:
QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *);
void keyPressEvent(QKeyEvent *event);
private:
QSGSimpleRectNode* QSGSimNode;
};
#endif // SELFDEFINEDQMLTYPE_H
自定义的类,cpp:
#include "SelfDefinedQMLType.h"
SelfDefinedQMLType::SelfDefinedQMLType()
{
setFlags(QQuickItem::ItemHasContents);
QSGSimNode = NULL;
//setFocus(true);
qDebug()<<"SelfDefinedQMLType::SelfDefinedQMLType() was called!";
}
SelfDefinedQMLType::~SelfDefinedQMLType()
{
qDebug() << "SelfDefinedQMLType::~SelfDefinedQMLType start";
if(QSGSimNode)
{
//Must comment the following, otherwise, there will be an error!
//seems that the qt can handle resource itself.
//delete QSGSimNode;
}
qDebug() << "SelfDefinedQMLType::~SelfDefinedQMLType end";
}
void SelfDefinedQMLType::changeColor()
{
if (!QSGSimNode) {
if( QColor(255, 0, 0, 127) == QSGSimNode->color() )
QSGSimNode->setColor(QColor(255, 0, 0, 127));
else
QSGSimNode->setColor(QColor(0, 255, 0, 127));
}
}
QSGNode *SelfDefinedQMLType::updatePaintNode(QSGNode *node, UpdatePaintNodeData *)
{
//define a rectangle:
QSGSimNode = static_cast<QSGSimpleRectNode *>(node);
if (!QSGSimNode) {
QSGSimNode = new QSGSimpleRectNode();
QColor myColor = QColor(255, 0, 0, 127);
QSGSimNode->setColor(myColor);
QSGSimNode->setRect(10,10,400,400);
}
return QSGSimNode;
}
//why: this func can not be activated, even add "setFocus(true);" in SelfDefinedQMLType::SelfDefinedQMLType()
void SelfDefinedQMLType::keyPressEvent(QKeyEvent *event)
{
if(Qt::Key_Left == event->key())
changeColor();
}
main.qml
import QtQuick 2.11
import QtQuick.Window 2.11
import SelfDefinedQMLType 1.0
import QtQuick 2.4
import QtQuick.Layouts 1.2
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
Window {
id:windowTop
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Rectangle{
id:rect1
x:0
y:0
visible: true
anchors.fill: parent
color: "steelblue"
Keys.enabled: true
focus: true
SelfDefinedQMLType{
id:selfDefined
}
Keys.onPressed: {
switch(event.key)
{
case Qt.Key_Left:
console.log("Qt.Key_Left was pressed!!!")
//don't know why,the following repor error, during execution.
selfDefined.changeColor()//Error:TypeError: Cannot call method 'changeColor' of null
break;
}
}
}
}
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "SelfDefinedQMLType.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
qmlRegisterType<SelfDefinedQMLType>("SelfDefinedQMLType", 1, 0, "SelfDefinedQMLType");
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
例子中,还有一些点需要继续探索:
- 重新实现的继承自QQuickItem类的void keyPressEvent函数并没有被触发,需要进一步看资料。
- 在main.qml中调用selfDefined.changeColor()时,会报错:TypeError: Cannot call method 'changeColor' of null,为什么找不到对象selfDefined呢,可能是将这个类放在qml中使用时有些地方需要注意。最好的方式是,看一下qt源码中的QQuickRectangle是如何实现的。
Qt5 QtQuick系列----QtQuick的Secne Graph剖析(2)--自定义QML类型 (继承QQuickItem)的更多相关文章
- Qt5 QtQuick系列----QtQuick的Secne Graph剖析(1)
教是言词, 实不是道,道本无言, 言说是妄.------- 达摩 Qt 5提出了一个新的渲染底层,以替代Qt4时期的Graphics View,这个渲染底层就是Scene Graph.Scene Gr ...
- Qt5 QtQuick系列----QtQuick的Secne Graph剖析(3)-- qml与OpenGl结合
我读的书愈多,就愈亲近世界,愈明了生活的意义,愈觉得生活的重要. -- 高尔基 需要先看:https://blog.csdn.net/qq_35865125/article/details/86485 ...
- 【java集合框架源码剖析系列】java源码剖析之TreeSet
本博客将从源码的角度带领大家学习TreeSet相关的知识. 一TreeSet类的定义: public class TreeSet<E> extends AbstractSet<E&g ...
- 【java集合框架源码剖析系列】java源码剖析之HashSet
注:博主java集合框架源码剖析系列的源码全部基于JDK1.8.0版本.本博客将从源码角度带领大家学习关于HashSet的知识. 一HashSet的定义: public class HashSet&l ...
- Gradle学习系列之九——自定义Task类型
在本系列的上篇文章中,我们学习了多Project构建,在本篇文章中,我们将学到如何自定义Task类型. 请通过以下方式下载本系列文章的Github示例代码: git clone https://git ...
- 【java集合框架源码剖析系列】java源码剖析之TreeMap
注:博主java集合框架源码剖析系列的源码全部基于JDK1.8.0版本.本博客将从源码角度带领大家学习关于TreeMap的知识. 一TreeMap的定义: public class TreeMap&l ...
- 【java集合框架源码剖析系列】java源码剖析之ArrayList
注:博主java集合框架源码剖析系列的源码全部基于JDK1.8.0版本. 本博客将从源码角度带领大家学习关于ArrayList的知识. 一ArrayList类的定义: public class Arr ...
- 【java集合框架源码剖析系列】java源码剖析之LinkedList
注:博主java集合框架源码剖析系列的源码全部基于JDK1.8.0版本. 在实际项目中LinkedList也是使用频率非常高的一种集合,本博客将从源码角度带领大家学习关于LinkedList的知识. ...
- 【java集合框架源码剖析系列】java源码剖析之HashMap
前言:之所以打算写java集合框架源码剖析系列博客是因为自己反思了一下阿里内推一面的失败(估计没过,因为写此博客已距阿里巴巴一面一个星期),当时面试完之后感觉自己回答的挺好的,而且据面试官最后说的这几 ...
随机推荐
- 利用GitHub+Node.js+Hexo搭建个人博客
本篇是自己在搭建Hexo博客平台时的一个过程记录.(2019.9.13实测有效) GitHub 账号注册 因为此文所搭建的个人博客是基于GitHub平台服务的,所以首先是注册GitHub,当然已有账号 ...
- create系列创建节点的方法
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- svn服务的安装与设置 .
1. 下载svn软件并安装,本人使用的是如下软件: TortoiseSVN-1.6.5.16974-win32-svn-1.6.5 Vis ...
- 用于未处理异常错误的.NET框架清理工具
当你启动某些程序时,会收到与此错误类似的未处理异常错误:Unhandled e0434f4dh exception at 7c81eb33h.此问题是由于.NET框架未正确安装或.NET框架系统中的另 ...
- PHP生成随机数;订单号唯一
//8-12位随机数 function makeRand($num=){ $strand = (; if(strlen($strand)<$num){ $strand = str_pad($st ...
- 51 NOD 1239 欧拉函数之和(杜教筛)
1239 欧拉函数之和 基准时间限制:3 秒 空间限制:131072 KB 分值: 320 难度:7级算法题 收藏 关注 对正整数n,欧拉函数是小于或等于n的数中与n互质的数的数目.此函数以其首名研究 ...
- HTML5之图片在Retina屏的常用几种处理方式
Media Queries使用css3的媒体查询实现高清屏的图片处理. @media only screen and (-webkit-min-device-pixel-ratio: 1.5), on ...
- vue Uncaught SyntaxError: Unexpected token < 报错
这个问题是因为项目中出现没有闭合的标签,如<img src=""> 需改成<img src="xxx.png"/>
- K8S组件
Master 组件 Master组件提供集群的管理控制中心.Master组件可以在集群中任何节点上运行.但是为了简单起见,通常在一台VM/机器上启动所有Master组件,并且不会在此VM/机器上运行用 ...
- hdu1501 Zipper[简单DP]
目录 题目地址 题干 代码和解释 参考 题目地址 hdu1501 题干 代码和解释 最优子结构分析:设这三个字符串分别为a.b.c,如果a.b可以组成c,那么c的最后一个字母必定来自a或者b的最后一个 ...