正在尝试在PyQt5中打开PyQtGraph窗口

2024-04-25 20:27:38 发布

您现在位置:Python中文网/ 问答频道 /正文

我的OptionViz类正在独立工作。但是,当我加入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()

Tags: importselfloopasyncioappplotmaindef
1条回答
网友
1楼 · 发布于 2024-04-25 20:27:38

Qt与asyncio不兼容,因此实现了几个库,如quamash、asyncqt、qasync等,以使其兼容。在quamash和asyncqt的情况下,它们有一个不允许执行的bug,但是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必须是QoObject才能使用asyncSlot装饰器,此外,QTimer必须是QoObject的子对象,以便其生命周期增加

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()

相关问题 更多 >