QML学习及实战

news2025/6/26 7:44:21

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

创建项目

  1. 在这里插入图片描述

  2. 在这里插入图片描述

3.在这里插入图片描述

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

添加静态资源——图片

  1. 在这里插入图片描述

  2. 在这里插入图片描述

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

    在这里插入图片描述

案列 || demo

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

1. 文本省略号

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

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

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.12

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

    TextMetrics{
        id: textMetrics
        elide: Text.ElideRight
        elideWidth: 600
        text: "Negativnsets to place a shadow outside the popup's boundaries:"

    }
    //文字显示缩略
    TextArea {
        id: referMessage
        color: "#000000"
        anchors.top: parent.top
        anchors.topMargin: 100
        anchors.left: parent.left
        anchors.leftMargin: 100
        width: 300
        height: 90
        text: textMetrics.elidedText //文字缩略
        font.pixelSize: 14
        font.weight: Font.Light
        wrapMode: TextArea.WrapAnywhere
        readOnly: true
        verticalAlignment: Text.AlignVCenter
        focusReason: Qt.MouseFocusReason
        textFormat: TextArea.AutoText

        background: Rectangle {
            anchors.fill: parent
            color: "#ffff00"
        }
    }
    Component.onCompleted:
    {
        console.log("str=====", textMetrics.elidedText)
    }
}

2. Canvas画圆角

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

import QtQuick
import QtQuick.Controls 2.15

Window {
    visible: true
    width: 1000
    height: 900
        Canvas {
        id: canvas
        anchors.fill: parent

        onPaint: {
            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.15

Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")
    Canvas {
    id: canvas
    anchors.fill: parent

        onPaint: {
            var ctx = getContext("2d");

            // 定义矩形位置和大小
            var rectX = 0;
            var rectY = 0;
            var rectWidth = 59;
            var rectHeight = 59;

            // 定义圆弧半径
            var arcRadius = 8;

            // 计算圆弧位置
            var arcX = rectX + rectWidth;//109
            var arcY = rectY// 50
            var arcStartX = arcX + arcRadius;//117
            var arcStartY = rectY;//50
            var arcEndX = arcStartX; //117
            var arcEndY = arcStartY + arcRadius;// 58r
            console.log(arcX,arcY,arcStartX,arcStartY,arcEndX,arcEndY)

            // 绘制矩形
            ctx.fillStyle = "#000000";

            // 绘制右上角圆弧
            ctx.beginPath();
            ctx.moveTo(rectX, rectY);// 50 50
            ctx.lineTo(arcX, arcY);// 109 50
            ctx.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 到 100

    QTimer 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.12

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

    Rectangle {
        width: 200
        height: 200
        color: "lightblue"

        MouseArea {
            anchors.fill: parent
            acceptedButtons: Qt.RightButton

            onClicked: {
                menu.popup()
            }
        }

        Menu {
            id: menu

            MenuItem {
                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.source
      property alias label: text.text
      implicitWidth: text.implicitWidth + image.implicitWidth
      implicitHeight: Math.max(text.implicitHeight, image.implicitHeight)
      Image { id: image }
      Text {
          id: text
          wrapMode: Text.Wrap
          anchors.left: image.right; anchors.right: parent.right
          anchors.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.15

Item {
    width: 200
    height: 200

    property bool showComponent: false

    Loader {
        id: componentLoader
        sourceComponent: showComponent ? componentA : null
    }

    Component {
            id: componentA
            Rectangle {
            width: 100
            height: 100
            color: "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: 640
    height: 480
    visible: true
    title: qsTr("Hello World")

    Rectangle {
            id:id_root
            width: 800
            height: 400
            color:"black"
            Rectangle {
                width: 400
                height: 200
                gradient: Gradient {
                    GradientStop { position: 0; color: "white" }
                    GradientStop { position: 1; color: "gray" }
                }
                Row {
                    id:id_row
                    opacity: 1.0
                    Item {
                        id: foo
                        width: 100; height: 100
                        Rectangle { 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: 70
                    anchors.horizontalCenter: id_row.horizontalCenter
                    anchors.top: id_row.bottom
                    sourceItem: foo
                    opacity:0.3
                    rotation: 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.0

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello Qt")

    // 2. 使用
    TestProperty{
        id: testProperty
        title: 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: deviceModel
  ListElement {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: showNoDogBoxDevice
  spacing: 12 * rw
  height: 2 * rw * (deviceModel.count - 1) + deviceTxt.contentHeight * deviceModel.count
  anchors.horizontalCenter: parent.horizontalCenter
  anchors.top: contentColumn.bottom
  anchors.topMargin: 20 * rw
  Repeater {
    model:deviceModel
    delegate: Row{
    spacing: 2 * rw
    Image {
      id: showNoDogBoxRadio
      source: model.active ? "qrc:/imgs/radioTrue.svg" : "qrc:/imgs/radioFalse.svg"
      MouseArea {
        anchors.fill: parent
        cursorShape: Qt.PointingHandCursor
        onClicked: {
        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: deviceTxt
        text: qsTr(model.name)
        font.pixelSize: 20 * rf
        font.family: family
        font.bold: true
        color: "#DBDBDB"
        wrapMode: Text.Wrap
        anchors.top: parent.top
        anchors.topMargin: 1 * rw
        MouseArea {
        anchors.fill: parent
        cursorShape: Qt.PointingHandCursor
        onClicked: {
        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: 2
    Rectangle { 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: 3
      spacing: 2
      Rectangle { 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: parent
     anchors.margins: 4
     spacing: 10
     Text { 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: 640
    height: 480
    visible: true
    title: 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: root
    width: 640
    height: 480
    visible: true
    title: 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);
#endif
    QGuiApplication 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: root
    width: 640
    height: 480
    visible: true
    title: 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: root
    width: 640
    height: 480
    visible: true
    title: 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: root
    width: 640
    height: 480
    visible: true
    title: 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: root
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")
    objectName: "window"
    // 定义一个槽函数
    function  qmlSlot(i,s){ // 参数类型  对应CPP端 收拾QVariant
        console.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: root
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")

    function qmlFunc(i,s){
        return "success";
    }

    Button{
        onClicked: {
            MyObject.func();
        }
    }
}

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

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

相关文章

RedHat9 | Mariadb数据库的配置与管理

一、实验环境 1、Mariadb数据库介绍 MariaDB数据库管理系统是一个开源的关系型数据库管理系统&#xff0c;与MySQL高度兼容&#xff0c;并提供了更多的功能和性能优化。 起源和背景 MariaDB是MySQL的一个分支&#xff0c;主要由开源社区维护。由MySQL的创始人Michael Widen…

百度OCR初探-python

百度OCR使用&#x1f680; 在项目中需要对一些资料首先进行OCR识别&#xff0c;然后对OCR之后得到的结果进行结构化分析&#xff0c;各家的都打算简单尝试一下&#xff0c;首先尝试一下百度的OCR&#xff0c;首先找到百度的OCR的官方&#xff0c;开始自己搜索然后尝试。 OCR&am…

浅谈数据管理架构 Data Fabric(数据编织)及其关键特征、落地应用

伴随着企业从数字化转型迈向更先进的数智化运营新阶段&#xff0c;对看数、用数的依赖越来越强&#xff0c;但数据的海量增长给数据管理带来一系列难题&#xff0c;如数据类型和加工链路日益复杂&#xff0c;数据存储和计算引擎更加分散&#xff0c;数据需求响应与数据质量、数…

【电机控制】FOC算法验证步骤——PWM、ADC

【电机控制】FOC算法验证步骤 文章目录 前言一、PWM——不接电机1、PWMA-H-50%2、PWMB-H-25%3、PWMC-H-0%4、PWMA-L-50%5、PWMB-L-75%6、PWMC-L-100% 二、ADC——不接电机1.电流零点稳定性、ADC读取的OFFSET2.电流钳准备3.运放电路分析1.电路OFFSET2.AOP3.采样电路的采样值范围…

kubespray离线安装k8s

kubespray离线安装k8s 系统环境 OS: Static hostname: test Icon name: computer-vm Chassis: vm Machine ID: 22349ac6f9ba406293d0541bcba7c05d Boot ID: 83bb7e5dbf27453c94ff9f1fe88d5f02 Virtualization: vmware Operating System: Ubuntu 22.04.4 LTS Kernel: Linux 5.…

哪个牌子的开放式耳机性价比高呢?五大口碑销量双佳产品汇总!

​喜欢户外活动的朋友们&#xff0c;你们都是懂得享受生活的达人吧&#xff01;想象一下&#xff0c;在户外活动时&#xff0c;如果能有一副既适合场景又提供超棒音乐体验的耳机&#xff0c;那该多完美啊&#xff01;这时候&#xff0c;开放式耳机就闪亮登场了&#xff01;它的…

JAVAEE值之网络原理(1)_用户数据报协议(UDP)、概念、特点、结构、代码实例

前言 在前两节中我们介绍了UDP数据报套接字编程&#xff0c;但是并没有对UDP进行详细介绍&#xff0c;本节中我们将会详细介绍传输层中的UDP协议。 一、什么是UDP&#xff1f; UDP工作在传输层&#xff0c;用于程序之间传输数据的。数据一般包含&#xff1a;文件类型&#xff0…

SpringCloud2023 - 学习笔记

文章目录 1. 简介1.1 基础知识1.2 组件更替与升级 2. 微服务基础项目构建2.1 创建项目2.2 Mapper4生成代码2.3 支付模块编码2.4 项目完善2.5 订单模块编码2.6 工程重构 3. consul服务注册与发现3.1 consul简介3.2 consul下载安装3.3 微服务入驻3.4 order订单微服务入驻3.5 其他…

美摄科技匿名化处理解决方案,包含模糊、同色、马赛克、效果遮挡等各种形式

信息安全已成为企业发展中不可忽视的重要一环&#xff0c;随着信息安全法规的日益严格和公众对个人隐私保护意识的不断提高&#xff0c;企业如何在保障业务顺畅进行的同时&#xff0c;满足信息安全和隐私保护的要求&#xff0c;成为了亟待解决的问题。美摄科技凭借其强大的技术…

手把手搭建 Nginx + VIP + Keepalived 高可用集群

文章目录 1、前置讲解1.1、常用方案1.2、实现流程 2、集群搭建2.1、环境准备2.2、关于 Nginx2.2.1、安装 Nginx2.2.2、调整 Nginx 首页 2.3、关于 Keepalived2.3.1、安装 Keepalived2.3.2、编写 Shell2.3.3、调整 KeepAlived 配置 1、前置讲解 其实阿里云ECS本身不支持使用服务…

Kubernetes集群持久化部署实践

WordPress 网站持久化部署 要持久化MariaDB 可以把 Deployment 改成了 StatefulSet&#xff0c;修改 YAML添加“serviceName”“volumeClaimTemplates”这两个字段&#xff0c;定义网络标识和 NFS 动态存储卷&#xff0c;然后在容器部分用“volumeMounts”挂载到容器里的数据目…

一文搞懂阻塞赋值和非阻塞赋值

目录 2.非阻塞赋值举例3.阻塞赋值举例4.总结 微信公众号获取更多FPGA相关源码&#xff1a; # 1.阻塞赋值和非阻塞赋值的区别&#xff1a; (1)阻塞赋值""&#xff0c;必须是阻塞赋值完成后&#xff0c;才进行下一条语句的执行&#xff1b;赋值一旦完成&#xff0c;等号…

docker环境中配置phpstorm php xdebug调试工具

本文介绍通过docker compose的使用方式 第一步&#xff1a;在php镜像中安装phpxdebug扩展&#xff0c;比如php7.4对应的是xdebug3.1.6 第二步&#xff1a;设置项目中的docker-compose.yml docker-compose 增加开启xdebug的环境变量,host.docker.internal是宿主机的地址&#…

MBTI:探索你的性格类型

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌…

4.音视频 AAC SSAASS

目录 AAC 1.什么是ADIF和ADTS&#xff1f; 2.ADTS的数据结构是怎样的&#xff1f; SSA/ASS 1.SSA/ASS的基本结构 AAC AAC(Advanced Audio Coding&#xff0c;高级音频编码)是一种声音数据的文件压缩格式。AAC分为ADIF和ADTS两种文件格式。 1.什么是ADIF和ADTS&#xff…

Day01 C语言嵌入式

目录 1、嵌入式知识体系 2、计算机的组成原理 3、计算机之父 4、C语言标准 5、关键字 6、字符编码 7、字符集 1、嵌入式知识体系 备注&#xff1a;图片来源于网络&#xff0c;为嵌入式知识体系思维导图&#xff0c;分为软件、硬件和理论知识三个部分&#xff0c;仅供各位…

【LeetCode】4,寻找两个正序数组中的中位数

题目地址 B站那个官方解答视频实在看不懂&#xff0c;我就根据他那个代码和自己的理解写一篇文章 1. 基本思路 在只有一个有序数组的时候&#xff0c;中位数把数组分割成两个部分。中位数的定义&#xff1a;中位数&#xff0c;又称中点数&#xff0c;中值。中位数是按顺序排列…

全志摄像头屏幕预览、录制(H264)

一、录像 使用dvr_test录制视频 运行dvr_test demo出现space not enought问题&#xff0c;修改/etc/dvrconfig.ini文件下对应的camera节点下cur_filedir属性无效 修改以下内容解决; 录制时出现摄像头画面异常&#xff0c;如下 摄像头型号与打印信息匹配&#xff1a; 但是出现画…

整蛊软件/插件使用方法与配置步骤~

今天出一期整蛊软件的使用方法与配置步骤 很多人在使用整蛊软件的时候 想自己添加更多的玩法内容 但是还不知道如何去配置 这期给大家出一下图文教程步骤 基本上也是软件的功能介绍使用方式~ 案例可扫码查看 第一步&#xff1a;打开软件输入卡密登录&#xff1a; 卡密费用&…

最好用的邮箱管理软件推荐,邮箱管理软件哪个好?(干货篇)

在快节奏的工作与生活中&#xff0c;有效管理电子邮件成为提升个人与团队效率的关键。 面对海量信息流&#xff0c;一款好的邮箱管理软件不仅能够帮助我们高效地整理收件箱&#xff0c;还能确保重要邮件不会错过&#xff0c;同时提升通讯的便捷性和安全性。 本文将为您推荐几款…