QML 和 QQuickWidget

Posted

技术标签:

【中文标题】QML 和 QQuickWidget【英文标题】:QML and QQuickWidget 【发布时间】:2021-01-29 14:52:54 【问题描述】:

我是 qml 的新手,但我想通过参考 QT 示例的仪表板向 QQuickWidget 添加一个圆形仪表。 以下是我的代码。

guagetest.pro

QT       += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets quickwidgets
CONFIG += c++11

DEFINES += QT_DEPRECATED_WARNINGS

SOURCES += \
    main.cpp \
    mainwindow.cpp

HEADERS += \
    mainwindow.h

FORMS += \
    mainwindow.ui

# Default rules for deployment.
qnx: target.path = /tmp/$$TARGET/bin
else: unix:!android: target.path = /opt/$$TARGET/bin
!isEmpty(target.path): INSTALLS += target

RESOURCES += \
    dashboard.qrc

主窗口.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)

    ui->setupUi(this);

    ui->quickWidget->setSource(QUrl("qrc:/qml/qml/test.qml"));
    ui->quickWidget->show();


MainWindow::~MainWindow()

    delete ui;
 

test.qml

import QtQuick 2.2
import QtQuick.Window 2.1
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Extras 1.4

Item 
    id: container
    width: parent.width
    height: parent.height
    anchors.centerIn: parent.Center

    Row 
        id: gaugeRow
        spacing: container.width * 0.2
        anchors.centerIn: parent

        CircularGauge 
            id: speedometer
            value: valueSource.kph
            anchors.verticalCenter: parent.verticalCenter
            maximumValue: 280
            // We set the width to the height, because the height will always be
            // the more limited factor. Also, all circular controls letterbox
            // their contents to ensure that they remain circular. However, we
            // don't want to extra space on the left and right of our gauges,
            // because they're laid out horizontally, and that would create
            // large horizontal gaps between gauges on wide screens.
            width: height
            height: container.height * 0.8

            style: DashboardGaugeStyle 
        
    

DashboardGaugeStyle.qml

import QtQuick 2.2
import QtQuick.Controls.Styles 1.4

CircularGaugeStyle 
    tickmarkInset: toPixels(0.04)       // gauge graduation radius
    minorTickmarkInset: tickmarkInset
    labelStepSize: 20                   // gauge graduation text
    labelInset: toPixels(0.23)          // gauge graduation text position

    property real xCenter: outerRadius
    property real yCenter: outerRadius
    property real needleLength: outerRadius - tickmarkInset * 1.25
    property real needleTipWidth: toPixels(0.02)
    property real needleBaseWidth: toPixels(0.06)
    property bool halfGauge: false

    function toPixels(percentage) 
        return percentage * outerRadius;
    

    function degToRad(degrees) 
        return degrees * (Math.PI / 180);
    

    function radToDeg(radians) 
        return radians * (180 / Math.PI);
    

    function paintBackground(ctx) 
        if (halfGauge) 
            ctx.beginPath();
            ctx.rect(0, 0, ctx.canvas.width, ctx.canvas.height / 2);
            ctx.clip();
        

        ctx.beginPath();
        ctx.fillStyle = "black";
        ctx.ellipse(0, 0, ctx.canvas.width, ctx.canvas.height);
        ctx.fill();

        ctx.beginPath();
        ctx.lineWidth = tickmarkInset;
        ctx.strokeStyle = "black";
        ctx.arc(xCenter, yCenter, outerRadius - ctx.lineWidth / 2, outerRadius -ctx.lineWidth / 2, 0, Math.PI * 2);
        ctx.stroke();

        ctx.beginPath();
        ctx.lineWidth = tickmarkInset / 2;
        ctx.strokeStyle = "#222";
        ctx.arc(xCenter, yCenter, outerRadius - ctx.lineWidth / 2, outerRadius -ctx.lineWidth / 2, 0, Math.PI * 2);
        ctx.stroke();

        ctx.beginPath();
        var gradient = ctx.createRadialGradient(xCenter, yCenter, 0, xCenter, yCenter, outerRadius * 1.5);
        gradient.addColorStop(0, Qt.rgba(1, 1, 1, 0));
        gradient.addColorStop(0.7, Qt.rgba(1, 1, 1, 0.13));
        gradient.addColorStop(1, Qt.rgba(1, 1, 1, 1));
        ctx.fillStyle = gradient;
        ctx.arc(xCenter, yCenter, outerRadius - tickmarkInset, outerRadius - tickmarkInset, 0, Math.PI * 2);
        ctx.fill();
    

    background: Canvas 
        onPaint: 
            var ctx = getContext("2d");
            ctx.reset();
            paintBackground(ctx);
        

        Text 
            id: speedText
            font.pixelSize: toPixels(0.3)
            text: kphInt
            color: "white"
            horizontalAlignment: Text.AlignRight
            anchors.horizontalCenter: parent.horizontalCenter
            anchors.top: parent.verticalCenter
            anchors.topMargin: toPixels(0.1)

            readonly property int kphInt: control.value
        
        Text 
            text: "km/h"
            color: "white"
            font.pixelSize: toPixels(0.09)
            anchors.top: speedText.bottom
            anchors.horizontalCenter: parent.horizontalCenter
        
    

    needle: Canvas 
        implicitWidth: needleBaseWidth
        implicitHeight: needleLength

        property real xCenter: width / 2
        property real yCenter: height / 2

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

            ctx.beginPath();
            ctx.moveTo(xCenter, height);
            ctx.lineTo(xCenter - needleBaseWidth / 2, height - needleBaseWidth / 2);
            ctx.lineTo(xCenter - needleTipWidth / 2, 0);
            ctx.lineTo(xCenter, yCenter - needleLength);
            ctx.lineTo(xCenter, 0);
            ctx.closePath();
            ctx.fillStyle = Qt.rgba(0.66, 0, 0, 0.66);
            ctx.fill();

            ctx.beginPath();
            ctx.moveTo(xCenter, height)
            ctx.lineTo(width, height - needleBaseWidth / 2);
            ctx.lineTo(xCenter + needleTipWidth / 2, 0);
            ctx.lineTo(xCenter, 0);
            ctx.closePath();
            ctx.fillStyle = Qt.lighter(Qt.rgba(0.66, 0, 0, 0.66));
            ctx.fill();
        
    

    foreground: null

当我编译时,出现以下消息。

qrc:/qml/qml/test.qml:9: TypeError: Cannot read property 'width' of null
qrc:/qml/qml/test.qml:10: TypeError: Cannot read property 'height' of null
qrc:/qml/qml/test.qml:20: ReferenceError: valueSource is not defined
qrc:/qml/qml/test.qml:11: TypeError: Cannot read property 'Center' of null

我想知道为什么会出现这条消息以及如何解决它。 以及如何更改 QQuickWidget 的背景颜色?

请帮帮我。

【问题讨论】:

问题是你在test.qml的根Item中调用parent.width,但是没有父级。 同样Center 应该是center 【参考方案1】:

根对象需要一个初始大小。并且不需要以父母为中心,因为没有父母。假设尺寸为 500x300。

Item 
    id: container
    width: 500
    height: 300

或者,如果您不想给出恒定大小,但要使大小完全适合内容,则可以使用childrenRect。确保您的内容大小不依赖于根目录并且在使用前具有有效的宽度和高度。它可能会导致“检测到宽度/高度的绑定循环”。警告。

Item 
    id: container
    width: childrenRect.width
    height: childrenRect.height

如果您希望您的场景根据 QQuickWidget 的大小调整大小,请动态设置调整大小模式。

ui->quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);

让我们进入着色点。要更改根项目的颜色,我们可以使用Rectangle.color 属性。因此,将根对象从 Item 更改为 Rectangle。让我们把背景变成红色。

Rectangle 
    id: container
    width: childrenRect.width
    height: childrenRect.height
    color: "red"

或者如果你想改变QQuickWidget的窗口颜色,设置调色板。但既然你的场景会覆盖它,我怀疑这就是你所需要的。

auto palette = ui->quickWidget->palette();
palette.setColor(QPalette::Window, QColor(Qt::red));
ui->quickWidget->setPalette(palette);

还有一个问题:

qrc:/qml/qml/test.qml:20: ReferenceError: valueSource is not defined

我不知道valueSource 是什么,要么确保你拥有它,要么摆脱它。

【讨论】:

当我使用'width:childrenRect.width'和'height:childrenRect.height'时,圆规消失并显示以下消息:QML Rectangle:为属性“width”检测到绑定循环跨度> 'color: "red"' 在 qml 中运行良好,但使用 QQuickWidget 的代码不起作用 @user11668757 感谢您的反馈。我刚刚更新了答案。删除圆形仪表的宽度和高度以使用它的默认大小或给它一个恒定的大小。您的场景可能覆盖了窗口调色板,这可能是您看不到它的原因。

以上是关于QML 和 QQuickWidget的主要内容,如果未能解决你的问题,请参考以下文章

列数可变的 QML 中继器和 QML 网格布局

Qt5 / PyQt5 : 带有 QML 前端和 Python 后端的自定义 QML 组件

在 Qml 代码中编辑 C++ QList<Object*> 模型的问题和一些 Qml 警告

如何处理过多的 QML 和音频文件

QML和C++混合编程中,在qml中向C++的char* 函数传递一个char*的字符串参数,qml不能识别char*的参数类型

C++ 和 QML:将 QML 信号连接到 C++ 插槽