如何让 Qt 异步运行以进行交互使用,如 Matplotlib 离子模式?
Posted
技术标签:
【中文标题】如何让 Qt 异步运行以进行交互使用,如 Matplotlib 离子模式?【英文标题】:How to have Qt run asynchroneously for interactive use like Matplotlib's ion mode? 【发布时间】:2020-03-07 10:08:35 【问题描述】:我希望能够从 python 解释器启动一个 Qt 接口,并立即返回命令行,这样我就可以在能够使用该接口的同时继续使用 python。基本上我希望能够与解释器的 GUI 进行交互,就像使用 matplotlib 的 ion
交互模式、jupyter notebook 或 Matlab 一样。
我天真地尝试将应用程序的执行放在一个线程中:
from PyQt5.QtCore import QThread
from PyQt5.QtWidgets import QApplication, QGraphicsRectItem, QGraphicsScene, QGraphicsView, QMainWindow
class Rect(QGraphicsRectItem):
def mousePressEvent(self, event):
print("foo")
app = QApplication([])
class AppThread(QThread):
def run(self):
app.exec()
print('bar')
window = QMainWindow()
window.setGeometry(100, 100, 400, 400)
view = QGraphicsView()
scene = QGraphicsScene()
rect = Rect(0, 0, 150, 150)
scene.addItem(rect)
view.setScene(scene)
window.setCentralWidget(view)
window.show()
thread = AppThread()
thread.start()
...但这不起作用,因为生成的 GUI 已冻结,因此无法使用。
matplotlib 的一个后端是Qt5Agg
,我天真地认为这意味着我可以使用 PyQt5 或 PySide2 来实现类似的效果。
真的可以做到吗?
【问题讨论】:
【参考方案1】:不需要使用线程或其他库的补充,你只需要执行命令但你不应该调用 QApplication 的 exec_() 方法,因为它使用 python 交互式控制台事件循环。
$ python
Python 3.8.2 (default, Feb 26 2020, 22:21:03)
[GCC 9.2.1 20200130] on linux
Type "help", "copyright", "credits" or "license" for more information
>>> from PyQt5.QtWidgets import QApplication, QGraphicsRectItem, QGraphicsScene, QGraphicsView, QMainWindow
>>> class Rect(QGraphicsRectItem):
... def mousePressEvent(self, event):
... print("foo")
...
>>> app = QApplication([])
>>> window = QMainWindow()
>>> window.setGeometry(100, 100, 400, 400)
>>> view = QGraphicsView()
>>> scene = QGraphicsScene()
>>> rect = Rect(0, 0, 150, 150)
>>> scene.addItem(rect)
>>> view.setScene(scene)
>>> window.setCentralWidget(view)
>>> window.show()
IPython
正如IPython docs 指出的那样,%gui backend
必须用于启用 GUI 事件循环。在 PyQt5/PySide2 的情况下,必须在开头使用%gui qt5
。
$ ipython
Python 3.8.2 (default, Feb 26 2020, 22:21:03)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.13.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: %gui qt5
In [2]: from PyQt5.QtWidgets import QApplication, QGraphicsRectItem, QGraphicsScene, QGraphicsView, QMainWindow
In [3]: class Rect(QGraphicsRectItem):
...: def mousePressEvent(self, event):
...: print("foo")
...:
In [4]: app = QApplication([])
In [5]: window = QMainWindow()
In [6]: window.setGeometry(100, 100, 400, 400)
In [7]: view = QGraphicsView()
In [8]: scene = QGraphicsScene()
In [9]: rect = Rect(0, 0, 150, 150)
In [10]: scene.addItem(rect)
In [11]: view.setScene(scene)
In [12]: window.setCentralWidget(view)
In [13]: window.show()
【讨论】:
不幸的是,这不起作用。我在 Windows 和 Linux 上进行了测试——在这两个平台上,GUI 仍然冻结。 @user209974 好奇怪,你是怎么打开交互式python控制台的?我使用 Linux,只需在控制台中键入 python 并按 ENTER,然后编写我在答案中显示的命令(不应使用app.exec()
)
我使用了 ipython -- 这会有所不同吗?
哦,是的——只是在一个普通的 python 解释器中尝试过,它可以工作
知道如何让它在 ipython 中工作吗?或者这是一个完全不同的话题?以上是关于如何让 Qt 异步运行以进行交互使用,如 Matplotlib 离子模式?的主要内容,如果未能解决你的问题,请参考以下文章
技术分享 | 让ROS人机交互更加有趣--基于Qt+ROS开发