如何解决运行多个PYQT或PYQTGRAPH绘图组件的自我崩溃问​​题?

发布于 2025-01-18 00:20:15 字数 5214 浏览 3 评论 0原文

输入图片这里的描述

我设计了界面,自定义组件尝试输出多个绘图组件,过了一会程序就崩溃了。

该程序可能包含以下内容:ble. Py 读取临时保存 EMG 数组的蓝牙值。 main_plot.py实例化Show_EMG绘图类并输出Show_EMG绘图类读取ble.PY的蓝牙值

程序自行崩溃,没有报告任何错误,我尝试输出错误在不同的航站楼。

错误信息: 输入图片此处描述

在此处输入图像描述

CMD: 输入图片此处描述

pyqtgraph 组件代码(Show_EMG.py):

import ble
from pyqtgraph import PlotWidget
import pyqtgraph as pg
import numpy as np
from PyQt5 import QtCore

class Plot_Show(object):
    '''
    Form,y,x,data,length = 1800, width = 250, high = 120, text = "sEMG Voltage"
    '''
    def __init__(self,Form,y,x,data,text=""):
        # length = 1800, width = 250, high = 120, text = "sEMG Voltage"
        self.Form=Form
        self.y=y
        self.x=x
        self.data=ble.EMG[data]
        self.length=1800
        if(text==""):
            self.test="sEMG Voltage"
        else:
            self.text = text
        self.graphicsView = PlotWidget(self.Form)
        self.initUI()


    def initUI(self):

        self.graphicsView.setGeometry(QtCore.QRect(self.y, self.x, 250, 120))
        self.graphicsView.hideButtons()
        self.graphicsView.setObjectName(self.text)


        self.graphicsView.setLabel(axis="left",text=self.text)
        self.graphicsView.setLabel(axis='bottom',text='Time')
        self.graphicsView.setMouseEnabled(x=False,y=False)
        self.graphicsView.setAntialiasing(True)
        self.graphicsView.setMenuEnabled(False)
        self.graphicsView.hideButtons()
        self.data1 = np.zeros(self.length)
        self.curve1 = self.graphicsView.plot(self.data1)
        self.ptr1 = 0

        def update1():
            global data1, ptr1
            self.graphicsView.setRange(xRange=[self.ptr1,self.ptr1+self.length],yRange=[5,550],padding=0)
            self.data1[:-1] = self.data1[1:]  # shift data in the array one sample left

            self.data1[-1] = self.data

            self.ptr1 += 1
            self.curve1.setData(self.data1)
            self.curve1.setPos(self.ptr1, 0)

        self.timer = pg.QtCore.QTimer()
        self.timer.timeout.connect(update1)
        self.timer.start(10)

main_plot.py 代码:

import ble
import sys

import Show_EMG
from PyQt5 import QtCore, QtWidgets
import threading

class Ui_Form(object):
    def __init__(self):
        super().__init__()

    def setupUi(self, Form,**kwargs):
        Form.resize(820, 454)
        Form.setObjectName("Form")

                Show_EMG.Plot_Show(Form=Form, y=10, x=10, data=0, text="sEMG2 Voltage")
        Show_EMG.Plot_Show(Form=Form, y=10, x=140, data=1, text="sEMG2 Voltage")
        Show_EMG.Plot_Show(Form=Form, y=10, x=270, data=2, text="sEMG3 Voltage")
        Show_EMG.Plot_Show(Form=Form, y=280, x=10, data=3, text="sEMG4 Voltage")
        Show_EMG.Plot_Show(Form=Form, y=280, x=140, data=4, text="sEMG5 Voltage")
        Show_EMG.Plot_Show(Form=Form, y=280, x=270, data=5, text="sEMG6 Voltage")
        Show_EMG.Plot_Show(Form=Form, y=550, x=10, data=0, text="sEMG7 Voltage")
        Show_EMG.Plot_Show(Form=Form, y=550, x=140, data=0, text="sEMG8 Voltage")

        self.gridLayoutWidget = QtWidgets.QWidget(Form)
        self.gridLayoutWidget.setGeometry(QtCore.QRect(550, 270, 261, 121))
        self.gridLayoutWidget.setObjectName("gridLayoutWidget")
        self.gridLayout = QtWidgets.QGridLayout(self.gridLayoutWidget)
        self.gridLayout.setContentsMargins(0, 0, 0, 0)
        self.gridLayout.setObjectName("gridLayout")
        self.pushButton = QtWidgets.QPushButton(Form)
        self.pushButton.setGeometry(QtCore.QRect(370, 410, 75, 23))
        self.pushButton.setObjectName("pushButton")

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        self.pushButton.setText(_translate("Form", "开始记录"))
        Form.setWindowTitle(_translate("Form", "Form"))

def main():
    app = QtWidgets.QApplication(sys.argv)
    Form = QtWidgets.QWidget()
    ui = Ui_Form()
    ui.setupUi(Form)
    Form.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    thread_main=threading.Thread(target=main)
    thread_main.start()
    thread_ble=threading.Thread(target=ble.ble)
    thread_ble.start()

Ble.EMG 数组暂时默认为:[200. 0. 0. 0. 0. 0.]

更多 Ble 代码详细信息: https://gist.github.com/allrobot/1547447f313942f278118cb2e569f59f

我尝试在main_plot.py,但程序仍然自行崩溃...

也许 QTimer 应该是问题的原因?

如何更改代码来解决自崩溃问题?我需要修复自定义组件类,但我是 PyQT 的新手,您有什么建议吗?

enter image description here

I designed the interface, and the custom component tried to output multiple drawing components, and the program crashed after a while.

The program probably consists of the following:ble. Py reads the bluetooth values temporarily holding the EMG array. main_plot.py instantiates the Show_EMG plotting class and outputs the Show_EMG plotting class reading the Bluetooth values of ble.PY

The program crashed itself without reporting any errors, I tried to output errors at different terminals.

ERROR MESSAGE:
enter image description here

enter image description here

CMD:
enter image description here

pyqtgraph Component Code(Show_EMG.py):

import ble
from pyqtgraph import PlotWidget
import pyqtgraph as pg
import numpy as np
from PyQt5 import QtCore

class Plot_Show(object):
    '''
    Form,y,x,data,length = 1800, width = 250, high = 120, text = "sEMG Voltage"
    '''
    def __init__(self,Form,y,x,data,text=""):
        # length = 1800, width = 250, high = 120, text = "sEMG Voltage"
        self.Form=Form
        self.y=y
        self.x=x
        self.data=ble.EMG[data]
        self.length=1800
        if(text==""):
            self.test="sEMG Voltage"
        else:
            self.text = text
        self.graphicsView = PlotWidget(self.Form)
        self.initUI()


    def initUI(self):

        self.graphicsView.setGeometry(QtCore.QRect(self.y, self.x, 250, 120))
        self.graphicsView.hideButtons()
        self.graphicsView.setObjectName(self.text)


        self.graphicsView.setLabel(axis="left",text=self.text)
        self.graphicsView.setLabel(axis='bottom',text='Time')
        self.graphicsView.setMouseEnabled(x=False,y=False)
        self.graphicsView.setAntialiasing(True)
        self.graphicsView.setMenuEnabled(False)
        self.graphicsView.hideButtons()
        self.data1 = np.zeros(self.length)
        self.curve1 = self.graphicsView.plot(self.data1)
        self.ptr1 = 0

        def update1():
            global data1, ptr1
            self.graphicsView.setRange(xRange=[self.ptr1,self.ptr1+self.length],yRange=[5,550],padding=0)
            self.data1[:-1] = self.data1[1:]  # shift data in the array one sample left

            self.data1[-1] = self.data

            self.ptr1 += 1
            self.curve1.setData(self.data1)
            self.curve1.setPos(self.ptr1, 0)

        self.timer = pg.QtCore.QTimer()
        self.timer.timeout.connect(update1)
        self.timer.start(10)

main_plot.py Code:

import ble
import sys

import Show_EMG
from PyQt5 import QtCore, QtWidgets
import threading

class Ui_Form(object):
    def __init__(self):
        super().__init__()

    def setupUi(self, Form,**kwargs):
        Form.resize(820, 454)
        Form.setObjectName("Form")

                Show_EMG.Plot_Show(Form=Form, y=10, x=10, data=0, text="sEMG2 Voltage")
        Show_EMG.Plot_Show(Form=Form, y=10, x=140, data=1, text="sEMG2 Voltage")
        Show_EMG.Plot_Show(Form=Form, y=10, x=270, data=2, text="sEMG3 Voltage")
        Show_EMG.Plot_Show(Form=Form, y=280, x=10, data=3, text="sEMG4 Voltage")
        Show_EMG.Plot_Show(Form=Form, y=280, x=140, data=4, text="sEMG5 Voltage")
        Show_EMG.Plot_Show(Form=Form, y=280, x=270, data=5, text="sEMG6 Voltage")
        Show_EMG.Plot_Show(Form=Form, y=550, x=10, data=0, text="sEMG7 Voltage")
        Show_EMG.Plot_Show(Form=Form, y=550, x=140, data=0, text="sEMG8 Voltage")

        self.gridLayoutWidget = QtWidgets.QWidget(Form)
        self.gridLayoutWidget.setGeometry(QtCore.QRect(550, 270, 261, 121))
        self.gridLayoutWidget.setObjectName("gridLayoutWidget")
        self.gridLayout = QtWidgets.QGridLayout(self.gridLayoutWidget)
        self.gridLayout.setContentsMargins(0, 0, 0, 0)
        self.gridLayout.setObjectName("gridLayout")
        self.pushButton = QtWidgets.QPushButton(Form)
        self.pushButton.setGeometry(QtCore.QRect(370, 410, 75, 23))
        self.pushButton.setObjectName("pushButton")

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        self.pushButton.setText(_translate("Form", "开始记录"))
        Form.setWindowTitle(_translate("Form", "Form"))

def main():
    app = QtWidgets.QApplication(sys.argv)
    Form = QtWidgets.QWidget()
    ui = Ui_Form()
    ui.setupUi(Form)
    Form.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    thread_main=threading.Thread(target=main)
    thread_main.start()
    thread_ble=threading.Thread(target=ble.ble)
    thread_ble.start()

Ble.EMG array default temporarily to:[200. 0. 0. 0. 0. 0.]

More Ble Code detail:
https://gist.github.com/allrobot/1547447f313942f278118cb2e569f59f

I tried to add threads in main_plot.py, but the program still crashes itself...

Perhaps QTimer should be the cause of the problem?

How can I change the code to solve the self-crash problem?I need to fix the custom component classes, but I am novice to PyQT, you have any suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

や莫失莫忘 2025-01-25 00:20:15

如您已经知道(所有)GUI不应在分离的线程中运行。

但是我用代码遇到的主要问题是,如果未分配给全球变量或类变量,则PYQT中的某些元素无效。

绘图未分配给变量时,其qtimer对我不起作用。

因此,我将所有情节都放在列表上,现在所有QTimers(没有特殊线程)对我有用。

        self.plots = [
            PlotShow(...),
            PlotShow(...),
            PlotShow(...),
            # ...
        ]

完整的工作代码。

我使用类ble仿真模块ble.py,并将所有代码在一个文件中(用于测试)。

我还做了一些小更改: pep 8- python代码的样式指南

#import ble
from PyQt5 import QtCore, QtWidgets
import pyqtgraph as pg   # pg.PlotWidget
import numpy as np
import threading


class ble:
    ''' Simulate module `ble.py` '''
    
    EMG = [0,0,0,0,0,0,0,0,0,0,0,0,0]
    
    def ble():
        import math
        import random
        import time

        counter = 0
        
        while True:
        
            for i in range(10):
            
                if i in (0, 4, 8):
                    ble.EMG[i] = random.randint(0, 550)
                elif i in (1, 5, 6):
                    ble.EMG[i] = random.randint(150, 250)
                else:
                    ble.EMG[i] = 200 + math.sin(math.radians(counter//i)) * 200
            
            counter += 1
            time.sleep(0.1)
    
class PlotShow():  # PE8: `CamelNames` for classes
    '''
    form, y, x, data, length=1800, width=250, high=120, text="sEMG Voltage"
    '''
    def __init__(self, form, y, x, data_number, text=""):   # PEP8: spaces after commans `,`
        self.form = form   # PE8: `lower_case_names` for variables
        self.y = y
        self.x = x
        self.data_number = data_number
        self.length = 1800

        self.data = np.zeros(self.length)
        self.ptr  = 0
        
        if not text:
            self.test="sEMG Voltage"
        else:
            self.text = text
        
        self.initUI()

        #print('start:', self.text)
        self.timer = pg.QtCore.QTimer()
        self.timer.timeout.connect(self.update_plot)
        self.timer.start(10)


    def initUI(self):
        self.graphicsView = pg.PlotWidget(self.form)

        self.graphicsView.setGeometry(QtCore.QRect(self.y, self.x, 250, 120))
        self.graphicsView.hideButtons()
        self.graphicsView.setObjectName(self.text)

        self.graphicsView.setLabel(axis="left",text=self.text)
        self.graphicsView.setLabel(axis='bottom',text='Time')
        self.graphicsView.setMouseEnabled(x=False,y=False)
        self.graphicsView.setAntialiasing(True)
        self.graphicsView.setMenuEnabled(False)
        self.graphicsView.hideButtons()
        
        self.curve = self.graphicsView.plot(self.data)

    def update_plot(self):
        #print('update:', self.text)
        
        self.data[:-1] = self.data[1:]  # shift data in the array one sample left
        self.data[-1]  = ble.EMG[self.data_number]

        self.ptr += 1

        self.curve.setData(self.data)
        self.curve.setPos(self.ptr, 0)
        self.graphicsView.setRange(xRange=[self.ptr, self.ptr+self.length], yRange=[5, 550], padding=0)  # PEP8: spaces after commans `,`

        
class UIForm():  # PE8: `CamelNames` for classes

    def setupUI(self, form, **kwargs):
        form.resize(820, 454)
        form.setObjectName("Form")

        self.plots = [
            PlotShow(form=form, y=10,  x=10,  data_number=0, text="sEMG1 Voltage"),
            PlotShow(form=form, y=10,  x=140, data_number=1, text="sEMG2 Voltage"),
            PlotShow(form=form, y=10,  x=270, data_number=2, text="sEMG3 Voltage"),
            PlotShow(form=form, y=280, x=10,  data_number=3, text="sEMG4 Voltage"),
            PlotShow(form=form, y=280, x=140, data_number=4, text="sEMG5 Voltage"),
            PlotShow(form=form, y=280, x=270, data_number=5, text="sEMG6 Voltage"),
            PlotShow(form=form, y=550, x=10,  data_number=6, text="sEMG7 Voltage"),
            PlotShow(form=form, y=550, x=140, data_number=7, text="sEMG8 Voltage"),
            PlotShow(form=form, y=550, x=270, data_number=8, text="sEMG9 Voltage"),
        ]
        
        self.gridLayoutWidget = QtWidgets.QWidget(form)
        self.gridLayoutWidget.setGeometry(QtCore.QRect(550, 270, 261, 121))
        self.gridLayoutWidget.setObjectName("gridLayoutWidget")
        
        self.gridLayout = QtWidgets.QGridLayout(self.gridLayoutWidget)
        self.gridLayout.setContentsMargins(0, 0, 0, 0)
        self.gridLayout.setObjectName("gridLayout")
        
        self.pushButton = QtWidgets.QPushButton(form)
        self.pushButton.setGeometry(QtCore.QRect(370, 410, 75, 23))
        self.pushButton.setObjectName("pushButton")

        self.retranslateUi(form)
        
        QtCore.QMetaObject.connectSlotsByName(form)

    def retranslateUi(self, form):
        _translate = QtCore.QCoreApplication.translate
        self.pushButton.setText(_translate("Form", "开始记录"))
        form.setWindowTitle(_translate("Form", "Form"))

def main():
    app = QtWidgets.QApplication([])
    form = QtWidgets.QWidget()  # PE8: `lower_case_names` for variables
    ui = UIForm()
    ui.setupUI(form)
    form.show()
    app.exec()

if __name__ == "__main__":
    # better start before GUI to create all needed variables and values
    thread_ble = threading.Thread(target=ble.ble)
    thread_ble.start()
    
    #thread_main = threading.Thread(target=main)
    #thread_main.start()
    #input() # keep running program when GUI runs in thread
    
    # GUI rather shouldn't run in separated thread
    main()

坦率地说,如果所有图都从同一源获取数据,则可以在所有图中使用一个qtimer运行所有update1 - 但是此计时器应在usiform而不是plotshow


编辑中:

版本仅使用一个qtimer in uiform要执行update_plot() for List self.plots上的所有图。

#import ble
from PyQt5 import QtCore, QtWidgets
import pyqtgraph as pg   # pg.PlotWidget
import numpy as np
import threading


class ble:
    ''' Simulate module `ble.py` '''
    
    EMG = [0,0,0,0,0,0,0,0,0,0,0,0,0]
    
    def ble():
        import math
        import random
        import time

        counter = 0
        
        while True:
        
            for i in range(10):
            
                if i in (0, 4, 8):
                    ble.EMG[i] = random.randint(0, 550)
                elif i in (1, 5, 6):
                    ble.EMG[i] = random.randint(150, 250)
                else:
                    ble.EMG[i] = 200 + math.sin(math.radians(counter//i)) * 200
            
            counter += 1
            time.sleep(0.1)
    
class PlotShow():  # PE8: `CamelNames` for classes
    '''
    form, y, x, data, length=1800, width=250, high=120, text="sEMG Voltage"
    '''
    def __init__(self, form, y, x, data_number, text=""):   # PEP8: spaces after commans `,`
        self.form = form   # PE8: `lower_case_names` for variables
        self.y = y
        self.x = x
        self.data_number = data_number
        self.length = 1800

        self.data = np.zeros(self.length)
        self.ptr  = 0
        
        if not text:
            self.test="sEMG Voltage"
        else:
            self.text = text
        
        self.initUI()

        #print('start:', self.text)
        #self.timer = pg.QtCore.QTimer()
        #self.timer.timeout.connect(self.update_plot)
        #self.timer.start(10)


    def initUI(self):
        self.graphicsView = pg.PlotWidget(self.form)

        self.graphicsView.setGeometry(QtCore.QRect(self.y, self.x, 250, 120))
        self.graphicsView.hideButtons()
        self.graphicsView.setObjectName(self.text)

        self.graphicsView.setLabel(axis="left",text=self.text)
        self.graphicsView.setLabel(axis='bottom',text='Time')
        self.graphicsView.setMouseEnabled(x=False,y=False)
        self.graphicsView.setAntialiasing(True)
        self.graphicsView.setMenuEnabled(False)
        self.graphicsView.hideButtons()
        
        self.curve = self.graphicsView.plot(self.data)

    def update_plot(self):
        #print('update:', self.text)
        
        self.data[:-1] = self.data[1:]  # shift data in the array one sample left
        self.data[-1]  = ble.EMG[self.data_number]

        self.ptr += 1

        self.curve.setData(self.data)
        self.curve.setPos(self.ptr, 0)
        self.graphicsView.setRange(xRange=[self.ptr, self.ptr+self.length], yRange=[5, 550], padding=0)  # PEP8: spaces after commans `,`

        
class UIForm():  # PE8: `CamelNames` for classes

    def setupUI(self, form, **kwargs):
        form.resize(820, 454)
        form.setObjectName("Form")

        self.plots = [
            PlotShow(form=form, y=10,  x=10,  data_number=0, text="sEMG1 Voltage"),
            PlotShow(form=form, y=10,  x=140, data_number=1, text="sEMG2 Voltage"),
            PlotShow(form=form, y=10,  x=270, data_number=2, text="sEMG3 Voltage"),
            PlotShow(form=form, y=280, x=10,  data_number=3, text="sEMG4 Voltage"),
            PlotShow(form=form, y=280, x=140, data_number=4, text="sEMG5 Voltage"),
            PlotShow(form=form, y=280, x=270, data_number=5, text="sEMG6 Voltage"),
            PlotShow(form=form, y=550, x=10,  data_number=6, text="sEMG7 Voltage"),
            PlotShow(form=form, y=550, x=140, data_number=7, text="sEMG8 Voltage"),
            PlotShow(form=form, y=550, x=270, data_number=8, text="sEMG9 Voltage"),
        ]
        
        self.gridLayoutWidget = QtWidgets.QWidget(form)
        self.gridLayoutWidget.setGeometry(QtCore.QRect(550, 270, 261, 121))
        self.gridLayoutWidget.setObjectName("gridLayoutWidget")
        
        self.gridLayout = QtWidgets.QGridLayout(self.gridLayoutWidget)
        self.gridLayout.setContentsMargins(0, 0, 0, 0)
        self.gridLayout.setObjectName("gridLayout")
        
        self.pushButton = QtWidgets.QPushButton(form)
        self.pushButton.setGeometry(QtCore.QRect(370, 410, 75, 23))
        self.pushButton.setObjectName("pushButton")

        self.retranslateUi(form)
        
        QtCore.QMetaObject.connectSlotsByName(form)

        self.timer = pg.QtCore.QTimer()
        self.timer.timeout.connect(self.update_all_plots)
        self.timer.start(10)
        
    def update_all_plots(self):
        for plot in self.plots:
            plot.update_plot()
        
    def retranslateUi(self, form):
        _translate = QtCore.QCoreApplication.translate
        self.pushButton.setText(_translate("Form", "开始记录"))
        form.setWindowTitle(_translate("Form", "Form"))

def main():
    app = QtWidgets.QApplication([])
    form = QtWidgets.QWidget()  # PE8: `lower_case_names` for variables
    ui = UIForm()
    ui.setupUI(form)
    form.show()
    app.exec()

if __name__ == "__main__":
    # better start before GUI to create all needed variables and values
    thread_ble = threading.Thread(target=ble.ble)
    thread_ble.start()
    
    #thread_main = threading.Thread(target=main)
    #thread_main.start()
    #input() # keep running program when GUI runs in thread
    
    # GUI rather shouldn't run in separated thread
    main()

As you already know (all) GUIs shouldn't run in separated thread.

But main problem which I had with code is that some elements in PyQt don't work if they are not assigned to global or class variables.

And when Plot is not assigned to variable then its QTimer doesn't work for me.

So I put all Plot on list and now all QTimers (without special threads) works for me.

        self.plots = [
            PlotShow(...),
            PlotShow(...),
            PlotShow(...),
            # ...
        ]

Full working code.

I used class ble to simulate module ble.py and to have all code in one file (for tests).

I made also few small changes: PEP 8 -- Style Guide for Python Code

#import ble
from PyQt5 import QtCore, QtWidgets
import pyqtgraph as pg   # pg.PlotWidget
import numpy as np
import threading


class ble:
    ''' Simulate module `ble.py` '''
    
    EMG = [0,0,0,0,0,0,0,0,0,0,0,0,0]
    
    def ble():
        import math
        import random
        import time

        counter = 0
        
        while True:
        
            for i in range(10):
            
                if i in (0, 4, 8):
                    ble.EMG[i] = random.randint(0, 550)
                elif i in (1, 5, 6):
                    ble.EMG[i] = random.randint(150, 250)
                else:
                    ble.EMG[i] = 200 + math.sin(math.radians(counter//i)) * 200
            
            counter += 1
            time.sleep(0.1)
    
class PlotShow():  # PE8: `CamelNames` for classes
    '''
    form, y, x, data, length=1800, width=250, high=120, text="sEMG Voltage"
    '''
    def __init__(self, form, y, x, data_number, text=""):   # PEP8: spaces after commans `,`
        self.form = form   # PE8: `lower_case_names` for variables
        self.y = y
        self.x = x
        self.data_number = data_number
        self.length = 1800

        self.data = np.zeros(self.length)
        self.ptr  = 0
        
        if not text:
            self.test="sEMG Voltage"
        else:
            self.text = text
        
        self.initUI()

        #print('start:', self.text)
        self.timer = pg.QtCore.QTimer()
        self.timer.timeout.connect(self.update_plot)
        self.timer.start(10)


    def initUI(self):
        self.graphicsView = pg.PlotWidget(self.form)

        self.graphicsView.setGeometry(QtCore.QRect(self.y, self.x, 250, 120))
        self.graphicsView.hideButtons()
        self.graphicsView.setObjectName(self.text)

        self.graphicsView.setLabel(axis="left",text=self.text)
        self.graphicsView.setLabel(axis='bottom',text='Time')
        self.graphicsView.setMouseEnabled(x=False,y=False)
        self.graphicsView.setAntialiasing(True)
        self.graphicsView.setMenuEnabled(False)
        self.graphicsView.hideButtons()
        
        self.curve = self.graphicsView.plot(self.data)

    def update_plot(self):
        #print('update:', self.text)
        
        self.data[:-1] = self.data[1:]  # shift data in the array one sample left
        self.data[-1]  = ble.EMG[self.data_number]

        self.ptr += 1

        self.curve.setData(self.data)
        self.curve.setPos(self.ptr, 0)
        self.graphicsView.setRange(xRange=[self.ptr, self.ptr+self.length], yRange=[5, 550], padding=0)  # PEP8: spaces after commans `,`

        
class UIForm():  # PE8: `CamelNames` for classes

    def setupUI(self, form, **kwargs):
        form.resize(820, 454)
        form.setObjectName("Form")

        self.plots = [
            PlotShow(form=form, y=10,  x=10,  data_number=0, text="sEMG1 Voltage"),
            PlotShow(form=form, y=10,  x=140, data_number=1, text="sEMG2 Voltage"),
            PlotShow(form=form, y=10,  x=270, data_number=2, text="sEMG3 Voltage"),
            PlotShow(form=form, y=280, x=10,  data_number=3, text="sEMG4 Voltage"),
            PlotShow(form=form, y=280, x=140, data_number=4, text="sEMG5 Voltage"),
            PlotShow(form=form, y=280, x=270, data_number=5, text="sEMG6 Voltage"),
            PlotShow(form=form, y=550, x=10,  data_number=6, text="sEMG7 Voltage"),
            PlotShow(form=form, y=550, x=140, data_number=7, text="sEMG8 Voltage"),
            PlotShow(form=form, y=550, x=270, data_number=8, text="sEMG9 Voltage"),
        ]
        
        self.gridLayoutWidget = QtWidgets.QWidget(form)
        self.gridLayoutWidget.setGeometry(QtCore.QRect(550, 270, 261, 121))
        self.gridLayoutWidget.setObjectName("gridLayoutWidget")
        
        self.gridLayout = QtWidgets.QGridLayout(self.gridLayoutWidget)
        self.gridLayout.setContentsMargins(0, 0, 0, 0)
        self.gridLayout.setObjectName("gridLayout")
        
        self.pushButton = QtWidgets.QPushButton(form)
        self.pushButton.setGeometry(QtCore.QRect(370, 410, 75, 23))
        self.pushButton.setObjectName("pushButton")

        self.retranslateUi(form)
        
        QtCore.QMetaObject.connectSlotsByName(form)

    def retranslateUi(self, form):
        _translate = QtCore.QCoreApplication.translate
        self.pushButton.setText(_translate("Form", "开始记录"))
        form.setWindowTitle(_translate("Form", "Form"))

def main():
    app = QtWidgets.QApplication([])
    form = QtWidgets.QWidget()  # PE8: `lower_case_names` for variables
    ui = UIForm()
    ui.setupUI(form)
    form.show()
    app.exec()

if __name__ == "__main__":
    # better start before GUI to create all needed variables and values
    thread_ble = threading.Thread(target=ble.ble)
    thread_ble.start()
    
    #thread_main = threading.Thread(target=main)
    #thread_main.start()
    #input() # keep running program when GUI runs in thread
    
    # GUI rather shouldn't run in separated thread
    main()

enter image description here

Frankly, if all plots get data from the same source and in the same time then you could use one QTimer to run all update1 in all plots - but this timer should be in UIForm instead of PlotShow


EDIT:

Version which use only one QTimer in UIForm to execute update_plot() for all plots on list self.plots.

#import ble
from PyQt5 import QtCore, QtWidgets
import pyqtgraph as pg   # pg.PlotWidget
import numpy as np
import threading


class ble:
    ''' Simulate module `ble.py` '''
    
    EMG = [0,0,0,0,0,0,0,0,0,0,0,0,0]
    
    def ble():
        import math
        import random
        import time

        counter = 0
        
        while True:
        
            for i in range(10):
            
                if i in (0, 4, 8):
                    ble.EMG[i] = random.randint(0, 550)
                elif i in (1, 5, 6):
                    ble.EMG[i] = random.randint(150, 250)
                else:
                    ble.EMG[i] = 200 + math.sin(math.radians(counter//i)) * 200
            
            counter += 1
            time.sleep(0.1)
    
class PlotShow():  # PE8: `CamelNames` for classes
    '''
    form, y, x, data, length=1800, width=250, high=120, text="sEMG Voltage"
    '''
    def __init__(self, form, y, x, data_number, text=""):   # PEP8: spaces after commans `,`
        self.form = form   # PE8: `lower_case_names` for variables
        self.y = y
        self.x = x
        self.data_number = data_number
        self.length = 1800

        self.data = np.zeros(self.length)
        self.ptr  = 0
        
        if not text:
            self.test="sEMG Voltage"
        else:
            self.text = text
        
        self.initUI()

        #print('start:', self.text)
        #self.timer = pg.QtCore.QTimer()
        #self.timer.timeout.connect(self.update_plot)
        #self.timer.start(10)


    def initUI(self):
        self.graphicsView = pg.PlotWidget(self.form)

        self.graphicsView.setGeometry(QtCore.QRect(self.y, self.x, 250, 120))
        self.graphicsView.hideButtons()
        self.graphicsView.setObjectName(self.text)

        self.graphicsView.setLabel(axis="left",text=self.text)
        self.graphicsView.setLabel(axis='bottom',text='Time')
        self.graphicsView.setMouseEnabled(x=False,y=False)
        self.graphicsView.setAntialiasing(True)
        self.graphicsView.setMenuEnabled(False)
        self.graphicsView.hideButtons()
        
        self.curve = self.graphicsView.plot(self.data)

    def update_plot(self):
        #print('update:', self.text)
        
        self.data[:-1] = self.data[1:]  # shift data in the array one sample left
        self.data[-1]  = ble.EMG[self.data_number]

        self.ptr += 1

        self.curve.setData(self.data)
        self.curve.setPos(self.ptr, 0)
        self.graphicsView.setRange(xRange=[self.ptr, self.ptr+self.length], yRange=[5, 550], padding=0)  # PEP8: spaces after commans `,`

        
class UIForm():  # PE8: `CamelNames` for classes

    def setupUI(self, form, **kwargs):
        form.resize(820, 454)
        form.setObjectName("Form")

        self.plots = [
            PlotShow(form=form, y=10,  x=10,  data_number=0, text="sEMG1 Voltage"),
            PlotShow(form=form, y=10,  x=140, data_number=1, text="sEMG2 Voltage"),
            PlotShow(form=form, y=10,  x=270, data_number=2, text="sEMG3 Voltage"),
            PlotShow(form=form, y=280, x=10,  data_number=3, text="sEMG4 Voltage"),
            PlotShow(form=form, y=280, x=140, data_number=4, text="sEMG5 Voltage"),
            PlotShow(form=form, y=280, x=270, data_number=5, text="sEMG6 Voltage"),
            PlotShow(form=form, y=550, x=10,  data_number=6, text="sEMG7 Voltage"),
            PlotShow(form=form, y=550, x=140, data_number=7, text="sEMG8 Voltage"),
            PlotShow(form=form, y=550, x=270, data_number=8, text="sEMG9 Voltage"),
        ]
        
        self.gridLayoutWidget = QtWidgets.QWidget(form)
        self.gridLayoutWidget.setGeometry(QtCore.QRect(550, 270, 261, 121))
        self.gridLayoutWidget.setObjectName("gridLayoutWidget")
        
        self.gridLayout = QtWidgets.QGridLayout(self.gridLayoutWidget)
        self.gridLayout.setContentsMargins(0, 0, 0, 0)
        self.gridLayout.setObjectName("gridLayout")
        
        self.pushButton = QtWidgets.QPushButton(form)
        self.pushButton.setGeometry(QtCore.QRect(370, 410, 75, 23))
        self.pushButton.setObjectName("pushButton")

        self.retranslateUi(form)
        
        QtCore.QMetaObject.connectSlotsByName(form)

        self.timer = pg.QtCore.QTimer()
        self.timer.timeout.connect(self.update_all_plots)
        self.timer.start(10)
        
    def update_all_plots(self):
        for plot in self.plots:
            plot.update_plot()
        
    def retranslateUi(self, form):
        _translate = QtCore.QCoreApplication.translate
        self.pushButton.setText(_translate("Form", "开始记录"))
        form.setWindowTitle(_translate("Form", "Form"))

def main():
    app = QtWidgets.QApplication([])
    form = QtWidgets.QWidget()  # PE8: `lower_case_names` for variables
    ui = UIForm()
    ui.setupUI(form)
    form.show()
    app.exec()

if __name__ == "__main__":
    # better start before GUI to create all needed variables and values
    thread_ble = threading.Thread(target=ble.ble)
    thread_ble.start()
    
    #thread_main = threading.Thread(target=main)
    #thread_main.start()
    #input() # keep running program when GUI runs in thread
    
    # GUI rather shouldn't run in separated thread
    main()
哆啦不做梦 2025-01-25 00:20:15

谢谢@furas和@musicamante建议,问题已经解决。

该错误非常简单。

我将刷新率设置得太快。因为我在自定义组件类中设置self.timer.timer.start(10),所以程序自身崩溃。

Thank @furas and @musicamante suggests, the problem is solved.

The bug is surprisingly simple.

I set the refresh rate too fast. Because I setting self.timer.start(10) in the custom component class, So the program crashes itself.????It only need setting self.timer.start(100), the program can working...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文