当我在将信号连接到插槽时不使用部分功能时,我的 pyqt5 应用程序冻结

问题描述

我的目标是创建一个概念验证代码,以在 Python pyqt5 HMI 中运行一个简单的动态模拟器。我已经创建了一个非常简单的模拟器,其中包含一些 setter 和 getter,并且我正在使用模型-视图-控制器设计模式。 HMI 相当简单,只有几个输入。我也在使用 pyqtgraph 实时绘制模拟结果。

我的问题是我的 HMI 在启动时冻结,除非我在将信号连接到插槽时添加至少一个部分功能:

def _connectSignals(self):
    self._view.buttons['u'].clicked.connect(self._on_u_update)
    self._view.buttons['k'].clicked.connect(self._on_k_update)
    self._view.buttons['dt'].clicked.connect(partial(self._on_dt_update,'dummy')) # Program freeze without at least one partial function. No idea why.

def _on_k_update(self):
    self._model.set_k(float(self._view.lineEdits['k'].text()))

def _on_dt_update(self,dt): # Need to have an input here to avoid program freezing. See connect of dt above
    dt_ = float(self._view.lineEdits['dt'].text())
    dt_ = float(dt_)
    self._model.set_dt(dt_ / 1000.0)
    self.u_line.set_n_samples(seconds=60,dt=dt_ / 1000.0)
    self.x_line.set_n_samples(seconds=60,dt=dt_ / 1000.0)
    self.dt = int(dt_)
    self.timer.setInterval(self.dt)

def _on_u_update(self):
    self._model.set_u(float(self._view.lineEdits['u'].text()))

这甚至发生在我避免调用我的 `_connectSignals 函数时。我怀疑可能跟我用QTimer控制模拟器的步进有关。

没有错误消息,我无法暂停/调试应用程序。整个代码位于:

import sys

from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtWidgets import QLabel
from PyQt5.QtWidgets import QPushButton
from PyQt5.QtWidgets import QLineEdit
from PyQt5.QtWidgets import QHBoxLayout,QVBoxLayout
from PyQt5.QtWidgets import QWidget
from PyQt5 import QtCore

from functools import partial

from scipy.integrate import odeint

import pyqtgraph as pg

class POC_Simulator():
    def __init__(self):
        self.u = 0.0
        self.k = 1.0
        self.x = 0.0
        self.dt = 0.050
        self.t = 0.0

    def set_k(self,k):
        self.k = float(k)

    def get_k(self):
        return self.k

    def set_u(self,u):
        self.u = float(u)

    def get_u(self):
        return self.u

    def set_dt(self,dt):
        self.dt = float(dt)

    def get_dt(self):
        return self.dt

    def get_x(self):
        return self.x

    def get_t(self):
        return self.t

    def model(self,x,t):
        dxdt = 1/self.k*(-x + self.u)
        return dxdt

    def step(self):
        t_span = [0,self.dt]
        x = odeint(self.model,self.x,t_span)
        self.x = float(x[1])
        self.t += self.dt
        return self.x,self.t

class GraphLine():
    def __init__(self,graph: pg.PlotWidget,n_samples=100):
        self.graph = graph
        self.x = []
        self.y = []
        self.n_samples = n_samples


    def createPlot(self,color,linetype,name,width):
        if linetype == '-':
            style = QtCore.Qt.SolidLine
        elif linetype == ':':
            style = QtCore.Qt.DotLine
        elif linetype == '--':
            style = QtCore.Qt.DashLine
        else:
            style = QtCore.Qt.SolidLine
        pen = pg.mkPen(color=color)
        self.plt = self.graph.plot(self.x,self.y,pen=pen,style=style,name=name,width=width)

    def updatePlot(self,y):
        if len(self.x) >= self.n_samples:
            self.x = self.x[1:]
        self.x.append(x)
        if len(self.y) >= self.n_samples:
            self.y = self.y[1:]
        self.y.append(y)

        self.plt.setData(self.x,self.y)

    def set_n_samples(self,seconds,dt):
        self.n_samples = seconds / dt

class SimulatorUI(QMainWindow):
    def __init__(self):
        super(SimulatorUI,self).__init__()
        self.setWindowTitle('POC Simulator UI')
        self.setFixedSize(800,500)
        self.generalLayout = QHBoxLayout()
        self._centralWidget = QWidget()
        self.setCentralWidget(self._centralWidget)
        self._centralWidget.setLayout(self.generalLayout)
        self._createInputs()
        self._createPlot()
        self.n_samples = 100

    def _createInputs(self):
        layout = QVBoxLayout()
        lines = ('u','k','dt')
        self.lineEdits = {}
        self.labelValues = {}
        self.buttons = {}

        for name in lines:
            lineLayout = QHBoxLayout()
            lineEdit = QLineEdit('')
            lineLayout.addWidget(QLabel(name))
            lineLayout.addWidget(lineEdit)
            self.lineEdits[name] = lineEdit
            btn = QPushButton(f'Update {name}')
            lineLayout.addWidget(btn)
            self.buttons[name] = btn
            value = QLabel('')
            lineLayout.addWidget(value)
            self.labelValues[name] = value
            layout.addLayout(lineLayout)
        self.generalLayout.addLayout(layout)

    def _createPlot(self):
        self.graphWidget = pg.PlotWidget()
        self.graphWidget.setBackground('w')
        self.graphWidget.addLegend()
        self.graphWidget.showGrid(x=True,y=True)
        self.generalLayout.addWidget(self.graphWidget)

    def addPlot(self,width=2,linetype='-'):
        line = GraphLine(self.graphWidget)
        line.createPlot(color=color,linetype=linetype,width=width,name=name)
        return line

class POC_Ctrl():
    def __init__(self,model: POC_Simulator,view: SimulatorUI):
        self._model = model
        self._view = view
        self._connectSignals()
        self.timer = QtCore.QTimer()
        self.u_line = self._view.addPlot(color='k',linetype=':',name='u')
        self.x_line = self._view.addPlot(color='r',name='x')
        u_0 = self._model.get_u()
        k_0 = self._model.get_k()
        dt_0 = self._model.get_dt()

        self.dt = int(dt_0 * 1000)
        self.timer.setInterval(self.dt)
        self.timer.timeout.connect(self._onTimerTimeout)

        self._view.labelValues['u'].setText(f'u value: {u_0}')
        self._view.labelValues['k'].setText(f'k value: {k_0}')
        self._view.labelValues['dt'].setText(f'dt value: {self.dt}')

        self._view.lineEdits['u'].setText(f'{u_0}')
        self._view.lineEdits['k'].setText(f'{k_0}')
        self._view.lineEdits['dt'].setText(f'{self.dt}')

        self.timer.start()

    def _connectSignals(self):
        self._view.buttons['u'].clicked.connect(self._on_u_update)
        self._view.buttons['k'].clicked.connect(self._on_k_update)
        self._view.buttons['dt'].clicked.connect(partial(self._on_dt_update,'dummy')) # Program freeze without at least one partial function. No idea why.

    def _on_k_update(self):
        self._model.set_k(float(self._view.lineEdits['k'].text()))

    def _on_dt_update(self,dt): # Need to have an input here to avoid program freezing. See connect of dt above
        dt_ = float(self._view.lineEdits['dt'].text())
        dt_ = float(dt_)
        self._model.set_dt(dt_ / 1000.0)
        self.u_line.set_n_samples(seconds=60,dt=dt_ / 1000.0)
        self.x_line.set_n_samples(seconds=60,dt=dt_ / 1000.0)
        self.dt = int(dt_)
        self.timer.setInterval(self.dt)

    def _on_u_update(self):
        self._model.set_u(float(self._view.lineEdits['u'].text()))


    def _onTimerTimeout(self):
        self._model.step()
        self._view.labelValues['u'].setText(f'u value: {self._model.get_u()}')
        self._view.labelValues['k'].setText(f'k value: {self._model.get_k()}')
        self._view.labelValues['dt'].setText(f'dt value: {int(self._model.get_dt()*1000.0)}')
        self.u_line.updatePlot(self._model.get_t(),self._model.get_u())
        self.x_line.updatePlot(self._model.get_t(),self._model.get_x())
        self.timer.start()



def main():
    app = QApplication(sys.argv)
    view = SimulatorUI()
    view.show()
    model = POC_Simulator()
    POC_Ctrl(model=model,view=view)
    sys.exit(app.exec())

if __name__ == '__main__':
    main()

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)