QML的使用

0、相关博客

【官方】Qt Quick
QML 三言两语
一套酷炫的QtQuick/Qml基础库和示例【TaoQuick-master】
QmlFlightInstruments

ChartJs2QML
RadialBarDemo

360qml: 使用qml实现的360主界面

qml-rules

QML绘图的三种方式
【Qt5】qmlplotting 【Qt6】QtQuickPlotScene


MDPlot

QmlComponentGallery

1. 概述

1.1 程序框架

程序是通过qmlscene.exe来运行qml文件。

//main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>

int main(int argc char *argv[])
{
	QCoreApplication app(argc,argv);
	QQmlApplicationEngin engin;
	const QUrl url(QStringLiteral("qrc:/main.qml"));
	//const QUrl url(QStringLiteral("file///D:/project/learqml/main.qml"));
	QObject::connect(&engin, &QQmlApplicationEngin::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl){
		if(!obj && url == objUrl)
			QCoreApplication::exit(-1);
	},Qt::QueuedConnection);

	return app.exec();
}

main.qml

//main.qml 每行可用;也可不用;   “on+信号”槽函数
//===类型值判断  ==只判断值
import QtQuick 2.12
import QtQuick.Controls 2.5

ApplicationWindow{
	id:window
	visible:true
	width:640
	height:480
	title:qsTr("Tabs")
	property int name: 1  //变量
	fuction aaa() {
		//consol.log("123");
		consol.log(name);
	}

	Button{
		id:button1
		x:200
		y:200
		text:qsTr("Test")
		icon.source: "qrc:/icon/up.png"
		//icon.source: "file:D:/pic/icon/up.png"
		onClicked:{
			console.log("1234");			
		}
		onDoubleClicked: aaa()
	}
}
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controlsf 2.15
import QtQuick.Layouts 1.15

Window{
	width:640
	height:480
	visible:true
	title:"hello world"
	title:qsTr("Hello World")

	Item{
		id:root
		anchors.fill:parent
		Grid{
			id:grid
			columns:3
			Rectangle{color:"red";width:50;height:50}
			Rectangle{color:"green";width:50;height:50}
			Rectangle{color:"blue";width:50;height:50}
			Component.onCompleted:{
				consol.log(grid.x, ' ',grid.y)
			}
		}
		Button{
			text:"click me"
			onClicked:{
				console.log('btn clicked')
			}		
		}
	}
}

2. qml中使用c++

qml和Qt c++交互

有两种方式:

  • 1、导出类 :将c++的类注册到元qml元对象系统中,在QML中创建该类的对象
  • 2、导出环境:在c++构造一个带有qml上下文属性的对象,在QML中直接使用该对象

1、 导出类
导出类必须是继承自QObject的,然后注册QML类型、引入所注册类型,作为一个数据类型使用

//c++文件中
#include <QtQml>
qmlRegisterType<MySliderItem>("com.mycompany.qmlcomponents", 1, 0, "Slider");//第4个参数(qml中对应的类名)首字母必须大写,
//qml文件中
import com.mycompany.qmlcomponents 1.0
Slider {undefined	
}

2、导出环境


#include <QtGui/QGuiApplication>
#include "qtquick2applicationviewer.h"
#include <QtQml>
#include "colorMaker.h" 
int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv); 
    QtQuick2ApplicationViewer viewer;  
    //堆上分配了一个 ColorMaker 对象,然后注册为 QML 上下文的属性,起了个名字就叫 colorMaker   
    viewer.rootContext()->setContextProperty("colorMaker", new ColorMaker);    
    viewer.setMainQmlFile(QStringLiteral("qml/colorMaker/main.qml"));
    viewer.showExpanded();
 
    return app.exec();
}

在 main.qml 中不需要 import 语句,导出的属性可以直接使用,与属性关联的对象,它的信号、槽、可调用方法(使用 Q_INVOKABLE 宏修饰的方法)、属性都可以使用,只是不能通过类名来引用枚举值了。

3. c++中使用qml

QML 与 C++ 混合编程详解

//查找子对象的指针
QPushButton *button = parentWidget->findChild<QPushButton *>("button1");

新建一个 callQml ,添加 changeColor.h 、 changeColor.cpp 两个文件。

//main.qml 内容如下:
import QtQuick 2.0
import QtQuick.Controls 1.1 
Rectangle {
    objectName: "rootRect";
    width: 360;
    height: 360;
    Text {
        objectName: "textLabel";
        text: "Hello World";
        anchors.centerIn: parent;
        font.pixelSize: 26;
    } 
    Button {
        anchors.right: parent.right;
        anchors.rightMargin: 4;
        anchors.bottom: parent.bottom;
        anchors.bottomMargin: 4;
        text: "quit";
        objectName: "quitButton";
    }
}
//main.cpp
#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)
    {
        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(255,0,0));
        bRet = QMetaObject::invokeMethod(textLabel, "doLayout");
        qDebug() << "call doLayout return - " << bRet;
    }
 
    return app.exec();
}

4. GUI程序中嵌入qml

在Qt Gui程序中嵌入qml界面
在Qt Gui中嵌入QML(old)
QML嵌入到QWidget中方法(两种)

1.qml 文件import QtQuick 2.0
  	QQuickView *view = new QQuickView;
   	view->setSource(QUrl::fromLocalFile("myqmlfile.qml"));
   	view->show();
2.qml 文件import QtQuick 1.0
	QDeclarativeView *view = new QDeclarativeView;
 	view->setSource(QUrl::fromLocalFile("myqmlfile.qml"));
 	view->show();

可以用qquickwidget载入qml文件,集成到现有的widget项目中,我下面这两个app就是qml写的camera,其他都是widget。交互还是很方便的。

	QQmlEngine *engine = ui->quickWidget->engine();
    QQmlContext *context = engine->rootContext();
    context->setContextProperty("appPath", QUIHelper::appPath());
    context->setContextProperty("appName", QUIHelper::appName());
    QObject *obj = (QObject *)ui->quickWidget->rootObject();
    QMetaObject::invokeMethod(obj, "setOrientation", Q_ARG(QVariant, -90));
    connect(obj, SIGNAL(receiveImage()), this, SLOT(receiveImage()));
    connect(this, SIGNAL(snap()), obj, SLOT(snap()));
    connect(this, SIGNAL(select()), obj, SLOT(select()));

5. SceneGraph

玩转QtQuick(1)-SceneGraph场景图简介
玩转QtQuick(2)-默认渲染器
【官方】Qt Quick Scene Graph
【官方】QSGNode Class
Qt Quick Scene Graph 学习1:画线
Qt Quick实现的涂鸦程序
Qml组件化编程7-自绘组件
QML核心渲染类说明(好)

  SceneGraph是Qml基于GPU实现的一套渲染框架,使用QSG功能,将自定义渲染直接加入SceneGraph框架的渲染流程,无疑是性能最优的。不过问题在于,这些QSG有点难以使用。需要有一定的OpenGL或DirectX相关图形学知识,并理解SceneGraph的节点交换机制,才能用好。而懂OpenGL的人,有更好的选择,就是直接使用OpenGL的API。
  QSG使用方式是在QQuickItem的子类中,重载updatePaintNode函数:

QSGNode *TaoItem::updatePaintNode(QSGNode *node, UpdatePaintNodeData *)
{
    QSGSimpleRectNode *n = static_cast<QSGSimpleRectNode *>(node);
    if (!n) {
        n = new QSGSimpleRectNode();
        n->setColor(Qt::red);
    }
    n->setRect(boundingRect());
    return n;
}

  需要注意的是:updatePaintNode()函数虽然是在渲染线程中执行的,但此时主线程也阻塞了,故此函数内主要是绘制,而数据处理尽量放在其他的Node里。(具体见渲染流程)

The main thread is blocked while this function is executed so it is safe to read values from the QQuickItem instance and other objects in the main thread.
If no call to QQuickItem::updatePaintNode() result in actual scene graph changes, like SGNode::markDirty() or adding and removing nodes, then the underlying implementation may decide to not render the scene again as the visual outcome is identical.
Warning: It is crucial that OpenGL operations and interaction with the scene graph happens exclusively on the render thread, primarily during the QQuickItem::updatePaintNode() call. The best rule of thumb is to only use classes with the “QSG” prefix inside the QQuickItem::updatePaintNode() function.
Warning: This function is called on the render thread. This means any QObjects or thread local storage that is created will have affinity to the render thread, so apply caution when doing anything other than rendering in this function. Similarly for signals, these will be emitted on the render thread and will thus often be delivered via queued connections.

在这里插入图片描述

QML绘图的三种方式
  Qt Quick 里不只 Canvas 可以自绘,绘图方式有:(1)可以使用原始的 OpenGL(Qt Quick 使用 OpenGL 渲染),(2)可以构造QSGNode 来绘图,(3)可以使用 QPainter (QQuickPaintedItem)。
  Qt Quick 的核心是 Scene Graph , Scene Graph 的设计思想和QGraphicsView/QGraphicsScene 框架类似,一个场景,很多图元往场景里放。不同之处是 Item 的绘制,(1) QGraphicsView 框架里是通过 View 的绘图事件来驱动 Item 的绘制,QGraphicsItem 有一个 paint() 虚函数,只要你从 QGraphicsItem 继承来的 Item 实现这个 paint() 函数,就可以往 QPaintDevice 上绘制了,逻辑直接;(2)而 Qt Quick 的绘制,其实另有一个渲染线程, Scene 里的 Item 没有 paint() 这种直观的绘图函数,只有一个 updatePaintNode() 方法让你来构造你的 Item 的几何表示,当程序轮转到渲染循环时,渲染循环把所有 Item 的 QSGNode 树取出来绘制。updatePaintNode() 这种绘制的方式很不直观,它来自 OpenGL 或者 Direct 3D 的绘图模式:你构造图元的几何表示,别人会在某一个时刻根据你提供的材料帮你绘制,就像你扔一袋垃圾到门口,过一阵子有人会来帮你收走这种感觉。
  用惯 Qt Widgets 和 QPainter 的开发者可能会不适应这种方式,所以 Qt Quick 提供了一种兼容老习惯的方式:引入 QQuickPaintedItem ,使用 QPainter 绘制。 一般地,你可以这样理解: QQuickPaintedItem 使用 Qt Widgets 里惯常的 2D 绘图方式,将你想要的线条、图片、文字等绘制到一个内存中的 QImage 上,然后把这个 QImage 作为一个 QSGNode 放在那里等着 Qt Quick 的渲染线程来取走它,把它绘制到实际的场景中。按照这种理解, QQuickPaintedItem 会多个绘图步骤,有性能上的损失!不过为了开发方便,有时候这一点点性能损失是可以承受的——只要你的应用仍然可以流畅运行。

Qt中的自绘方案有这么一些:

QWidget+QPainter / QQuickPaintedItem+QPainter
Qml Canvas
Qml Shapes
QOpenGLWidget / QOpenGLWindow
Qml QQuickFrameBufferObject
Qml SceneGraph
Qml ShaderEffect
QVulkanWindow

5.1 渲染

用QSG_RENDER_LOOP环境变量可指定用渲染方式。
一种是在QtCreator项目选项卡中设置运行环境变量,另一种是代码设置,在main()的最开始,要在QApplication初始化之前,加上:

qputenv("QSG_RENDER_LOOP", "basic");	//basic windows threaded

There are three render loop variants available: basic, windows, and threaded. Out of these, basic and windows are single-threaded, while threaded performs scene graph rendering on a dedicated thread. Qt attempts to choose a suitable loop based on the platform and possibly the graphics drivers in use. When this is not satisfactory, or for testing purposes, the environment variable QSG_RENDER_LOOP can be used to force the usage of a given loop. To verify which render loop is in use, enable the qt.scenegraph.general logging category.

5.1.1 Threaded Render Loop (‘threaded’)

5.1.2 Non-threaded Render Loop (‘basic’)

自定义节点通过继承QQuickItem类,重写QuickItem::updatePaintNode(),并且设置 QuickItem::ItemHasContents 标志的方式,添加到“场景图”。
警告:至关重要的是, 原生图形(OpenGL,Vulkan,Metal等)操作以及与“场景图”的交互只能在渲染线程中进行,主要在updatePaintNode()调用期间进行。经验法则是仅在QuickItem::updatePaintNode()函数内使用带有“QSG”前缀的类。

6. QML多线程

QML多线程魔法:探索不同方法,提升性能

7. TabBar

Qml底部导航 Github下载
qtquickexamples

8.常用属性

属性进行关联绑定时,在经过赋值后绑定也就解除了。

anchors.fill:parent
focus:true
KeyNavigation.Tab:NextEdit
Keys.onSpacePressed:{consol.log("text is space")}
gridient:Gridient{
	GrideientStop:{position:0.0;color:'green'}
	GrideientStop:{position:1.0;color:'red'}
}
color:Qt.rgba(Math.random(),Math.random(),Math.random(),1)	//js随机颜色
color:"#303030"
font.family:"Ubuntu"
font.pixelSize:22
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
QML是一种用于创建用户界面的声明性编程语言,通过它可以简单而强大地创建交互式界面。而qcustomplot是基于Qt的一个绘图库,它提供了丰富的绘图功能,可以轻松地绘制各种类型的图表。 在QML使用qcustomplot可以通过以下几个步骤进行: 1. 引入qcustomplot库:首先需要将qcustomplot的库文件导入到QML项目中。可以将qcustomplot所在的文件夹复制到项目的源文件目录中,并在项目文件中添加相应的引用。 2. 创建QCustomPlot组件:在QML文件中,创建一个QCustomPlot组件用于显示绘图内容。可以将它放置在界面的任意位置,并设置其大小和样式。 3. 添加数据:使用QML中的绑定语法,将要绘制的数据传递给QCustomPlot组件。可以使用JavaScript数组或对象表示数据,并将其绑定到QCustomPlot的相应属性上。 4. 绘制图表:根据需要,通过设置QCustomPlot的属性和方法来自定义图表的样式和布局。可以设置图表的标题、坐标轴、网格线、数据点等属性,以及调整图表的大小和位置。 5. 处理交互:qcustomplot支持用户的交互操作,如鼠标点击、拖拽、缩放等。可以通过在QML文件中捕捉相应的事件,并调用qcustomplot提供的方法来实现交互功能。 通过上述步骤,就可以在QML中成功地使用qcustomplot进行绘图。在绘制图表时,可以根据具体需求进行进一步的定制和优化,以满足特定的界面需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值