如何像 Matplotlib 的离子模式一样异步使用 At 运行 进行交互?
How to have Qt run asynchroneously for interactive use like Matplotlib's ion mode?
我希望能够从 python 解释器启动 Qt 界面,命令行立即返回,这样我就可以在能够使用界面的同时继续使用 python。基本上,我希望能够像使用 matplotlib 的 ion
交互模式、jupyter notebook 或 Matlab 那样从解释器与 GUI 进行交互。
我天真地尝试将应用程序的执行放在一个线程中:
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 来实现类似的效果。
真的可以实现吗?
不需要使用线程或另一个库的补充,你只需要执行命令但你不应该调用 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()
我希望能够从 python 解释器启动 Qt 界面,命令行立即返回,这样我就可以在能够使用界面的同时继续使用 python。基本上,我希望能够像使用 matplotlib 的 ion
交互模式、jupyter notebook 或 Matlab 那样从解释器与 GUI 进行交互。
我天真地尝试将应用程序的执行放在一个线程中:
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 来实现类似的效果。
真的可以实现吗?
不需要使用线程或另一个库的补充,你只需要执行命令但你不应该调用 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()