【问题标题】:PyQt5 stops updating GUI within 30...300 seconds after startPyQt5 在启动后 30...300 秒内停止更新 GUI
【发布时间】:2019-02-07 19:32:43
【问题描述】:

我在 PyQt 的帮助下在 python3 中开发了一个 SCADA。我希望我的程序能够连续指示通过 RS-485 接口接收到的各种参数,但是,在开始后的几分钟内(总是不同的时间),GUI 停止自我更新。同时,GUI 保持响应,如果我单击其中一个动画 QAbstractButtons,GUI 会在短时间内再次按预期工作。 Linux 和 Windows 都会出现此问题。

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

数据用 QLabels 表示。 QLabel.setText 被添加到包含 QLabels 的 QWidgets 的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() 信号?

【问题讨论】:

标签: python-3.x pyqt5


【解决方案1】:

答案很简单。永远不要在主线程之外做任何与 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

这次程序已经运行了一个多小时,从未崩溃过。在得出这是修复的结论后,我重构了非常混乱的测试文件并继续测试 - 再次,半小时没有问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-04
    • 1970-01-01
    • 2019-01-11
    相关资源
    最近更新 更多