【问题标题】:Trying to open a PyQtGraph window in PyQt5尝试在 PyQt5 中打开 PyQtGraph 窗口
【发布时间】:2020-05-18 19:05:45
【问题描述】:

我的 OptionsViz 类正在独立工作。但是,当我放入 asyncio 的东西时,它并没有显示任何更新。为简洁起见,我删除的代码需要循环,所以请不要把它扔掉。

import sys
import asyncio
from qasync import QEventLoop
from PyQt5.QtWidgets import QApplication, QMainWindow, QDockWidget

class OptionViz:
  def __init__(self, app):
    self.app = app
    self.p = pg.plot()
    self.p.setWindowTitle("pyqtgraph example: PlotSpeedTest")
    self.p.setRange(QtCore.QRectF(0, -10, 5000, 20))
    self.p.setLabel("bottom", "Index", units="B")
    self.curve = self.p.plot()

    self.data = np.random.normal(size=(50,5000))
    self.ptr = 0
    self.lastTime = time()
    self.fps = None

    timer = QtCore.QTimer()
    timer.timeout.connect(self.update)
    timer.start(0)

  def update(self):
      self.curve.setData(self.data[self.ptr%10])
      self.ptr += 1
      now = time()
      dt = now - self.lastTime
      self.lastTime = now
      if self.fps is None:
          fps = 1.0/dt
      else:
          s = np.clip(dt*3., 0, 1)
          self.fps = self.fps * (1-s) + (1.0/dt) * s
      self.p.setTitle('%0.2f fps' % fps)
      self.app.processEvents()  ## force complete redraw for every plot

async def main(app):
  # some await task here
  viz = OptionViz(app)
  # more await code here

if __name__ == '__main__':
  app = QApplication(sys.argv)
  loop = QEventLoop(app)
  asyncio.set_event_loop(loop)
  loop.create_task(main(app))
  loop.run_forever()

【问题讨论】:

  • 什么是 # some await task here# more await code here
  • 在你的代码“main”中它是不可等待的,所以它会立即执行。你明白它是一个等待函数吗?
  • 你会回答我的一些问题吗?

标签: python pyqt pyqtgraph


【解决方案1】:

Qt 与 asyncio 不兼容,因此已经实现了几个库,例如 quamash、asyncqt、qasync 等以使其兼容。在 quamash 和 asyncqt 的情况下,它们有一个不允许执行的错误,但 qasync 库已经解决了它(执行 pip install qasync 以安装包)。

另一方面,main 方法是不可等待的,因为它不执行耗时的任务,而是立即执行,所以我不得不重组您的项目:

import sys
import asyncio
from qasync import QEventLoop
from PyQt5 import QtCore, QtWidgets
import pyqtgraph as pg
import numpy as np


class OptionViz:
    def __init__(self, app):
        self.app = app
        p = pg.plot()
        p.setWindowTitle("pyqtgraph example: PlotSpeedTest")
        p.setRange(QtCore.QRectF(0, -10, 5000, 20))
        p.setLabel("bottom", "Index", units="B")
        self.curve = p.plot()


async def main(viz):
    data = np.random.normal(size=(50, 5000))
    ptr = 0
    while True:
        viz.curve.setData(data[ptr % 10])
        await asyncio.sleep(0.1)
        ptr += 1


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    loop = QEventLoop(app)
    asyncio.set_event_loop(loop)
    viz = OptionViz(app)
    loop.create_task(main(viz))
    loop.run_forever()

同样,“main”函数只创建一个“OptionViz”对象,它不需要很长时间是不可等待的,因此在这种情况下使用 async 是荒谬的。看来OP不理解asyncio的操作。

通过重构您的代码,我们可以使函数可等待,因此 OptionViz 必须是 QObject 才能使用 asyncSlot 装饰器,此外 QTimer 必须是 QObject 的子对象,这样它的生命周期才会增加。

import sys
import asyncio
from qasync import QEventLoop, asyncSlot
from PyQt5 import QtCore, QtWidgets
import pyqtgraph as pg
import numpy as np
from time import time


class OptionViz(QtCore.QObject):
    def __init__(self, app):
        super().__init__()
        self.app = app
        self.p = pg.plot()
        self.p.setWindowTitle("pyqtgraph example: PlotSpeedTest")
        self.p.setRange(QtCore.QRectF(0, -10, 5000, 20))
        self.p.setLabel("bottom", "Index", units="B")
        self.curve = self.p.plot()

        self.data = np.random.normal(size=(50, 5000))
        self.ptr = 0
        self.lastTime = time()
        self.fps = None

        timer = QtCore.QTimer(self)
        timer.timeout.connect(self.update)
        timer.start(0)

    @asyncSlot()
    async def update(self):
        self.curve.setData(self.data[self.ptr % 10])
        self.ptr += 1
        now = time()
        dt = now - self.lastTime
        self.lastTime = now
        if self.fps is None:
            fps = 1.0 / dt
        else:
            s = np.clip(dt * 3.0, 0, 1)
            self.fps = self.fps * (1 - s) + (1.0 / dt) * s
        self.p.setTitle("%0.2f fps" % fps)


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    loop = QEventLoop(app)
    asyncio.set_event_loop(loop)
    viz = OptionViz(app)
    loop.run_forever()

【讨论】:

  • 我更新了我的代码以匹配您的解决方案。但我没有收到图表数据更新。
  • @BAR 我怀疑您不清楚何时应该使用“异步”函数以及何时不使用的基本概念。
  • 重要的是我的 main() 函数被称为异步,因为它里面有等待代码。
  • 如果我按照自己的方式进行操作,则不会有任何更新。
  • @BAR 如果你提供一个真实的minimal reproducible example,那么我可以告诉你为什么它失败了,但是你提供的东西我不可能帮助你。
猜你喜欢
  • 2021-10-10
  • 2018-10-19
  • 2016-08-08
  • 1970-01-01
  • 1970-01-01
  • 2019-09-14
  • 1970-01-01
  • 2018-05-16
  • 1970-01-01
相关资源
最近更新 更多