QML与C++炫酷界面交互DEMO

目录

[1 运行界面](#1 运行界面)

[2 目录结构](#2 目录结构)

[3 源码](#3 源码)

[4 遇到的问题](#4 遇到的问题)


1 运行界面

2 目录结构

QT 5.12 + MINGW64

3 源码

untitled13.pro

cpp 复制代码
QT += quick
QT += core network

CONFIG += c++11

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Refer to the documentation for the
# deprecated API to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
        datamanager.cpp \
        main.cpp

RESOURCES += qml.qrc

# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =

# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =

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

HEADERS += \
    datamanager.h

datamanager.h

cpp 复制代码
#ifndef DATAMANAGER_H
#define DATAMANAGER_H

#include <QObject>
#include <QTimer>
#include <QVector>
#include <QRandomGenerator>

class DataManager : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QVector<int> lineData READ lineData NOTIFY lineDataChanged)
    Q_PROPERTY(QVector<int> barData READ barData NOTIFY barDataChanged)
    Q_PROPERTY(int deviceUsage READ deviceUsage NOTIFY deviceUsageChanged)
    Q_PROPERTY(int capacityRate READ capacityRate NOTIFY capacityRateChanged)
    Q_PROPERTY(int energyRate READ energyRate NOTIFY energyRateChanged)
    Q_PROPERTY(QString lastUpdateTime READ lastUpdateTime NOTIFY lastUpdateTimeChanged)

public:
    static DataManager* instance();

    // Getter方法
    QVector<int> lineData() const { return m_lineData; }
    QVector<int> barData() const { return m_barData; }
    int deviceUsage() const { return m_deviceUsage; }
    int capacityRate() const { return m_capacityRate; }
    int energyRate() const { return m_energyRate; }
    QString lastUpdateTime() const { return m_lastUpdateTime; }

signals:
    void lineDataChanged();
    void barDataChanged();
    void deviceUsageChanged();
    void capacityRateChanged();
    void energyRateChanged();
    void lastUpdateTimeChanged();
    void dataUpdated();  // 总体数据更新信号

private slots:
    void updateData();    // 定时更新数据
    void simulateRealTimeData(); // 模拟实时数据变化

private:
    DataManager(QObject *parent = nullptr);
    ~DataManager();

    void initData();      // 初始化数据
    void generateRandomData(); // 生成随机数据

    QTimer* m_updateTimer;      // 数据更新定时器
    QTimer* m_realtimeTimer;    // 实时数据模拟定时器

    QVector<int> m_lineData;    // 折线图数据
    QVector<int> m_barData;     // 直方图数据
    int m_deviceUsage;           // 设备使用率
    int m_capacityRate;          // 产能达标率
    int m_energyRate;            // 能耗优化率
    QString m_lastUpdateTime;    // 最后更新时间

    QRandomGenerator* m_random;  // 随机数生成器
};

#endif // DATAMANAGER_H

datamanager.cpp

cpp 复制代码
#include "datamanager.h"
#include <QDateTime>
#include <QDebug>

DataManager* DataManager::instance()
{
    static DataManager* instance = nullptr;
    if (!instance) {
        instance = new DataManager();
    }
    return instance;
}

DataManager::DataManager(QObject *parent) : QObject(parent)
{
    m_random = new QRandomGenerator(QRandomGenerator::securelySeeded());
    m_updateTimer = new QTimer(this);
    m_realtimeTimer = new QTimer(this);

    // 初始化数据
    initData();

    // 设置定时器:每5秒更新一次基础数据
    connect(m_updateTimer, &QTimer::timeout, this, &DataManager::updateData);
    m_updateTimer->start(5000);

    // 设置定时器:每2秒模拟实时数据微小变化
    connect(m_realtimeTimer, &QTimer::timeout, this, &DataManager::simulateRealTimeData);
    m_realtimeTimer->start(2000);
}

DataManager::~DataManager()
{
    delete m_random;
}

void DataManager::initData()
{
    // 初始化折线图数据(8个时间点)
    m_lineData = {120, 280, 190, 350, 260, 410, 330, 480};

    // 初始化直方图数据(6个车间)
    m_barData = {480, 390, 380, 320, 260, 290};

    // 初始化环形图数据
    m_deviceUsage = 83;
    m_capacityRate = 92;
    m_energyRate = 76;

    // 更新时间
    m_lastUpdateTime = QDateTime::currentDateTime().toString("hh:mm:ss");

    qDebug() << "数据管理器初始化完成";
}

void DataManager::updateData()
{
    qDebug() << "开始更新数据...";

    // 更新折线图数据(模拟新数据点,滚动更新)
    int newValue = m_random->bounded(100, 500);
    m_lineData.push_back(newValue);
    if (m_lineData.size() > 8) {
        m_lineData.removeFirst();
    }
    emit lineDataChanged();

    // 更新直方图数据
    for (int i = 0; i < m_barData.size(); i++) {
        int change = m_random->bounded(-20, 21); // -20 到 +20 的变化
        m_barData[i] = qBound(100, m_barData[i] + change, 550);
    }
    emit barDataChanged();

    // 更新环形图数据(在合理范围内波动)
    m_deviceUsage = qBound(70, m_deviceUsage + m_random->bounded(-5, 6), 98);
    m_capacityRate = qBound(80, m_capacityRate + m_random->bounded(-3, 4), 99);
    m_energyRate = qBound(65, m_energyRate + m_random->bounded(-4, 5), 95);

    emit deviceUsageChanged();
    emit capacityRateChanged();
    emit energyRateChanged();

    // 更新时间戳
    m_lastUpdateTime = QDateTime::currentDateTime().toString("hh:mm:ss");
    emit lastUpdateTimeChanged();

    // 触发整体数据更新信号
    emit dataUpdated();

    qDebug() << "数据更新完成 - 设备使用率:" << m_deviceUsage
             << "% 产能达标率:" << m_capacityRate
             << "% 能耗优化率:" << m_energyRate;
}

void DataManager::simulateRealTimeData()
{
    // 模拟实时数据的微小变化(让图表看起来更生动)
    static int counter = 0;

    // 每2秒轻微调整折线图最后一个数据点
    if (m_lineData.size() > 0) {
        int lastValue = m_lineData.last();
        int adjustment = m_random->bounded(-15, 16);
        m_lineData.last() = qBound(80, lastValue + adjustment, 550);
        emit lineDataChanged();
    }

    // 轻微调整环形图数据(1-2%的波动)
    int usageChange = m_random->bounded(-2, 3);
    int capacityChange = m_random->bounded(-1, 2);
    int energyChange = m_random->bounded(-2, 3);

    m_deviceUsage = qBound(70, m_deviceUsage + usageChange, 98);
    m_capacityRate = qBound(80, m_capacityRate + capacityChange, 99);
    m_energyRate = qBound(65, m_energyRate + energyChange, 95);

    emit deviceUsageChanged();
    emit capacityRateChanged();
    emit energyRateChanged();

    // 每10次更新(20秒)更新一次时间戳
    if (++counter % 10 == 0) {
        m_lastUpdateTime = QDateTime::currentDateTime().toString("hh:mm:ss");
        emit lastUpdateTimeChanged();
    }
}

void DataManager::generateRandomData()
{
    // 生成随机测试数据(备用方法)
    m_lineData.clear();
    for (int i = 0; i < 8; i++) {
        m_lineData.append(m_random->bounded(100, 500));
    }

    m_barData.clear();
    for (int i = 0; i < 6; i++) {
        m_barData.append(m_random->bounded(200, 500));
    }

    m_deviceUsage = m_random->bounded(70, 98);
    m_capacityRate = m_random->bounded(80, 99);
    m_energyRate = m_random->bounded(65, 95);

    emit lineDataChanged();
    emit barDataChanged();
    emit deviceUsageChanged();
    emit capacityRateChanged();
    emit energyRateChanged();
}

main.cpp

cpp 复制代码
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <qqml.h>
#include "datamanager.h"
// 单例创建函数
static QObject* dataManagerSingletonProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
{
    Q_UNUSED(engine)
    Q_UNUSED(scriptEngine)
    return DataManager::instance();
}

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    // 注册为单例类型(必须在加载 QML 之前)
    qmlRegisterSingletonType<DataManager>("IndustrialMonitor", 1, 0, "DataManager", dataManagerSingletonProvider);
    QQmlApplicationEngine engine;
    // 方式1:设置上下文属性
    DataManager* dataMgr = DataManager::instance();
    engine.rootContext()->setContextProperty("dataManager", dataMgr);
    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);

    return app.exec();
}

main.qml

javascript 复制代码
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
import IndustrialMonitor 1.0

Window {
    id: mainWindow
    width: 1920
    height: 1080
    visible: true
    title: "上海工业生产实时监控大屏"
    color: "#0A0E1A"

    property int refreshCounter: 0
    property int glowAnimation: 0

    Timer {
        interval: 50
        running: true
        repeat: true
        onTriggered: glowAnimation = (glowAnimation + 1) % 360
    }

    // 动态渐变背景
    Rectangle {
        anchors.fill: parent
        gradient: Gradient {
            GradientStop { position: 0.0; color: "#0A0E1A" }
            GradientStop { position: 0.5; color: "#0F1530" }
            GradientStop { position: 1.0; color: "#0A0E1A" }
        }

        // 科技网格背景
        Grid {
            anchors.fill: parent
            columns: 24
            rows: 14
            opacity: 0.05
            Repeater {
                model: 336
                Rectangle {
                    width: parent.width / 24
                    height: parent.height / 14
                    color: "#4D9FFF"
                    opacity: 0.05
                    border.color: "#4D9FFF"
                    border.width: 0.5
                }
            }
        }
    }

    // 监听C++数据更新信号
    Connections {
        target: dataManager
        enabled: true

        onDataUpdated: {
            console.log("收到 dataUpdated 信号")
            lineCanvas.requestPaint()
            barCanvas.requestPaint()
            ringCanvas1.requestPaint()
            ringCanvas2.requestPaint()
            ringCanvas3.requestPaint()
        }

        onLineDataChanged: {
            console.log("收到 lineDataChanged 信号,数据:", dataManager.lineData)
            lineCanvas.requestPaint()
        }

        onBarDataChanged: {
            console.log("收到 barDataChanged 信号")
            barCanvas.requestPaint()
        }

        onDeviceUsageChanged: {
            console.log("收到 deviceUsageChanged 信号,值:", dataManager.deviceUsage)
            ringCanvas1.requestPaint()
        }

        onCapacityRateChanged: {
            console.log("收到 capacityRateChanged 信号")
            ringCanvas2.requestPaint()
        }

        onEnergyRateChanged: {
            console.log("收到 energyRateChanged 信号")
            ringCanvas3.requestPaint()
        }
    }

    // ========== 顶部标题栏(炫酷版) ==========
    Rectangle {
        anchors.top: parent.top
        anchors.left: parent.left
        anchors.right: parent.right
        height: 90
        color: "#0F1530"

        // 顶部发光边框
        Rectangle {
            anchors.bottom: parent.bottom
            anchors.left: parent.left
            anchors.right: parent.right
            height: 2
            gradient: Gradient {
                GradientStop { position: 0.0; color: "transparent" }
                GradientStop { position: 0.2; color: "#4D9FFF" }
                GradientStop { position: 0.5; color: "#00FFFF" }
                GradientStop { position: 0.8; color: "#4D9FFF" }
                GradientStop { position: 1.0; color: "transparent" }
            }
        }

        // 顶部光晕
        Rectangle {
            anchors.bottom: parent.bottom
            anchors.left: parent.left
            anchors.right: parent.right
            height: 30
            gradient: Gradient {
                GradientStop { position: 0.0; color: "transparent" }
                GradientStop { position: 0.5; color: "#4D9FFF" }
                GradientStop { position: 1.0; color: "transparent" }
            }
            opacity: 0.15
        }

        Text {
            anchors.centerIn: parent
            text: "上海工业生产实时监控大屏"
            color: "#ffffff"
            font.pixelSize: 36
            font.bold: true
            font.family: "Microsoft YaHei"
            style: Text.Outline
            styleColor: "#4D9FFF"

            SequentialAnimation on opacity {
                loops: Animation.Infinite
                NumberAnimation { from: 0.85; to: 1; duration: 2000 }
                NumberAnimation { from: 1; to: 0.85; duration: 2000 }
            }
        }

        // 时间显示框
        Rectangle {
            anchors.right: parent.right
            anchors.rightMargin: 30
            anchors.verticalCenter: parent.verticalCenter
            width: 200
            height: 45
            color: "#1A2350"
            radius: 8
            border.color: "#00FFFF"
            border.width: 1

            Text {
                anchors.centerIn: parent
                text: dataManager.lastUpdateTime
                color: "#00FFFF"
                font.pixelSize: 20
                font.family: "Consolas"
                font.bold: true

                SequentialAnimation on scale {
                    loops: Animation.Infinite
                    NumberAnimation { from: 1; to: 1.03; duration: 1000 }
                    NumberAnimation { from: 1.03; to: 1; duration: 1000 }
                }
            }
        }

        // 左侧装饰
        Rectangle {
            anchors.left: parent.left
            anchors.leftMargin: 30
            anchors.verticalCenter: parent.verticalCenter
            width: 50
            height: 50
            radius: 25
            color: "#4D9FFF"
            opacity: 0.2

            Rectangle {
                anchors.centerIn: parent
                width: 30
                height: 30
                radius: 15
                color: "#4D9FFF"
                opacity: 0.5

                Rectangle {
                    anchors.centerIn: parent
                    width: 15
                    height: 15
                    radius: 7.5
                    color: "#4D9FFF"
                    SequentialAnimation on scale {
                        loops: Animation.Infinite
                        NumberAnimation { from: 0.8; to: 1.2; duration: 1500 }
                        NumberAnimation { from: 1.2; to: 0.8; duration: 1500 }
                    }
                }
            }
        }
    }

    // ========== 左侧:产量趋势折线图(炫酷版) ==========
    Rectangle {
        id: lineChart
        anchors.top: parent.top
        anchors.topMargin: 110
        anchors.left: parent.left
        anchors.leftMargin: 40
        width: 820
        height: 420
        color: "#0F1530"
        radius: 15

        // 渐变边框
        border.width: 1
        border.color: "#4D9FFF"

        // 外发光效果
        Rectangle {
            anchors.fill: parent
            radius: 15
            color: "transparent"
            border.width: 2
            border.color: "#4D9FFF"
            opacity: 0.3
        }

        // 标题栏
        Rectangle {
            anchors.top: parent.top
            anchors.left: parent.left
            anchors.right: parent.right
            height: 50
            color: "#1A2350"
            radius: 15
            clip: true

            Text {
                anchors.centerIn: parent
                text: "产量趋势折线图"
                color: "#00FFFF"
                font.pixelSize: 22
                font.bold: true
                font.family: "Microsoft YaHei"
            }

            Rectangle {
                anchors.bottom: parent.bottom
                anchors.left: parent.left
                anchors.right: parent.right
                height: 2
                gradient: Gradient {
                    GradientStop { position: 0.0; color: "transparent" }
                    GradientStop { position: 0.5; color: "#00FFFF" }
                    GradientStop { position: 1.0; color: "transparent" }
                }
            }
        }

        Text {
            anchors.top: parent.top
            anchors.topMargin: 65
            anchors.right: parent.right
            anchors.rightMargin: 50
            text: "单位:吨"
            color: "#6B8CC0"
            font.pixelSize: 14
        }

        Item {
            id: chartContainer
            anchors.fill: parent
            anchors.margins: 40
            anchors.topMargin: 80

            Canvas {
                id: lineCanvas
                anchors.fill: parent

                property variant cachedData: []

                onPaint: {
                    var ctx = getContext("2d");
                    ctx.clearRect(0, 0, width, height);

                    var data = dataManager.lineData;
                    if (!data || data.length === 0) return;

                    cachedData = data.slice()

                    var maxY = 550;
                    var step = width/(data.length-1);

                    // 网格线
                    ctx.shadowBlur = 0;
                    ctx.strokeStyle = "#2A4A6B";
                    ctx.lineWidth = 0.8;
                    for(var i=0;i<=5;i++){
                        ctx.beginPath();
                        ctx.moveTo(0, height/5*i);
                        ctx.lineTo(width, height/5*i);
                        ctx.stroke();

                        ctx.fillStyle = "#6B8CC0";
                        ctx.font = "12px 'Microsoft YaHei'";
                        ctx.fillText(maxY - i*(maxY/5), -30, height/5*i + 4);
                    }

                    // X轴标签
                    var xLabels = ["08:00", "10:00", "12:00", "14:00", "16:00", "18:00", "20:00", "22:00"];
                    ctx.fillStyle = "#6B8CC0";
                    ctx.font = "12px 'Microsoft YaHei'";
                    for(var i=0;i<data.length;i++){
                        ctx.fillText(xLabels[i], step*i - 15, height + 20);
                    }

                    // 渐变填充区域
                    ctx.beginPath();
                    ctx.moveTo(0, height);
                    ctx.lineTo(0, height-data[0]/maxY*height);
                    for(var i=1;i<data.length;i++){
                        ctx.lineTo(step*i, height-data[i]/maxY*height);
                    }
                    ctx.lineTo(width, height);
                    var gradient = ctx.createLinearGradient(0, 0, 0, height);
                    gradient.addColorStop(0, "rgba(77, 159, 255, 0.4)");
                    gradient.addColorStop(1, "rgba(77, 159, 255, 0.05)");
                    ctx.fillStyle = gradient;
                    ctx.fill();

                    // 折线
                    ctx.beginPath();
                    ctx.moveTo(0, height-data[0]/maxY*height);
                    for(var i=1;i<data.length;i++){
                        ctx.lineTo(step*i, height-data[i]/maxY*height);
                    }
                    ctx.strokeStyle = "#4D9FFF";
                    ctx.lineWidth = 3;
                    ctx.shadowBlur = 8;
                    ctx.shadowColor = "#4D9FFF";
                    ctx.stroke();

                    // 数据点
                    for(var i=0;i<data.length;i++){
                        var x = step*i;
                        var y = height-data[i]/maxY*height;

                        // 外光晕
                        ctx.beginPath();
                        ctx.arc(x, y, 10, 0, Math.PI*2);
                        ctx.fillStyle = "rgba(77, 159, 255, 0.3)";
                        ctx.fill();

                        // 内圆点
                        ctx.beginPath();
                        ctx.arc(x, y, 6, 0, Math.PI*2);
                        ctx.fillStyle = "#4D9FFF";
                        ctx.fill();

                        ctx.beginPath();
                        ctx.arc(x, y, 3, 0, Math.PI*2);
                        ctx.fillStyle = "#FFFFFF";
                        ctx.fill();
                    }
                    ctx.shadowBlur = 0;
                }
            }

            // 数据点数值标签
            Repeater {
                id: valueLabels
                model: dataManager.lineData.length

                delegate: Item {
                    id: labelItem
                    width: 50
                    height: 28

                    property real step: lineCanvas.width / (dataManager.lineData.length - 1)
                    property real value: dataManager.lineData[index]
                    property real posX: step * index - 25
                    property real posY: lineCanvas.height - (value / 550 * lineCanvas.height) - 40

                    x: posX
                    y: posY

                    Connections {
                        target: dataManager
                        onLineDataChanged: {
                            labelItem.step = lineCanvas.width / (dataManager.lineData.length - 1)
                            labelItem.value = dataManager.lineData[index]
                            labelItem.posX = labelItem.step * index - 25
                            labelItem.posY = lineCanvas.height - (labelItem.value / 550 * lineCanvas.height) - 40
                        }
                    }

                    Rectangle {
                        anchors.fill: parent
                        color: "#1A2350"
                        border.color: "#4D9FFF"
                        border.width: 1
                        radius: 6

                        Text {
                            anchors.centerIn: parent
                            text: labelItem.value
                            color: "#00FFFF"
                            font.pixelSize: 12
                            font.bold: true
                        }
                    }

                    // 指向线
                    Rectangle {
                        anchors.horizontalCenter: parent.horizontalCenter
                        anchors.top: parent.bottom
                        width: 1
                        height: 12
                        color: "#4D9FFF"
                        opacity: 0.6
                    }
                }
            }
        }
    }

    // ========== 右侧:车间产能直方图(炫酷版) ==========
    Rectangle {
        id: barChart
        anchors.top: parent.top
        anchors.topMargin: 110
        anchors.right: parent.right
        anchors.rightMargin: 40
        width: 820
        height: 420
        color: "#0F1530"
        radius: 15

        border.width: 1
        border.color: "#36D399"

        Rectangle {
            anchors.fill: parent
            radius: 15
            color: "transparent"
            border.width: 2
            border.color: "#36D399"
            opacity: 0.3
        }

        Rectangle {
            anchors.top: parent.top
            anchors.left: parent.left
            anchors.right: parent.right
            height: 50
            color: "#1A2350"
            radius: 15
            clip: true

            Text {
                anchors.centerIn: parent
                text: "车间产能直方图"
                color: "#36D399"
                font.pixelSize: 22
                font.bold: true
            }

            Rectangle {
                anchors.bottom: parent.bottom
                anchors.left: parent.left
                anchors.right: parent.right
                height: 2
                gradient: Gradient {
                    GradientStop { position: 0.0; color: "transparent" }
                    GradientStop { position: 0.5; color: "#36D399" }
                    GradientStop { position: 1.0; color: "transparent" }
                }
            }
        }

        Text {
            anchors.top: parent.top
            anchors.topMargin: 65
            anchors.right: parent.right
            anchors.rightMargin: 50
            text: "单位:吨"
            color: "#6B8CC0"
            font.pixelSize: 14
        }

        Rectangle {
            id: barContainer
            anchors.bottom: parent.bottom
            anchors.bottomMargin: 60
            anchors.horizontalCenter: parent.horizontalCenter
            width: 650
            height: 280
            color: "transparent"

            Canvas {
                id: barCanvas
                anchors.fill: parent

                onPaint: {
                    var ctx = getContext("2d");
                    ctx.clearRect(0, 0, width, height);

                    var data = dataManager.barData;
                    if (!data || data.length === 0) return;

                    var barWidth = 75;
                    var gap = 28;
                    var startX = (width - (barWidth * data.length + gap * (data.length - 1))) / 2;
                    var colors = ["#4D9FFF", "#36D399", "#FBBD23", "#F87272", "#A78BFA", "#22D3EE"];

                    for(var i=0;i<data.length;i++){
                        var barHeight = (data[i] / 550) * height;
                        var x = startX + i * (barWidth + gap);
                        var y = height - barHeight;

                        // 渐变柱子
                        var gradient = ctx.createLinearGradient(x, y, x, y + barHeight);
                        gradient.addColorStop(0, colors[i % colors.length]);
                        gradient.addColorStop(1, Qt.darker(colors[i % colors.length]));
                        ctx.fillStyle = gradient;
                        ctx.fillRect(x, y, barWidth, barHeight);

                        // 柱子顶部高光
                        ctx.fillStyle = "rgba(255,255,255,0.3)";
                        ctx.fillRect(x, y, barWidth, 3);

                        // 数值标签
                        ctx.fillStyle = "#FFFFFF";
                        ctx.font = "bold 14px 'Microsoft YaHei'";
                        ctx.shadowBlur = 4;
                        ctx.shadowColor = "black";
                        ctx.fillText(data[i], x + barWidth/2 - 15, y - 10);

                        // X轴标签
                        var labels = ["车间A", "车间B", "车间C", "车间D", "车间E", "车间F"];
                        ctx.fillStyle = "#C0D8FF";
                        ctx.font = "12px 'Microsoft YaHei'";
                        ctx.fillText(labels[i], x + barWidth/2 - 20, height + 25);
                    }
                    ctx.shadowBlur = 0;
                }
            }
        }
    }

    // ========== 新增:炫酷实时数据表格(完美无报错版) ==========
    Rectangle {
        anchors.top: lineChart.bottom
        anchors.topMargin: 30
        anchors.horizontalCenter: parent.horizontalCenter
        width: 1680
        height: 240
        color: "#0F1530"
        radius: 15
        border.color: "#4D9FFF"
        border.width: 1

        // 外发光效果
        Rectangle {
            anchors.fill: parent
            radius: 15
            color: "transparent"
            border.width: 2
            border.color: "#4D9FFF"
            opacity: 0.3
        }

        // 表格标题
        Rectangle {
            anchors.top: parent.top
            anchors.left: parent.left
            anchors.right: parent.right
            height: 50
            color: "#1A2350"
            radius: 15
            clip: true

            Text {
                anchors.centerIn: parent
                text: "车间实时生产数据报表"
                color: "#00FFFF"
                font.pixelSize: 22
                font.bold: true
            }

            Rectangle {
                anchors.bottom: parent.bottom
                anchors.left: parent.left
                anchors.right: parent.right
                height: 2
                gradient: Gradient {
                    GradientStop { position: 0.0; color: "transparent" }
                    GradientStop { position: 0.5; color: "#00FFFF" }
                    GradientStop { position: 1.0; color: "transparent" }
                }
            }
        }

        // 表格表头
        Row {
            anchors.top: parent.top
            anchors.topMargin: 60
            anchors.horizontalCenter: parent.horizontalCenter
            width: parent.width - 40
            height: 40
            spacing: 0

            Rectangle { width: 240; height: 40; color: "#1A2350"; border.color: "#2A4A6B"; border.width:1; Text { anchors.centerIn: parent; text: "车间编号"; color: "#fff"; font.bold:true; font.pixelSize:16 } }
            Rectangle { width: 240; height: 40; color: "#1A2350"; border.color: "#2A4A6B"; border.width:1; Text { anchors.centerIn: parent; text: "实时产量(吨)"; color: "#fff"; font.bold:true; font.pixelSize:16 } }
            Rectangle { width: 240; height: 40; color: "#1A2350"; border.color: "#2A4A6B"; border.width:1; Text { anchors.centerIn: parent; text: "设备使用率"; color: "#fff"; font.bold:true; font.pixelSize:16 } }
            Rectangle { width: 240; height: 40; color: "#1A2350"; border.color: "#2A4A6B"; border.width:1; Text { anchors.centerIn: parent; text: "产能达标率"; color: "#fff"; font.bold:true; font.pixelSize:16 } }
            Rectangle { width: 240; height: 40; color: "#1A2350"; border.color: "#2A4A6B"; border.width:1; Text { anchors.centerIn: parent; text: "能耗优化率"; color: "#fff"; font.bold:true; font.pixelSize:16 } }
            Rectangle { width: 240; height: 40; color: "#1A2350"; border.color: "#2A4A6B"; border.width:1; Text { anchors.centerIn: parent; text: "运行状态"; color: "#fff"; font.bold:true; font.pixelSize:16 } }
            Rectangle { width: 240; height: 40; color: "#1A2350"; border.color: "#2A4A6B"; border.width:1; Text { anchors.centerIn: parent; text: "更新时间"; color: "#fff"; font.bold:true; font.pixelSize:16 } }
        }

        // 表格内容行
        Column {
            anchors.top: parent.top
            anchors.topMargin: 100
            anchors.horizontalCenter: parent.horizontalCenter
            width: parent.width - 40
            spacing: 0

            // 车间A
            Row {
                width: parent.width; height: 35; spacing: 0
                Rectangle { width:240; height:35; color: "#111835"; border.color: "#2A4A6B"; border.width:1; Text { anchors.centerIn: parent; text: "车间A"; color: "#C0D8FF"; font.pixelSize:14 } }
                Rectangle { width:240; height:35; color: "#111835"; border.color: "#2A4A6B"; border.width:1; Text { anchors.centerIn: parent; text: dataManager.barData[0]; color: "#4D9FFF"; font.bold:true; font.pixelSize:14 } }
                Rectangle { width:240; height:35; color: "#111835"; border.color: "#2A4A6B"; border.width:1; Text { anchors.centerIn: parent; text: dataManager.deviceUsage + "%"; color: "#4D9FFF"; font.bold:true; font.pixelSize:14 } }
                Rectangle { width:240; height:35; color: "#111835"; border.color: "#2A4A6B"; border.width:1; Text { anchors.centerIn: parent; text: dataManager.capacityRate + "%"; color: "#36D399"; font.bold:true; font.pixelSize:14 } }
                Rectangle { width:240; height:35; color: "#111835"; border.color: "#2A4A6B"; border.width:1; Text { anchors.centerIn: parent; text: dataManager.energyRate + "%"; color: "#FBBD23"; font.bold:true; font.pixelSize:14 } }
                Rectangle { width:240; height:35; color: "#111835"; border.color: "#2A4A6B"; border.width:1; Row { anchors.centerIn: parent; spacing:8; Rectangle { width:8; height:8; radius:4; color:"#36D399" }  Text { text:"正常运行"; color:"#36D399"; font.bold:true; font.pixelSize:14 } } }
                Rectangle { width:240; height:35; color: "#111835"; border.color: "#2A4A6B"; border.width:1; Text { anchors.centerIn: parent; text: dataManager.lastUpdateTime; color: "#6B8CC0"; font.pixelSize:13 } }
            }

            // 车间B
            Row {
                width: parent.width; height: 35; spacing: 0
                Rectangle { width:240; height:35; color: "#0F1530"; border.color: "#2A4A6B"; border.width:1; Text { anchors.centerIn: parent; text: "车间B"; color: "#C0D8FF"; font.pixelSize:14 } }
                Rectangle { width:240; height:35; color: "#0F1530"; border.color: "#2A4A6B"; border.width:1; Text { anchors.centerIn: parent; text: dataManager.barData[1]; color: "#4D9FFF"; font.bold:true; font.pixelSize:14 } }
                Rectangle { width:240; height:35; color: "#0F1530"; border.color: "#2A4A6B"; border.width:1; Text { anchors.centerIn: parent; text: dataManager.deviceUsage-5 + "%"; color: "#4D9FFF"; font.bold:true; font.pixelSize:14 } }
                Rectangle { width:240; height:35; color: "#0F1530"; border.color: "#2A4A6B"; border.width:1; Text { anchors.centerIn: parent; text: dataManager.capacityRate-3 + "%"; color: "#36D399"; font.bold:true; font.pixelSize:14 } }
                Rectangle { width:240; height:35; color: "#0F1530"; border.color: "#2A4A6B"; border.width:1; Text { anchors.centerIn: parent; text: dataManager.energyRate+2 + "%"; color: "#FBBD23"; font.bold:true; font.pixelSize:14 } }
                Rectangle { width:240; height:35; color: "#0F1530"; border.color: "#2A4A6B"; border.width:1; Row { anchors.centerIn: parent; spacing:8; Rectangle { width:8; height:8; radius:4; color:"#36D399" }  Text { text:"正常运行"; color:"#36D399"; font.bold:true; font.pixelSize:14 } } }
                Rectangle { width:240; height:35; color: "#0F1530"; border.color: "#2A4A6B"; border.width:1; Text { anchors.centerIn: parent; text: dataManager.lastUpdateTime; color: "#6B8CC0"; font.pixelSize:13 } }
            }

            // 车间C
            Row {
                width: parent.width; height: 35; spacing: 0
                Rectangle { width:240; height:35; color: "#111835"; border.color: "#2A4A6B"; border.width:1; Text { anchors.centerIn: parent; text: "车间C"; color: "#C0D8FF"; font.pixelSize:14 } }
                Rectangle { width:240; height:35; color: "#111835"; border.color: "#2A4A6B"; border.width:1; Text { anchors.centerIn: parent; text: dataManager.barData[2]; color: "#4D9FFF"; font.bold:true; font.pixelSize:14 } }
                Rectangle { width:240; height:35; color: "#111835"; border.color: "#2A4A6B"; border.width:1; Text { anchors.centerIn: parent; text: dataManager.deviceUsage+3 + "%"; color: "#4D9FFF"; font.bold:true; font.pixelSize:14 } }
                Rectangle { width:240; height:35; color: "#111835"; border.color: "#2A4A6B"; border.width:1; Text { anchors.centerIn: parent; text: dataManager.capacityRate+5 + "%"; color: "#36D399"; font.bold:true; font.pixelSize:14 } }
                Rectangle { width:240; height:35; color: "#111835"; border.color: "#2A4A6B"; border.width:1; Text { anchors.centerIn: parent; text: dataManager.energyRate-1 + "%"; color: "#FBBD23"; font.bold:true; font.pixelSize:14 } }
                Rectangle { width:240; height:35; color: "#111835"; border.color: "#2A4A6B"; border.width:1; Row { anchors.centerIn: parent; spacing:8; Rectangle { width:8; height:8; radius:4; color:"#36D399" }  Text { text:"正常运行"; color:"#36D399"; font.bold:true; font.pixelSize:14 } } }
                Rectangle { width:240; height:35; color: "#111835"; border.color: "#2A4A6B"; border.width:1; Text { anchors.centerIn: parent; text: dataManager.lastUpdateTime; color: "#6B8CC0"; font.pixelSize:13 } }
            }
        }

        // 呼吸动画
        SequentialAnimation on opacity {
            loops: Animation.Infinite
            NumberAnimation { from: 0.95; to: 1; duration: 1500 }
            NumberAnimation { from: 1; to: 0.95; duration: 1500 }
        }
    }

    // ========== 底部环形图(炫酷版) ==========

    // ========== 底部环形图(缩小 + 移到右侧,不遮挡表格) ==========
    Row {
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.bottom: parent.bottom
        anchors.bottomMargin: 60
        spacing: 40  // 缩小间距

        // 设备使用率 - 缩小
        Item {
            width: 180
            height: 180

            Canvas {
                id: ringCanvas1
                anchors.fill: parent

                onPaint: {
                    var ctx = getContext("2d");
                    ctx.clearRect(0, 0, width, height);
                    var cx = width/2;
                    var cy = height/2 - 15;
                    var r = 60;  // 缩小半径
                    var w = 12;  // 缩小环宽

                    var percent = dataManager.deviceUsage;

                    ctx.shadowBlur = 10;
                    ctx.shadowColor = "#4D9FFF";

                    ctx.beginPath();
                    ctx.arc(cx, cy, r, 0, Math.PI * 2);
                    ctx.strokeStyle = "#1A2350";
                    ctx.lineWidth = w;
                    ctx.stroke();

                    var startAngle = -Math.PI / 2;
                    var endAngle = startAngle + (Math.PI * 2 * percent / 100);
                    ctx.beginPath();
                    ctx.arc(cx, cy, r, startAngle, endAngle);
                    ctx.strokeStyle = "#4D9FFF";
                    ctx.lineWidth = w;
                    ctx.lineCap = "round";
                    ctx.stroke();

                    ctx.shadowBlur = 0;
                }
            }

            Text {
                anchors.centerIn: parent
                anchors.verticalCenterOffset: -15
                text: dataManager.deviceUsage + "%"
                color: "#4D9FFF"
                font.pixelSize: 32
                font.bold: true
            }

            Text {
                anchors.top: parent.top
                anchors.topMargin: 150
                anchors.horizontalCenter: parent.horizontalCenter
                text: "设备使用率"
                color: "#C0D8FF"
                font.pixelSize: 16
                font.bold: true
            }

            Rectangle {
                anchors.top: parent.top
                anchors.topMargin: 175
                anchors.horizontalCenter: parent.horizontalCenter
                width: 40
                height: 2
                color: "#4D9FFF"
                opacity: 0.5
            }
        }

        // 产能达标率 - 缩小
        Item {
            width: 180
            height: 180

            Canvas {
                id: ringCanvas2
                anchors.fill: parent

                onPaint: {
                    var ctx = getContext("2d");
                    ctx.clearRect(0, 0, width, height);
                    var cx = width/2;
                    var cy = height/2 - 15;
                    var r = 60;
                    var w = 12;

                    var percent = dataManager.capacityRate;

                    ctx.shadowBlur = 10;
                    ctx.shadowColor = "#36D399";

                    ctx.beginPath();
                    ctx.arc(cx, cy, r, 0, Math.PI * 2);
                    ctx.strokeStyle = "#1A2350";
                    ctx.lineWidth = w;
                    ctx.stroke();

                    var startAngle = -Math.PI / 2;
                    var endAngle = startAngle + (Math.PI * 2 * percent / 100);
                    ctx.beginPath();
                    ctx.arc(cx, cy, r, startAngle, endAngle);
                    ctx.strokeStyle = "#36D399";
                    ctx.lineWidth = w;
                    ctx.lineCap = "round";
                    ctx.stroke();

                    ctx.shadowBlur = 0;
                }
            }

            Text {
                anchors.centerIn: parent
                anchors.verticalCenterOffset: -15
                text: dataManager.capacityRate + "%"
                color: "#36D399"
                font.pixelSize: 32
                font.bold: true
            }

            Text {
                anchors.top: parent.top
                anchors.topMargin: 150
                anchors.horizontalCenter: parent.horizontalCenter
                text: "产能达标率"
                color: "#C0D8FF"
                font.pixelSize: 16
                font.bold: true
            }

            Rectangle {
                anchors.top: parent.top
                anchors.topMargin: 175
                anchors.horizontalCenter: parent.horizontalCenter
                width: 40
                height: 2
                color: "#36D399"
                opacity: 0.5
            }
        }

        // 能耗优化率 - 缩小
        Item {
            width: 180
            height: 180

            Canvas {
                id: ringCanvas3
                anchors.fill: parent

                onPaint: {
                    var ctx = getContext("2d");
                    ctx.clearRect(0, 0, width, height);
                    var cx = width/2;
                    var cy = height/2 - 15;
                    var r = 60;
                    var w = 12;

                    var percent = dataManager.energyRate;

                    ctx.shadowBlur = 10;
                    ctx.shadowColor = "#FBBD23";

                    ctx.beginPath();
                    ctx.arc(cx, cy, r, 0, Math.PI * 2);
                    ctx.strokeStyle = "#1A2350";
                    ctx.lineWidth = w;
                    ctx.stroke();

                    var startAngle = -Math.PI / 2;
                    var endAngle = startAngle + (Math.PI * 2 * percent / 100);
                    ctx.beginPath();
                    ctx.arc(cx, cy, r, startAngle, endAngle);
                    ctx.strokeStyle = "#FBBD23";
                    ctx.lineWidth = w;
                    ctx.lineCap = "round";
                    ctx.stroke();

                    ctx.shadowBlur = 0;
                }
            }

            Text {
                anchors.centerIn: parent
                anchors.verticalCenterOffset: -15
                text: dataManager.energyRate + "%"
                color: "#FBBD23"
                font.pixelSize: 32
                font.bold: true
            }

            Text {
                anchors.top: parent.top
                anchors.topMargin: 150
                anchors.horizontalCenter: parent.horizontalCenter
                text: "能耗优化率"
                color: "#C0D8FF"
                font.pixelSize: 16
                font.bold: true
            }

            Rectangle {
                anchors.top: parent.top
                anchors.topMargin: 175
                anchors.horizontalCenter: parent.horizontalCenter
                width: 40
                height: 2
                color: "#FBBD23"
                opacity: 0.5
            }
        }
    }
    // ========== 底部状态栏(炫酷版) ==========
    Rectangle {
        anchors.bottom: parent.bottom
        anchors.left: parent.left
        anchors.right: parent.right
        height: 35
        color: "#0F1530"

        Rectangle {
            anchors.top: parent.top
            anchors.left: parent.left
            anchors.right: parent.right
            height: 1
            gradient: Gradient {
                GradientStop { position: 0.0; color: "transparent" }
                GradientStop { position: 0.5; color: "#4D9FFF" }
                GradientStop { position: 1.0; color: "transparent" }
            }
            opacity: 0.5
        }

        Text {
            anchors.left: parent.left
            anchors.leftMargin: 40
            anchors.verticalCenter: parent.verticalCenter
            text: "⚡ 数据实时更新中 | 最后更新: " + dataManager.lastUpdateTime
            color: "#6B8CC0"
            font.pixelSize: 13
            font.family: "Consolas"
        }

        Row {
            anchors.right: parent.right
            anchors.rightMargin: 40
            anchors.verticalCenter: parent.verticalCenter
            spacing: 15

            Rectangle {
                width: 8
                height: 8
                radius: 4
                color: "#36D399"
                SequentialAnimation on opacity {
                    loops: Animation.Infinite
                    NumberAnimation { from: 0.3; to: 1; duration: 1000 }
                    NumberAnimation { from: 1; to: 0.3; duration: 1000 }
                }
            }

            Text {
                text: "系统运行正常"
                color: "#36D399"
                font.pixelSize: 13
            }

            Rectangle {
                width: 8
                height: 8
                radius: 4
                color: "#4D9FFF"
                SequentialAnimation on opacity {
                    loops: Animation.Infinite
                    NumberAnimation { from: 0.3; to: 1; duration: 800 }
                    NumberAnimation { from: 1; to: 0.3; duration: 800 }
                }
            }

            Text {
                text: "数据同步中"
                color: "#4D9FFF"
                font.pixelSize: 13
            }
        }
    }
}

4 遇到的问题

1 qml收不到信号

复制代码
Connections {
    target: dataManager
    onLineDataChanged: {
        console.log("信号收到")
        lineCanvas.requestPaint()
    }
}

正确

复制代码
Connections {
    target: dataManager
    function onLineDataChanged() {
        console.log("信号收到")
        lineCanvas.requestPaint()
    }
}

有问题

信号处理格式 : 使用 onSignalName: 而不是 function onSignalName()

2 像C++那样改为全局200ms刷新卡顿

解决方案对比

方案1:使用 QML 的图形类型(推荐)

方案2:使用 QQuickPaintedItem (C++)

方案3:改用 QML + Shader (最强性能)

相关推荐
小短腿的代码世界1 小时前
Qt libQGLViewer 深度解析:高性能OpenGL 3D交互查看器的架构设计与性能优化
qt·3d·交互
承渊政道1 小时前
【贪心算法】(经典实战应用解析(一):柠檬水找零、将数组和减半的最少操作次数、最大数、摆动序列)
数据结构·c++·学习·算法·leetcode·贪心算法·排序算法
脆皮炸鸡7551 小时前
大山之二:文件系统(Ext系列)
linux·开发语言·经验分享·学习方法
少司府1 小时前
C++基础入门:vector深度解析(七千字深度剖析)
c语言·开发语言·数据结构·c++·容器·vector·顺序表
yqcoder1 小时前
突破性能瓶颈:深入理解 JavaScript TypedArray
java·开发语言·javascript
yqcoder1 小时前
JS 中的“空”之双雄:null vs undefined
开发语言·前端·javascript
ch.ju1 小时前
Java Programming Chapter 3——Traversal of array
java·开发语言
郑寿昌1 小时前
2026年AR交互新趋势:多模态意图识别
ar·交互
计算机安禾1 小时前
【c++面向对象编程】第8篇:const成员与mutable:常对象与常函数
开发语言·javascript·c++