QML学习及实战

QML学习及实战(更多内容)

创建项目

  1. 在这里插入图片描述

  2. 在这里插入图片描述

3.在这里插入图片描述

剩下的就是一路下一步即可

添加静态资源——图片

  1. 在这里插入图片描述

  2. 在这里插入图片描述

  3. 添加之后完成之后的路径

    在这里插入图片描述

案列 || demo

可以参考的资料:https://github.com/gongjianbo/MyTestCode/blob/master/README.md

1. 文本省略号

Text {width: 100text: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"elide: Text.ElideRight
}

文字省略制作文本气泡全显示,是十分重要的

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.12Window {visible: truewidth: 640height: 480title: qsTr("Hello World")TextMetrics{id: textMetricselide: Text.ElideRightelideWidth: 600text: "Negativnsets to place a shadow outside the popup's boundaries:"}//文字显示缩略TextArea {id: referMessagecolor: "#000000"anchors.top: parent.topanchors.topMargin: 100anchors.left: parent.leftanchors.leftMargin: 100width: 300height: 90text: textMetrics.elidedText //文字缩略font.pixelSize: 14font.weight: Font.LightwrapMode: TextArea.WrapAnywherereadOnly: trueverticalAlignment: Text.AlignVCenterfocusReason: Qt.MouseFocusReasontextFormat: TextArea.AutoTextbackground: Rectangle {anchors.fill: parentcolor: "#ffff00"}}Component.onCompleted:{console.log("str=====", textMetrics.elidedText)}
}

2. Canvas画圆角

针对项目当中要有矩形中不同地方的圆角,这样就需要使用 Canvas来进行绘制一下就是针对圆角的绘制

import QtQuick
import QtQuick.Controls 2.15Window {visible: truewidth: 1000height: 900Canvas {id: canvasanchors.fill: parentonPaint: {var ctx = getContext("2d");// 渐变色的设置var gradient = ctx.createLinearGradient(x,y+height,x+width,y+height)gradient.addColorStop(0.0, "#191919")gradient.addColorStop(1.0, "#272829")var x = 50;var y = 50;var width = 200;var height = 100;var cornerSize = 20;// 左下// ctx.beginPath();// ctx.moveTo(x + cornerSize, y);// ctx.lineTo(x + width, y);// ctx.lineTo(x + width, y + height);// ctx.arcTo(x + width, y + height, x + width - cornerSize, y + height, cornerSize);// ctx.lineTo(x + cornerSize, y + height);// ctx.arcTo(x, y + height, x, y + height - cornerSize, cornerSize);// ctx.lineTo(x, y + cornerSize);// ctx.lineTo(x, y);// ctx.closePath();// 带圆角的矩形// ctx.beginPath();// ctx.moveTo(x + cornerSize, y);// ctx.arcTo(x + width, y, x + width, y + cornerSize, cornerSize);//右上// ctx.lineTo(x + width, y + height - cornerSize);// ctx.arcTo(x + width, y + height, x + width - cornerSize, y + height, cornerSize);//右下// ctx.lineTo(x + cornerSize, y + height);// ctx.arcTo(x, y + height, x, y + height - cornerSize, cornerSize);//左下// ctx.lineTo(x, y + cornerSize);// ctx.arcTo(x, y, x + cornerSize, y, cornerSize);// 左上// ctx.closePath();// 右上+左上// ctx.beginPath();// ctx.moveTo(x + cornerSize, y);// ctx.arcTo(x + width, y, x + width, y + cornerSize, cornerSize);//右上// ctx.lineTo(x + width, y + height);// ctx.lineTo(x + cornerSize, y + height);// ctx.lineTo(x, y + height);// ctx.arcTo(x, y, x + cornerSize, y, cornerSize);// 左上// ctx.closePath();// 右下ctx.beginPath();ctx.moveTo(x + cornerSize, y);ctx.lineTo(x + width, y);ctx.lineTo(x + width, y + height - cornerSize);ctx.arcTo(x + width, y + height, x + width - cornerSize, y + height, cornerSize);//右下ctx.lineTo(x + width, y + height);ctx.lineTo(x, y + height);ctx.lineTo(x, y);ctx.closePath();ctx.fillStyle = gradient;ctx.strokeStyle = 'transparent';// 边框ctx.fill();ctx.stroke();}}
}

3. 关闭按钮

import QtQuick
import QtQuick.Controls 2.15Window {width: 640height: 480visible: truetitle: qsTr("Hello World")Canvas {id: canvasanchors.fill: parentonPaint: {var ctx = getContext("2d");// 定义矩形位置和大小var rectX = 0;var rectY = 0;var rectWidth = 59;var rectHeight = 59;// 定义圆弧半径var arcRadius = 8;// 计算圆弧位置var arcX = rectX + rectWidth;//109var arcY = rectY// 50var arcStartX = arcX + arcRadius;//117var arcStartY = rectY;//50var arcEndX = arcStartX; //117var arcEndY = arcStartY + arcRadius;// 58rconsole.log(arcX,arcY,arcStartX,arcStartY,arcEndX,arcEndY)// 绘制矩形ctx.fillStyle = "#000000";// 绘制右上角圆弧ctx.beginPath();ctx.moveTo(rectX, rectY);// 50 50ctx.lineTo(arcX, arcY);// 109 50ctx.arcTo(arcStartX, arcStartY, arcEndX, arcEndY, arcRadius);ctx.lineTo(arcEndX, arcEndY);ctx.lineTo(arcEndX, rectY + rectHeight);ctx.lineTo(rectX, rectY + rectHeight);ctx.closePath();ctx.fill();// 计算 X 图标的位置var xIconSize = 20;var xIconX = rectX + 3 + (rectWidth - xIconSize) / 2;var xIconY = rectY + (rectHeight - xIconSize) / 2;// 绘制 X 关闭图标ctx.beginPath();ctx.moveTo(xIconX, xIconY);ctx.lineTo(xIconX + xIconSize, xIconY + xIconSize);ctx.moveTo(xIconX + xIconSize, xIconY);ctx.lineTo(xIconX, xIconY + xIconSize);ctx.strokeStyle = Qt.rgba(255, 255, 255, 0.7);ctx.lineWidth = 3;ctx.stroke();}}
}

在这里插入图片描述

4. QT 进度条放gif

#include <QApplication>
#include <QProgressBar>
#include <QPropertyAnimation>
#include <QPixmap>
#include <QMovie>
#include <QLabel>int main(int argc, char *argv[])
{QApplication a(argc, argv);QProgressBar progressBar;QLabel label(&progressBar);QMovie movie(":/tenor-1.gif");  // 从资源中加载 GIF 图片label.setMovie(&movie);movie.start();progressBar.show();return a.exec();
}

效果就是导航栏上放一个gif图片的动态效果,当然加载 gif的相关东西也是可以参考;

5. QT进度条加入css属性

#include <QApplication>
#include <QProgressBar>
#include <QTimer>int main(int argc, char *argv[])
{QApplication a(argc, argv);QProgressBar progressBar;progressBar.setRange(0, 100); // 设置进度条范围为 0 到 100QTimer timer;int progress = 0;// 每隔一段时间更新进度条的值,模拟加载过程QObject::connect(&timer, &QTimer::timeout, [&](){progress += 1;progressBar.setValue(progress);if (progress >= 100) {timer.stop();}});timer.start(100); // 每100毫秒更新一次进度条// 设置进度条的样式,使其具有流动的效果progressBar.setStyleSheet("QProgressBar { border: 2px solid grey; border-radius: 5px; text-align: center; }""QProgressBar::chunk { background-color: #37c9e1; width: 20px; margin: 1px; }");progressBar.show();return a.exec();
}

在这里插入图片描述

6. 鼠标右击

点击鼠标右键,弹出框,做选择

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.12Window {visible: truewidth: 640height: 480title: qsTr("Hello World")Rectangle {width: 200height: 200color: "lightblue"MouseArea {anchors.fill: parentacceptedButtons: Qt.RightButtononClicked: {menu.popup()}}Menu {id: menuMenuItem {text: "Option 1"onTriggered: {console.log("Option 1 selected")}}MenuItem {text: "Option 2"onTriggered: {console.log("Option 2 selected")}}}}
}

在这里插入图片描述

属性

implicitWidth

是指一个组件在没有显示设置宽度所具有的默认宽度。

Item {property alias icon: image.sourceproperty alias label: text.textimplicitWidth: text.implicitWidth + image.implicitWidthimplicitHeight: Math.max(text.implicitHeight, image.implicitHeight)Image { id: image }Text {id: textwrapMode: Text.Wrapanchors.left: image.right; anchors.right: parent.rightanchors.verticalCenter: parent.verticalCenter}}

vision

qml当中的vision表示当前组件的可见性,当为 false的时候只是表示当前组件不显示,但是当前组件在布局中还是存在的;(相当于vue中的 v-show

  • 在 QML 中,要实现类似 Vue.js 中 v-if 的功能,即根据条件动态创建或销毁组件,可以使用 Loader 组件。Loader 组件可以根据条件动态加载指定的 QML 组件,并在不需要时卸载该组件,从而实现类似 v-if 的效果。
  • 以下是一个简单的示例,演示如何在 QML 中使用 Loader 实现类似 v-if 的功能
import QtQuick 2.15
import QtQuick.Controls 2.15Item {width: 200height: 200property bool showComponent: falseLoader {id: componentLoadersourceComponent: showComponent ? componentA : null}Component {id: componentARectangle {width: 100height: 100color: "red"}}Button {text: "Toggle Component"onClicked: showComponent = !showComponent}
}
  • 在上面的示例中,我们定义了一个 Loader 组件,根据 showComponent 属性的值来加载或卸载 componentA 组件。当 showComponent 为 true 时,componentA 被加载并显示;当 showComponent 为 false 时,componentA 被卸载。
  • 通过点击按钮,可以动态切换 showComponent 属性的值,从而实现类似 v-if 的效果。
  • 这种方法可以让你在 QML 中根据条件动态加载组件,实现类似于 Vue.js 中 v-if 的功能。

Overlay

  • Overlay QML类型是用于在其子项之上显示另一组子项的布局类型。Overlay的子项会覆盖在其它子项之上,可以用于创建浮动窗口、弹出菜单等效果。

qml之ShaderEffectSource获取控件快照

ShaderEffectSourcegrabToImage的大致区别:
grabToImage接口可以提取出图像,但是这个需要把显存中的数据复制到内存中,非常耗时,而ShaderEffectSource是完全GPU内实现,不存在拷贝到内存的开销。

  • ShaderEffectSource类型将sourceItem渲染为纹理并在场景中显示

    • hideSource:

      • 如果此属性为true,则sourceItem将被隐藏,尽管它仍将呈现到纹理中。 与通过将visible设置为false来隐藏sourceItem相反,将此属性设置为true不会阻止鼠标或键盘输入到达sourceItem。
    • live

      • ShaderEffectSource默认情况下会随着设置的Item变化而变化,设置为false渲染完一次后,就不会发生变化
    • sourceItem

      • 就是生成快照的数据源,如果live为true,则将其设置为null将释放纹理资源
import QtQuick 2.0
Window {width: 640height: 480visible: truetitle: qsTr("Hello World")Rectangle {id:id_rootwidth: 800height: 400color:"black"Rectangle {width: 400height: 200gradient: Gradient {GradientStop { position: 0; color: "white" }GradientStop { position: 1; color: "gray" }}Row {id:id_rowopacity: 1.0Item {id: foowidth: 100; height: 100Rectangle { x: 5; y: 5; width: 60; height: 60; color: "red" }Rectangle { x: 20; y: 20; width: 60; height: 60; color: "orange" }Rectangle { x: 35; y: 35; width: 60; height: 60; color: "yellow" }}}ShaderEffectSource {width: 100; height: 70anchors.horizontalCenter: id_row.horizontalCenteranchors.top: id_row.bottomsourceItem: fooopacity:0.3rotation: 0 // 快照的旋转角度format:ShaderEffectSource.Alpha //单通道(Alpha通道)//format: ShaderEffectSource.RGB //三通道//format: ShaderEffectSource.RGBA // 四通道//mipmap:true}}}}

Q_PROPERTY宏

要声明属性,需要继承QObject并使用Q_PROPERTY()宏。

Q_PROPERTY(type name(READ getFunction [WRITE setFunction] |MEMBER memberName [(READ getFunction | WRITE setFunction)])[RESET resetFunction][NOTIFY notifySignal][REVISION int][DESIGNABLE bool][SCRIPTABLE bool][STORED bool][USER bool][CONSTANT][FINAL])

在QML中访问C++,通过C++类暴露属性来使用,接上面实例如下:

  1. 新建Qt Quick工程:qt PROPERTY

  2. 新建C++类TestProperty,公有继承于QObject

  3. 为TestProperty类设置上述属性title

     Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged);
    
  4. 属性读写函数声明与实现

TestProperty.h

#ifndef TESTPROPERTY_H
#define TESTPROPERTY_H#include <QObject>class TestProperty : public QObject
{Q_OBJECT
public:explicit TestProperty(QObject *parent = nullptr);Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged);QString title();void setTitle(QString strTitle);signals:void titleChanged();public slots:private:QString     m_title;};#endif // TESTPROPERTY_H

TestProperty.cpp

#include "TestProperty.h"TestProperty::TestProperty(QObject *parent) : QObject(parent)
{}QString TestProperty::title()
{return  m_title;
}void TestProperty::setTitle(QString strTitle)
{m_title = strTitle;emit titleChanged();
}

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>#include "TestProperty.h"int main(int argc, char *argv[])
{QGuiApplication app(argc, argv);// 注册这个类,到处到qml// template<typename T>// int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName);// template<typename T, int metaObjectRevision>// int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName);qmlRegisterType<TestProperty>("TestProperty", 1, 0, "TestProperty");QQmlApplicationEngine engine;const QUrl url(QStringLiteral("qrc:/12/Main.qml"));QObject::connect(&engine,&QQmlApplicationEngine::objectCreationFailed,&app,[]() { QCoreApplication::exit(-1); },Qt::QueuedConnection);engine.load(url);return app.exec();
}

main.qml

import QtQuick 2.9
import QtQuick.Window 2.2
// 1. 导入
import TestProperty 1.0Window {visible: truewidth: 640height: 480title: qsTr("Hello Qt")// 2. 使用TestProperty{id: testPropertytitle: qsTr("Hello World")}Component.onCompleted: {title = testProperty.title;}
}

invokeMethod()

Qt元对象系统是Qt最核心的一个基础特性,元对象系统负责信号和插槽对象间通信机制、运行时类型信息和Qt属性系统。为应用程序中使用的每个QObject子类创建一个QMetaObject实例,此实例存储QObject子类的所有元信息。通过元对象系统,你可以查询QObject的某个派生类的类名、有哪些信号、槽、属性、可调用方法等信息,然后可以使用QMetaObject::invokeMethod()调用QObject的某个注册到元对象系统中的方法。

QMetaObject::invokeMethod()

QMetaObject的invokeMethod()方法用来调用一个对象的信号、槽、可调用的方法。这是一个静态方法,其函数原型如下

bool QMetaObject::invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QGenericReturnArgument ret,QGenericArgument val0 = QGenericArgument(nullptr), QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), QGenericArgument val4 = QGenericArgument(),QGenericArgument val5 = QGenericArgument(),QGenericArgument val6 = QGenericArgument(), QGenericArgument val7 = QGenericArgument(),QGenericArgument val8 = QGenericArgument(),QGenericArgument val9 = QGenericArgument())
  • 在最新的Qt5.13中,QMetaObject中的invokeMethod函数一共有五个,除上面这个以外其他都是重载函数

  • 该函数就是调用obj对象中的member方法,如果调用成功则返回true,调用失败则返回false,失败的话要么就是没有这个方法要么就是参数传入不对。

  • 参数介绍

    • 第一个参数是被调用对象的指针;

    • 第二个参数是方法的名字;

    • 第三个参数是连接类型。可以指定连接类型,来决定是同步还是异步调用。

      • 如果type是Qt :: DirectConnection,则会立即调用该成员。

      • 如果type是Qt :: QueuedConnection,则会发送一个QEvent,并在应用程序进入主事件循环后立即调用该成员。

      • 如果type是Qt :: BlockingQueuedConnection,则将以与Qt :: QueuedConnection相同的方式调用该方法,除了当前线程将阻塞直到事件被传递。使用此连接类型在同一线程中的对象之间进行通信将导致死锁。

      • 如果type是Qt :: AutoConnection,则如果obj与调用者位于同一个线程中,则会同步调用该成员; 否则它将异步调用该成员。

      • 第四个参数接收被调用函数的返回值;注意,如果调用是异步的,则无法计算返回值。

      • 注意:传入的参数是有个数限制的,可以向成员函数传递最多十个参数(val0,val1,val2,val3,val4,val5,val6,val7,val8和val9)。

QGenericArgument和QGenericReturnArgument是内部帮助程序类。由于可以动态调用信号和槽,因此必须使用Q_ARG()和Q_RETURN_ARG()宏来封装参数。Q_ARG()接受该类型的类型名称和const引用; Q_RETURN_ARG()接受类型名称和非const引用。

注意:此功能是线程安全的。

  • 调用示例
    • 假设一个对象有一个槽compute(QString,int,double),返回一个QString对象,那么调用方式如下(同步):
QString retVal;
QMetaObject::invokeMethod(obj, "compute", Qt::DirectConnection,Q_RETURN_ARG(QString, retVal),Q_ARG(QString, "sqrt"),Q_ARG(int, 42),Q_ARG(double, 9.7));
  • 假设要异步调用QThread上的quit()槽:
QMetaObject::invokeMethod(thread, "quit", Qt::QueuedConnection);

注意,要调用的类型必须是信号、槽,以及Qt元对象系统能识别的类型, 如果不是信号和槽,可以使用qRegisterMetaType()来注册数据类型。此外,使用Q_INVOKABLE来声明函数,也可以正确调用。

Q_INVOKABLE及Qt中反射的使用

  • invokeableMethod()可以调用用Q_INVOKABLE修饰过的函数。加了Q_INVOKABLE的宏注册到元对象系统里面,并且能够被元对象系统使用,普通的没有注册过的函数是不能被使用的。

案列

  • ReflectTest.h
#ifndef REFLECTTEST_H
#define REFLECTTEST_H#include <QObject>class ReflectTest : public QObject
{Q_OBJECT
public:ReflectTest(QObject *parent = nullptr);Q_INVOKABLE void setPrint(const QString &print);Q_INVOKABLE QString getPrint();Q_INVOKABLE QString testFunction(QString para);private:QString m_print;};#endif // REFLECTTEST_H

ReflectTest.cpp

#include "ReflectTest.h"ReflectTest::ReflectTest(QObject *parent) : QObject(parent)
{}void ReflectTest::setPrint(const QString &print)
{m_print = print;
}QString ReflectTest::getPrint()
{return m_print;
}QString ReflectTest::testFunction(QString para)
{return "return:" + para;
}

main.cpp

#include <QCoreApplication>
#include <QDebug>
#include <QMetaObject>
#include <QMetaMethod>
#include "ReflectTest.h"int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);ReflectTest test1;test1.setPrint("one");qDebug() << test1.getPrint();qDebug() << "----------华丽的分割线----------";int count = test1.metaObject()->methodCount();for(int i = 0; i < count; i++){qDebug() << test1.metaObject()->method(i).name();}qDebug() << "----------华丽的分割线----------";qDebug() << test1.getPrint();qDebug() << QMetaObject::invokeMethod(&test1, "setPrint", Qt::DirectConnection, Q_ARG(QString, "one+one"));QString retVal;QMetaObject::invokeMethod(&test1, "getPrint", Qt::DirectConnection, Q_RETURN_ARG(QString, retVal));qDebug() << retVal;QMetaObject::invokeMethod(&test1, "testFunction", Qt::DirectConnection, Q_RETURN_ARG(QString, retVal), Q_ARG(QString, "one+one+one"));qDebug() << retVal;return a.exec();
}

C++加载qml界面参考资料

/// 启动画面的视图
m_view = new QQuickView;
m_view->rootContext()->setContextProperty("$screenController", this);
/// 无边框
m_view->setFlags(Qt::FramelessWindowHint);
/// 背景透明
m_view->setColor(QColor(Qt::transparent));
/// 置顶启动画面
m_view->setFlags(Qt::SplashScreen | Qt::WindowStaysOnTopHint);
VLOG(Info) << "background Picture to show:" << picPath.toStdString();
const QUrl splashScreenUrl(QStringLiteral("qrc:/views/SplashScreen.qml"));
QUrl backImageSource("qrc:/imgs/SplashScreen_Background_FreeScan.png");
m_view->setInitialProperties({{"backImageSource", backImageSource}});
m_view->setSource(splashScreenUrl);
/// 设置到屏幕中心
const auto& width = m_view->width();
const auto& height = m_view->height();
const auto& screenSize = QGuiApplication::primaryScreen()->size();
m_view->setPosition((screenSize.width() - width) / 2, (screenSize.height() - height) / 2);
m_view->show();

ListModel绑定数据[单选按钮]

ListModel {id: deviceModelListElement {index:0;name:"FreeScan UE"; active:1; deviceType:11}ListElement {index:1;name:"FreeScan UE Pro"; active:0; deviceType:12}ListElement {index:2;name:"FreeScan Combo"; active:0; deviceType:15}ListElement {index:3;name:"FreeScan UE Pro2"; active:0; deviceType:16}
}
Column{id: showNoDogBoxDevicespacing: 12 * rwheight: 2 * rw * (deviceModel.count - 1) + deviceTxt.contentHeight * deviceModel.countanchors.horizontalCenter: parent.horizontalCenteranchors.top: contentColumn.bottomanchors.topMargin: 20 * rwRepeater {model:deviceModeldelegate: Row{spacing: 2 * rwImage {id: showNoDogBoxRadiosource: model.active ? "qrc:/imgs/radioTrue.svg" : "qrc:/imgs/radioFalse.svg"MouseArea {anchors.fill: parentcursorShape: Qt.PointingHandCursoronClicked: {for(var i = 0; i < deviceModel.count;i++){if(i !== model.index){deviceModel.setProperty(i,"active",0)}}deviceModel.setProperty(model.index,"active",1)if(model.active === 1){type = model.deviceType}}}}Text {id: deviceTxttext: qsTr(model.name)font.pixelSize: 20 * rffont.family: familyfont.bold: truecolor: "#DBDBDB"wrapMode: Text.Wrapanchors.top: parent.topanchors.topMargin: 1 * rwMouseArea {anchors.fill: parentcursorShape: Qt.PointingHandCursoronClicked: {for(var i = 0; i < deviceModel.count;i++){if(i !== model.index){deviceModel.setProperty(i,"active",0)}}deviceModel.setProperty(model.index,"active",1)if(model.active === 1){type = model.deviceType}}}}}}
}

布局

Row 行布局

当你把一个Item交给Row来管理,那就不要在使用 Itemx、y、anchors等属性

在一个Row内的 Item,可以使用Poistioner附加属性来获知自己在 Row中的详细位置信息。 Positionerindex、isFirstItem、isLastItem

Row {spacing: 2Rectangle { color: "red"; width: 50; height: 50 }Rectangle { color: "green"; width: 20; height: 50 }Rectangle { color: "blue"; width: 50; height: 20 }
}
Colomun 用法和Row基本一样
Grid

Grid 在一个网格上安置它的子Item,他会创建一个一个拥有很多单元格的网格——从左到右,从上到下把它的子Item一个个塞到单元格里。

Item 默认会被放到一个单元格左上角,即(0,0)位置

Grid {columns: 3spacing: 2Rectangle { color: "red"; width: 50; height: 50 }Rectangle { color: "green"; width: 20; height: 50 }Rectangle { color: "blue"; width: 50; height: 20 }Rectangle { color: "cyan"; width: 50; height: 50 }Rectangle { color: "magenta"; width: 10; height: 10 }}

在这里插入图片描述

Flow

Flow其实和Grid类似,不同之处是它没有显示的行、列数,它会计算子item的尺寸,然后与自身尺寸比较,按需折行

Flowflow属性,默认取值 Flow.LeftToRight,从左到右安排Item,知道Flow本身的宽度不能容纳新的子Item时折行;

 Flow {anchors.fill: parentanchors.margins: 4spacing: 10Text { text: "Text"; font.pixelSize: 40 }Text { text: "items"; font.pixelSize: 40 }Text { text: "flowing"; font.pixelSize: 40 }Text { text: "inside"; font.pixelSize: 40 }Text { text: "a"; font.pixelSize: 40 }Text { text: "Flow"; font.pixelSize: 40 }Text { text: "item"; font.pixelSize: 40 }}
X,Y 定位

在qml中的X,Y定位相对于web中的absolute定位

  • 这种定位的位置,是相对于它的父级元素而言的,x,y,而不是相对于 全局的 window来定位的,重要!重要!重要!

内阴影

此处借鉴内阴影实现的方法,通过添加矩形,让边框显色,并且逐渐渐变;随后将这些边框叠加起来;得到阴影的效果;


通信

通过单例的方式进行全局注册

MyObject.h

public:static MyObject * getInstance();// 单例模式

MyObject.cpp

MyObject *MyObject::getInstance()
{static MyObject * obj = new MyObject();return obj;
}

main.cpp

// 我们一定要通过创建对象来定义一个我们自定义得object
qmlRegisterType<MyObject>("MyObj",1,0,"MyObject");
// 这种注册方式,使用的时候,我们需要在qml中进行如下写法,才可使用MyObject {id:myobj}// 创建一个全局的单例——这种写法不需要在qml在此写 MyObject {id:myobj }
qmlRegisterSingletonInstance("MyObj",1,0,"MyObject",MyObject::getInstance());
qml->c++

首先我们得MyObjecty以及注册过了,注册方式有两种,如下

// 第一种   
QQmlApplicationEngine engine;
//    QQmlContext *context = new QQmlContext(engine.rootContext());// 注册的上下文对象  它是作用于全局的
//    context->setContextProperty("MyObject", MyObject::getInstance());// 第二种qmlRegisterType<MyObject>("MyObj",1,0,"MyObject");
  • MyObject.h
Q_INVOKABLE void func();
  • MyObject.cpp
void MyObject::func()
{// 打印函数的名字qDebug() << __FUNCTION__;
}
  • main.qml
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.0
import MyObj 1.0
Window {width: 640height: 480visible: truetitle: qsTr("Hello World")Button{onClicked: {myobj.func()}}MyObject {id:myobj}
}

信号和槽

  • MyObject.h
    • 声明槽函数
public slots:void cppSolt(int i,QString s);
  • MyObject.cpp
    • 定义槽函数
void MyObject::cppSolt(int i, QString s)
{qDebug() << __FUNCTION__ << " " << i << " " << s;
}
  • main.qml
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.0
import MyObj 1.0
Window {id: rootwidth: 640height: 480visible: truetitle: qsTr("Hello World")signal qmlSig(int i ,string s);Button{onClicked: {// 发送一个信号qmlSig(10,"zhangsan")}}MyObject {id:myobj}// 第一种方法——连接信号和槽Connections{target: root // 发送信号得// 要触发得信号function onQmlSig(i,s){// 要触发得槽函数myobj.cppSolt(i,s);}}//第二种方法——连接信号和槽// Component.onCompleted: {//    qmlSig.connect(myobj.cppSolt)//}
}

在C++端完成信号和槽得绑定

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "myobject.h"int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endifQGuiApplication app(argc, argv);QQmlApplicationEngine engine;
//    QQmlContext *context = new QQmlContext(engine.rootContext());// 注册的上下文对象  它是作用于全局的
//    context->setContextProperty("MyObject", MyObject::getInstance());qmlRegisterType<MyObject>("MyObj",1,0,"MyObject");const QUrl url(QStringLiteral("qrc:/main.qml"));QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,&app, [url](QObject *obj, const QUrl &objUrl) {if (!obj && url == objUrl)QCoreApplication::exit(-1);}, Qt::QueuedConnection);engine.load(url);// 在C++端完成信号和槽得绑定 ——一定要在load之后auto list = engine.rootObjects(); // 获取主对象auto window = list.first();
//    auto objName = list.first()->objectName();// window
//    auto objChild = list.first()->findChild<QObject *>("mybut");QObject::connect(window,SIGNAL(qmlSig(int,QString)),MyObject::getInstance(),SLOT(cppSolt(int,QString)));return app.exec();
}

main.qml

import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.0
import MyObj 1.0
Window {id: rootwidth: 640height: 480visible: truetitle: qsTr("Hello World")objectName: "window"signal qmlSig(int i ,string s);Button{onClicked: {objectName: "mybut"// 发送一个信号qmlSig(10,"zhangsan")}}MyObject {id:myobj}
}
C++->qml
  • MyObject.h
void cppSig(int i,QString s);
  • MyObject.cpp
null
  • main.qml
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.0
import MyObj 1.0
Window {id: rootwidth: 640height: 480visible: truetitle: qsTr("Hello World")// 定义一个槽函数function  qmlSlot(i,s){console.log("qml",i,s);}Button{onClicked: {myobj.cppSig(99,"lisi");}}MyObject {id:myobj}Connections{target: myobj // 发送信号得// 要触发得信号function onCppSig(i,s){// 要触发得槽函数qmlSlot(i,s);}}
}

另一种方法(此处注册方式,采用的是全局注册单例)

  • MyObject.h
Q_INVOKABLE void func();
  • MyObject.cpp
void MyObject::func()
{emit cppSig(109,"wangwu");qDebug() << __FUNCTION__ ;
}
  • main.qml
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.0
import MyObj 1.0
Window {id: rootwidth: 640height: 480visible: truetitle: qsTr("Hello World")// 定义一个槽函数function  qmlSlot(i,s){console.log("qml",i,s);}Button{onClicked: {MyObject.func();}}Connections{target: MyObject // 发送信号得// 要触发得信号function onCppSig(i,s){// 要触发得槽函数qmlSlot(i,s);}}
}

最后一种方法 connect

参数类型 对应CPP端 收拾QVariant

  • MyObject.h
public:Q_INVOKABLE void func();
signals:void cppSig(QVariant i,QVariant s);// 信号
  • MyObject.cpp
void MyObject::func()
{emit cppSig(109,"wangwu");qDebug() << __FUNCTION__ ;
}
  • main.cpp
engine.load(url);auto list = engine.rootObjects(); // 获取主对象
auto window = list.first();
QObject::connect(MyObject::getInstance(),SIGNAL(cppSig(QVariant,QVariant)),window,SLOT(qmlSlot(QVariant,QVariant)));
  • main.qml
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.0
import MyObj 1.0
Window {id: rootwidth: 640height: 480visible: truetitle: qsTr("Hello World")objectName: "window"// 定义一个槽函数function  qmlSlot(i,s){ // 参数类型  对应CPP端 收拾QVariantconsole.log("qml",i,s);}Button{onClicked: {MyObject.func();}}
}

C++直接调用qml端函数

  • main.cpp
auto list = engine.rootObjects(); // 获取主对象
auto window = list.first();// 调用的对象  调用的函数  返回值放到那  传递的参数
QVariant res;
QVariant arg1 = 123;
QVariant arg2 = "lisi";
QMetaObject::invokeMethod(window,"qmlFunc",Q_RETURN_ARG(QVariant,res),Q_ARG(QVariant,arg1),Q_ARG(QVariant,arg2));
  • main.qml
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.0
import MyObj 1.0
Window {id: rootwidth: 640height: 480visible: truetitle: qsTr("Hello World")function qmlFunc(i,s){return "success";}Button{onClicked: {MyObject.func();}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/27288.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第二十三节:带你梳理Vue2:Vue插槽的认识和基本使用

前言: 通过上一节的学习,我们知道了如何将数据从父组件中传递到子组件中, 除了除了将数据作为props传入到组件中,Vue还允许传入HTML, Vue 实现了一套内容分发的 API&#xff0c;这套 API 的设计灵感源自 Web Components 规范草案&#xff0c;将 <slot> 元素作为承载分发…

java面试:Redis事务的相关命令

MULTI:标记一个事务块的开始。 EXEC:执行所有在 MULTI 开始之后&#xff0c;EXEC 执行之前添加到队列中的命令。 DISCARD:取消事务&#xff0c;清空事务队列中已入队的所有命令。 WATCH:监视一个或多个键&#xff0c;一旦其中任何一个键被修改&#xff0c;服务器将拒绝执行事务…

从零开始! jupyter notebook的安装教程

Jupyter Notebook 是一个开源的 web 应用程序&#xff0c;可以创建和共享包含代码、方程、可视化和文本的文档。它广泛用于数据清理和转换、数值模拟、统计建模、机器学习等数据科学领域。以下是从零开始安装 Jupyter Notebook 的详细步骤。 ### 步骤 1: 安装 Python Jupyter…

系统思考与创新解决

结束了为期两天的《系统思考与创新解决》课程&#xff0c;专为上市公司中后台管理者设计。这次课程让我深刻感受到中后端管理者与前端管理者在心智模式上的显著差异。通过使用系统环路图&#xff0c;不仅揭示了这些差异&#xff0c;还探讨了如何利用这些见解来增强团队间的对话…

13. 第十三章 案例研究-选择数据结构

13. 案例研究-选择数据结构 到这里尼应该已经学会了Python的核心数据结构, 也见过了一些使用它们的算法. 如果你想要更多地了解算个发可以阅读第21章. 本章配合联系介绍一个案例分析, 帮你思考如何选择数据结构并如何使用它们.13.1 单词频率分析 1. 练习1 编写一个程序, 读入…

《站在2024年的十字路口:计算机专业是否仍是高考生的明智之选?》

文章目录 每日一句正能量前言行业竞争现状行业饱和度和竞争激烈程度[^3^]新兴技术的影响[^3^]人才需求的变化[^3^]行业创新动态如何保持竞争力 专业与个人的匹配度判断专业所需的技术能力专业核心课程对学生的要求个人兴趣和性格特点专业对口的职业发展要求实践和经验个人价值观…

vue+intro.js实现引导功能

前言&#xff1a; 使用 intro.js这个插件&#xff0c;来实现一个引导性的效果&#xff0c;适用场景&#xff0c;比如&#xff1a;新手引导页&#xff0c;操作说明等等 效果图&#xff1a; 官网地址&#xff1a;点我 实现步骤&#xff1a; 1、安装 npm install intro.js --sa…

【AnimateAnyone】姿态可控视频生成模型训推,让图片里的人物动起来!

1. 模型简介 Animate Anyone是一项角色动画视频生成技术&#xff0c;能将静态图像依据指定动作生成动态的角色动画视频。该技术利用扩散模型&#xff0c;以保持图像到视频转换中的时间一致性和内容细节。训练由两阶段组成&#xff0c;对不同组网成分进行微调。具体实现借鉴于M…

【架构之路】聊聊什么是微服务

如何让大模型更聪明&#xff1f; 引言 微服务&#xff08;Microservices&#xff09;是一种软件架构风格&#xff0c;它将单一的应用程序拆分为多个小的服务&#xff0c;每个服务都是独立运行和部署的。每个微服务通常只专注于一个业务功能&#xff0c;具有自己的数据存储&…

JavaScript 实现数字计数器的动画效果

写JavaScript 实现数字递增的效果 在HTML页面实现数字计数器的动画效果&#xff0c;类似于页面上的计数器功能&#xff0c;可以控制递增速度和效果的流畅度。主要是显示数字时流畅度更好&#xff0c;页面没那么僵硬 1、第一种 设置每次增加的数量&#xff0c;我这里演示的是…

【UIDynamic-动力学-UIGravityBehavior-重力行为 Objective-C语言】

一、UIGravityBehavior,重力行为, 1.接下来啊,我们一个一个来做, 新建一个项目,叫做:01-重力, 接下来,我们在这个ViewController里边, ViewDidLoad:里边,先写一段简单的代码, 我们写这么一段简单的代码,新建一个红色的UIView,把它显示在屏幕上, UIView *redVie…

《征服数据结构》双端栈

摘要&#xff1a; 1&#xff0c;双端栈的介绍 2&#xff0c;双端栈的代码实现 1&#xff0c;双端栈的介绍 双端栈主要利用了“栈底位置不变&#xff0c;栈顶位置动态变化” 的特点&#xff0c;可以让两个栈共享一块存储空间。在前面我们讲到用数组实现栈的时候&#xff0c;如果…

memcached介绍和详解

Memcached 是一种高性能、分布式内存缓存系统&#xff0c;常用于加速动态 web 应用程序的性能&#xff0c;通过缓存数据库查询结果、对象等数据&#xff0c;减少对数据库的访问压力&#xff0c;从而提高响应速度和系统吞吐量。 ### Memcached 的特点和工作原理 #### 特点 1. …

2024最新流媒体在线音乐系统网站源码 音乐社区 多语言开心版

本文来自&#xff1a;2024最新流媒体在线音乐系统网站源码 音乐社区 多语言开心版 - 源码1688 应用介绍 简介&#xff1a; 2024最新流媒体在线音乐系统网站源码| 音乐社区 | 多语言 | 开心版 图片&#xff1a;

Hyper-V如何将文件复制到虚拟机?教您3个简单的方法!

需要将文件复制到虚拟机&#xff01; “大家好&#xff0c;有谁知道Hyper-V怎么将文件复制到虚拟机吗&#xff1f;我有一些文件&#xff0c;想要从主机中复制进虚拟机中&#xff0c;但是我不知道该怎么操作&#xff0c;有谁可以帮帮我吗&#xff1f;谢谢。” Hyper-V虚拟机可…

Python 使用 Tkinter库 设置 tkinter ttk 框架的背景颜色

Tkinter 设置 tkinter ttk 框架的背景颜色 在本文中&#xff0c;我们将介绍如何使用 Tkinter 在 tkinter ttk 框架中设置背景颜色。Tkinter 是 Python 中常用的 GUI 工具包&#xff0c;ttk 则是 Tkinter 中的一个模块&#xff0c;提供了一套更加现代化的控件。 Tkinter 简介 …

JAVA开发 PDF文件生成表格,表格根据内容自动调整高度

1、展示效果 2、相关功能实现 JAVA开发 使用Apache PDFBox库生成PDF文件&#xff0c;绘制表格 3、实现代码 import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.ap…

新增多种图表类型,新增视频、流媒体、跑马灯组件,DataEase开源数据可视化分析工具v2.7.0发布

2024年6月11日&#xff0c;人人可用的开源数据可视化分析工具DataEase正式发布v2.7.0版本。 这一版本的功能变动包括&#xff1a;图表方面&#xff0c;新增对称条形图、桑基图、流向地图、进度条等图表类型&#xff0c;并对已有的仪表盘、指标卡、明细表、汇总表、水波图、象限…

android studio 自定义类注释模版

perferences>File and Code Templates>Class 填写&#xff1a; /*** ClassName: ${ClassName}* Description: ${Description}* Author: ${Author}* CreateDate: ${CreateDate}* UpdateUser: ${UpdateUser}* UpdateDate: ${UpdateDate}* UpdateRemark: ${UpdateRemark}* …

计算机网络(7) 错误检测

一.校验和 使用补码计算校验和是一种常见的错误检测方法&#xff0c;应用于网络协议如IP和TCP。补码是二进制数的一种表示方法&#xff0c;可以有效地处理符号位和进位。下面是如何利用补码计算校验和的详细步骤和算数例子。 ### 计算步骤 1. **将数据分块**&#xff1a;将数…