PyQt5在启动后30 ... 300秒内停止更新GUI

时间:2019-02-06 08:38:00

标签: python-3.x pyqt5

我借助PyQt在python3中开发了一个SCADA。我希望我的程序能够不断指示通过RS-485接口接收的各种参数,但是从开始起几分钟(总是不同的时间)内,GUI会停止自我更新。同时,GUI保持响应状态,如果我单击它具有的动画QAbstractButtons之一,则GUI将在短时间内再次按预期工作。此问题在Linux和Windows上均会发生。

该程序有多个工作线程:一个用于RS-485交换,一个用于将各种数据读/写到磁盘,一个用于解码接收到的包并刷新内存中的数据,一个用于请求队列管理,等等。 while(True)循环:time.sleep(...)-完成工作。 GUI在主线程中实现。

数据用QLabels指示。将QLabel.setText添加到包含QLabel的QWidget的painterEvent()中。

当GUI停止更新时,其他线程已启动并正在运行:交换正在运行,正在形成请求队列等。尽管未更新,但GUI仍保持响应并对QAbstractButton单击做出反应。

我尝试将gui.update()或app.processEvents()添加到其中一个工作线程中,并尝试通过主线程中的QTimer强制进行更新。结果是相同的:它会工作一会儿然后停止。

我尝试增加刷新线程的time.sleep并强制在更长的时间间隔(0.5到5秒)内更新主窗口小部件,这似乎可以帮助解决这种情况,它可以运行几分钟,但是它仍然不能解决问题。

我很想展示代码,但是整个事情太庞大了,无法在此处发布,如果我可以将其缩小到至少一百行,那么我现在已经解决了这个问题。因此,如果你们中的任何一个至少可以就寻找的东西分享一些一般性的考虑,我将非常高兴。

更新: 这似乎可行,我明天将其运行几个小时以确认:

update_timer = QTimer() 
update_timer.setSingleShot(False) 
update_timer.timeout.connect(self.gui.repaint) 
update_timer.setInterval(500) 
update_timer.start()

我认为self.gui.update()不起作用,因为可能未发出dataChanged(),并且传递了控制权而不是执行repaint()。据我了解,以上解决方案不是更新小部件的正确方法。

因此,问题实际上可以归结为以下内容:

更新主QWidget的正确方法是什么,如何让程序知道需要重绘(可能使用dataChanged()信号)?

1 个答案:

答案 0 :(得分:0)

答案很简单。切勿从主线程外部执行与PyQt相关的任何操作。即使这似乎是做某事的唯一逻辑方法。

在“修复” GUI未更新的问题之后,我偶然遇到了一个更严重的问题:程序时不时崩溃。事实证明,未更新的GUI只是冰山一角。正常运行时间通常为2到7分钟,我收到了一些glibc错误(“损坏的双链表”和“双重释放或损坏”)。事实证明,问题的根源在于刷新线程内部,该线程有数百行更新gui:

self.gui.screen_name.device_name.setCrash()

其中setCrash()会更改小部件的颜色和调色板,甚至更直接的内容,例如

self.gui.screen_name.label_name.setText(str(value))

我从主文件(所有线程发生的位置)中查找了与gui甚至松散相关的所有内容,并重新设置了样式。现在它只有一个工作线程-RS-485,其余的都包裹在单独的QTimers中。

是这样的:

class Main():
    def __init__():
        self.plots_thread = Thread(target = self.plots_refresh)
        self.plots_thread.start()

    def plots_refresh():
        while True:
            time.sleep(0.5)
            #do stuff

现在是这样:

class Main():
    def __init__():
        self.plots_refresh_timer = QTimer()
        self.plots_refresh_timer.setSingleShot(False)
        self.plots_refresh_timer.timeout.connect(self.plots_refresh)
        self.plots_refresh_timer.setInterval(499) #prime number 
        self.plots_refresh_timer.start()

    def plots_refresh():
        #do stuff

这一次程序已经运行了一个多小时,并且从未崩溃。在得出结论认为这是解决办法之后,我重构了真正混乱的测试文件并恢复了测试-再次,半小时没有麻烦。