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集合框架源码剖析系列博客是因为自己反思了一下阿里内推一面的失败(估计没过,因为写此博客已距阿里巴巴一面一个星期),当时面试完之后感觉自己回答的挺好的,而且据面试官最后说的这几 ...
随机推荐
- HBase的二级索引
使用HBase存储中国好声音数据的案例,业务描述如下: 为了能高效的查询到我们需要的数据,我们在RowKey的设计上下了不少功夫,因为过滤RowKey或者根据RowKey查询数据的效率是最高的,我们的 ...
- djiango-异步发送邮件--celery
安装 pip install celery==4.2.0 # celery4.x支持django1.11以上版本 试了好几个版本 就4.2.0能发送成功 1.项目目录里新建一个celery的包cele ...
- git工具免密拉取、推送
很苦恼每次都要配置明文密码才能正常工作 其实也可以配置成非明文 打开控制面板 →用户账号 管理 Windows凭证 对应修改响应网址即可
- This content should also be served over HTTPS
HTTPS 是 HTTP over Secure Socket Layer,以安全为目标的 HTTP 通道,所以在 HTTPS 承载的页面上不允许出现 http 请求,一旦出现就是提示或报错: jqu ...
- 关于windbg报错"No symbols for ntdll. Cannot continue."问题
最近我写个例子程序研究下某个异常情况,故意制造了个崩溃.然后分析dmp文件. 当我执行!address -summary命令想观察下进程当前内存情况时,去报如下错误: 0:000> !addre ...
- Omnibus 安装
使用gem gem install omnibus 说明 可能需要配置gem source ,通过 gem source list 可以进行检查 参考如下: gem source -r https ...
- Centos 不重启 修改ulimit参数
1. 查看limits.conf文件 cat /etc/security/limits.conf 2. 打开编辑limits.conf文件 sudo vim /etc/security/limits. ...
- CF1172E Nauuo and ODT
CF1172E Nauuo and ODT 神仙题orz 要算所有路径的不同颜色之和,多次修改,每次修改后询问. 对每种颜色\(c\)计算多少条路径包含了这个颜色,不好算所以算多少条路径不包含这个颜色 ...
- 18年今日头条笔试第一题题解:球迷(fans)
其实本题是加强版,原数据是100*100的,老师为了尊重我们的智商加成了3000*3000并进行了字符串处理…… 上原题~ 球迷 [问题描述] 一个球场C的球迷看台可容纳M*N个球迷.官方想统计一共有 ...
- 【算法编程 C++ Python】字符串替换
题目描述 请实现一个函数,将一个字符串中的空格替换成“%20”.例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy. C++使用string,pyt ...