【问题标题】:PySide QML Charts update Series with real-time dataPySide QML Charts 使用实时数据更新系列
【发布时间】:2021-02-20 01:27:41
【问题描述】:

我尝试使用使用 OPC UA 协议接收的新数据动态更新图表系列

Python 代码:

class Thread(QThread):

    motor1 = Signal(int)
    motor2 = Signal(int)
    motor3 = Signal(int)
    var = Signal(int)
    strr = Signal(str)

    def run(self):
        client.connect()

        while True:
            d1 = client.get_node("ns=4;s=Deger_1")
            d2 = client.get_node("ns=4;s=Deger_2")
            d3 = client.get_node("ns=4;s=Deger_3")
            button = client.get_node("ns=4;s=QT_Button")
            string = client.get_node("ns=4;s=QT_String")
            button = button.get_value()
            string = string.get_value()
            d1 = d1.get_value()
            d2 = d2.get_value()
            d3 = d3.get_value()
            self.motor1.emit(d1)
            self.motor2.emit(d2)
            self.motor3.emit(d3)
            self.var.emit(d1)
            self.strr.emit(string)


    class ChartModel(QObject):
    def __init__(self, parent=None):
        super(ChartModel, self).__init__(parent)
        self.thread = Thread()
        self.thread.var.connect(self.opcua)
        self.thread.start()
        self.timestamp = time()
        self.my_data = []

        self.my_list = []

        self.index = -1

    @Slot(QtCharts.QAbstractSeries)
    def update_series(self, series):
        self.index += 1
        if self.index > 4:
            self.index = 0
        series.clear()

        for p in self.my_data[self.index]:
            series.append(p.x(), p.y())

    @Slot()
    def generateData(self):

        for i in range(5):

            my_list = []
            for j in range(500):
                my_list.append(QPoint(j, random.uniform(1, 70)))

            self.my_data.append(my_list)

    @Slot(int)
    def opcua(self, val):
        tsignal = time() - self.timestamp
        XY = QPoint(tsignal, val)
        self.my_list.append(XY)

    @Slot()
    def get_data(self):
        self.my_data.append(self.my_list)
        print(len(self.my_data))


    class MainWindow(QObject):
    def __init__(self):
        QObject.__init__(self)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    main = MainWindow()
    chartmodel = ChartModel()
    engine = QQmlApplicationEngine()
    # engine.rootContext().setContextProperty("backend", main)
    engine.rootContext().setContextProperty("chartmodel", chartmodel)
    engine.load(os.path.join(os.path.dirname(__file__), "qml/main.qml"))
    if not engine.rootObjects():
        sys.exit(-1)
    sys.exit(app.exec_())

QML 代码

import QtQuick 2.6
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
import QtCharts 2.0
import QtQuick.Controls.Styles 1.0
import QtQuick.Dialogs 1.1


Item {
   width: 1000
   height: 800


    Rectangle {
         id: rectangle
          property int amountOfData: 0
          color: "#27273a"
          anchors.fill: parent
       Timer{
            id: miTimer
            interval: 100
            running: true
            repeat: true
            onTriggered: {

                 chartmodel.update_series(chartViewItem.series(0))




        }
    }
    MessageDialog {
        id: msgbox
        title: "Error"
        text: "Data are not accepted !"
        onAccepted: {
            msgbox.close();


        }
        Component.onCompleted: visible = false
    }

    ChartView {
        id: chartViewItem
        x: 0
        y: 0
        width: 752
        height: 592
        antialiasing: true
        theme:ChartView.ChartThemeDark
        ValueAxis {
            id: axisX
            min:0
            max:500

         }

        ValueAxis{
            id: axisY
            min:0
            max:100
        }

        Rectangle {
            id: horizontalScrollMask
            visible: false
            anchors.fill: parent
        }

        MouseArea {
            id: chartMouseAreaA
            anchors.fill: parent
            anchors.rightMargin: -8
            anchors.bottomMargin: -8
            anchors.leftMargin: 8
            anchors.topMargin: 8

            acceptedButtons: Qt.LeftButton | Qt.RightButton

            onMouseXChanged: {
                if ((mouse.buttons & Qt.LeftButton) == Qt.LeftButton) {
                    chartViewItem.scrollLeft(mouseX - horizontalScrollMask.x);


                    horizontalScrollMask.x = mouseX;
                }
            }
            onPressed: {
                if (mouse.button == Qt.LeftButton) {
                    horizontalScrollMask.x = mouseX;
                }
            }




        }


    }

    TextField {
        id: mintxt
        x: 766
        y: 68
        placeholderText: qsTr("min X")
    }

    TextField {
        id: maxtxt
        x: 766
        y: 124
        placeholderText: qsTr("max X")
    }

    Button {
        id: button
        x: 825
        y: 176
        text: qsTr("Zoom")
        onClicked: {
            if(mintxt.text>maxtxt.text)
                msgbox.open()
            else

                axisX.min=mintxt.text;
                axisX.max=maxtxt.text;
        }
    }







}


Component.onCompleted: {
    var series = chartViewItem.createSeries(ChartView.SeriesTypeSpline,"Random",axisX,axisY)


    chartmodel.get_data()


}
}

当我使用 chartmodel.generateData() 时,代码适用于生成的数据,但是当我尝试 get_data 函数时,它返回以下错误:

错误:列表索引超出范围

如何用新数据而不是生成的数据更新图表?

【问题讨论】:

    标签: python qt qml pyside2


    【解决方案1】:

    问题是OP在不理解代码的情况下复制代码,例如索引是否必要?索引的目的是什么?当然,在原始示例中,代码作者试图展示一个显示循环数据的简单示例。

    在这种情况下,您必须遍历列表:

    import os
    import sys
    
    from PySide2.QtCore import *
    from PySide2.QtWidgets import *
    from PySide2.QtCharts import *
    from PySide2.QtQml import *
    from time import *
    import random
    
    
    class Thread(QThread):
    
        motor1 = Signal(int)
        motor2 = Signal(int)
        motor3 = Signal(int)
        var = Signal(int)
        strr = Signal(str)
    
        def run(self):
            client.connect()
    
            while True:
                d1 = client.get_node("ns=4;s=Deger_1")
                d2 = client.get_node("ns=4;s=Deger_2")
                d3 = client.get_node("ns=4;s=Deger_3")
                button = client.get_node("ns=4;s=QT_Button")
                string = client.get_node("ns=4;s=QT_String")
                button = button.get_value()
                string = string.get_value()
                d1 = d1.get_value()
                d2 = d2.get_value()
                d3 = d3.get_value()
                self.motor1.emit(d1)
                self.motor2.emit(d2)
                self.motor3.emit(d3)
                self.var.emit(d1)
                self.strr.emit(string)
    
    
    class ChartModel(QObject):
        def __init__(self, parent=None):
            super(ChartModel, self).__init__(parent)
            self.thread = Thread()
            self.thread.var.connect(self.opcua)
            self.thread.start()
            self.timestamp = time()
    
            self.my_list = []
    
        @Slot(QtCharts.QAbstractSeries)
        def update_series(self, series):
            series.clear()
    
            for p in self.my_list:
                series.append(p.x(), p.y())
    
        @Slot(int)
        def opcua(self, val):
            tsignal = time() - self.timestamp
            XY = QPoint(tsignal, val)
            self.my_list.append(XY)
    
    
    class MainWindow(QObject):
        def __init__(self):
            QObject.__init__(self)
    
    
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        main = MainWindow()
        chartmodel = ChartModel()
        engine = QQmlApplicationEngine()
        # engine.rootContext().setContextProperty("backend", main)
        engine.rootContext().setContextProperty("chartmodel", chartmodel)
        engine.load(os.path.join(os.path.dirname(__file__), "qml/main.qml"))
        if not engine.rootObjects():
            sys.exit(-1)
        sys.exit(app.exec_())
    
    import QtQuick 2.6
    import QtQuick.Window 2.2
    import QtQuick.Controls 2.2
    import QtCharts 2.0
    import QtQuick.Controls.Styles 1.0
    import QtQuick.Dialogs 1.1
    
    
    Window {
        width: 1000
        height: 800
        visible: true
    
    
        Rectangle {
            id: rectangle
            property int amountOfData: 0
            color: "#27273a"
            anchors.fill: parent
            Timer{
                id: miTimer
                interval: 100
                running: true
                repeat: true
                onTriggered: {
                    chartmodel.update_series(chartViewItem.series(0))
                }
            }
            MessageDialog {
                id: msgbox
                title: "Error"
                text: "Data are not accepted !"
                onAccepted: {
                    msgbox.close();
    
    
                }
                Component.onCompleted: visible = false
            }
    
            ChartView {
                id: chartViewItem
                x: 0
                y: 0
                width: 752
                height: 592
                antialiasing: true
                theme:ChartView.ChartThemeDark
                ValueAxis {
                    id: axisX
                    min:0
                    max:500
    
                }
    
                ValueAxis{
                    id: axisY
                    min:0
                    max:100
                }
    
                Rectangle {
                    id: horizontalScrollMask
                    visible: false
                    anchors.fill: parent
                }
    
                MouseArea {
                    id: chartMouseAreaA
                    anchors.fill: parent
                    anchors.rightMargin: -8
                    anchors.bottomMargin: -8
                    anchors.leftMargin: 8
                    anchors.topMargin: 8
    
                    acceptedButtons: Qt.LeftButton | Qt.RightButton
    
                    onMouseXChanged: {
                        if ((mouse.buttons & Qt.LeftButton) == Qt.LeftButton) {
                            chartViewItem.scrollLeft(mouseX - horizontalScrollMask.x);
    
    
                            horizontalScrollMask.x = mouseX;
                        }
                    }
                    onPressed: {
                        if (mouse.button == Qt.LeftButton) {
                            horizontalScrollMask.x = mouseX;
                        }
                    }
                }
            }
    
            TextField {
                id: mintxt
                x: 766
                y: 68
                placeholderText: qsTr("min X")
            }
    
            TextField {
                id: maxtxt
                x: 766
                y: 124
                placeholderText: qsTr("max X")
            }
    
            Button {
                id: button
                x: 825
                y: 176
                text: qsTr("Zoom")
                onClicked: {
                    if(mintxt.text>maxtxt.text)
                        msgbox.open()
                    else
    
                        axisX.min=mintxt.text;
                    axisX.max=maxtxt.text;
                }
            }
        }
    
        Component.onCompleted: {
            var series = chartViewItem.createSeries(ChartView.SeriesTypeSpline,"Random",axisX,axisY)
            miTimer.start()
        }
    }
    

    【讨论】:

    • 谢谢,我还有一个问题,如何让 X 轴最大值和最小值根据收到的数据滚动?
    • @user31562 如果您还有其他问题,请创建另一个帖子(请详细说明),这些是网站规则。
    猜你喜欢
    • 1970-01-01
    • 2018-04-18
    • 1970-01-01
    • 2012-11-05
    • 1970-01-01
    • 2017-08-06
    • 2021-11-08
    • 1970-01-01
    • 2016-12-29
    相关资源
    最近更新 更多