Matplotlib如何为后端库(如Qt)设置事件循环,同时仍然允许通过python REPL进行交互?至少对于Qt来说,主事件循环必须在主线程中运行,但是REPL所在的位置是正确的,所以我很难看到两者如何共存。
我目前的尝试是在单独的Python中启动QApplication
threading.Thread
def mainloop():
app = QtWidgets.QApplication([])
while True:
app.processEvents()
time.sleep(0.01)
t = threading.Thread(target=mainloop)
t.daemon = True
t.start()
哪种方式有效,但我收到此警告,有时会崩溃:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QApplication(0x7fc5cc001820), parent's thread is QThread(0x7fc5cc001a40), current thread is QThread(0x2702160)
此处尝试使用QThread
:
from PyQt5 import QtGui, QtCore, QtWidgets
import time
class Mainloop(QtCore.QObject):
def __init__(self):
super().__init__()
self.app = QtWidgets.QApplication([])
def run(self):
while True:
self.app.processEvents()
time.sleep(1)
t = QtCore.QThread()
m = Mainloop()
m.moveToThread(t)
t.started.connect(m.run)
t.start()
# Essentially I want to be able to interactively build a GUI here
dialog = QtWidgets.QDialog()
dialog.show()
基本上,我想模拟以下交互式 python会话,即不将其作为脚本运行以呈现现成的GUI。保持图形窗口外观阻止python解释器的神奇之处是什么?
Python 2.7.13 (default, Jan 19 2017, 14:48:08)
Type "copyright", "credits" or "license" for more information.
IPython 5.2.2 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object', use 'object??' for extra details.
In [1]: import matplotlib.pyplot as plt
In [2]: plt.ion()
In [3]: fig = plt.figure()
In [4]: # The last command opens a figure window which remains responsive.
...: I can resize it and the window redraws, yet I can still interact
...: with the python interpreter and interactively add new content to t
...: he figure
In [5]: ax = fig.add_subplot(111)
In [6]: # The last command updated the figure window and I can still inter
...: act with the interpreter
In [7]:
答案 0 :(得分:2)
神奇不是由Matplotlib完成的,而是由IPython完成的,实际上是名为magic command。
如果你用ipython --gui=qt
启动IPython,或者输入%gui qt
,Qt事件循环将被启动并集成到IPython中(--matplotlib
选项也会这样做但是对于默认的后端)。之后,您只需在命令行上创建小部件,而无需启动事件循环。
~> ipython
Python 3.5.3 |Continuum Analytics, Inc.| (default, Mar 6 2017, 12:15:08)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.1.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: %gui qt
In [2]: from PyQt5 import QtWidgets
In [3]: win = QtWidgets.QPushButton("click me")
In [4]: win.show()
In [5]: win.raise_()
Integrating with GUI event loop上有一个简短的部分,解释了这是如何工作的。但为了清楚起见,您不必遵循这些说明,因为已经为Qt实现了事件循环集成。只需使用%gui qt
magic-command。
<强>更新强>
所以你确实可以在没有IPython的情况下做到这一点。 PyQt使得同时拥有常规Python shell和运行事件循环成为可能,如PyQt参考指南中Using PyQt5 from the Python Shell部分所述。
差别在于您需要自己明确创建QApplication
。例如类型:
~> python
Python 3.6.0 |Continuum Analytics, Inc.| (default, Dec 23 2016, 13:19:00)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from PyQt5.QtWidgets import QApplication, QWidget
>>> a = QApplication([])
>>> w = QWidget()
>>> w.show()
>>> w.raise_()
我想知道它如何与Matplotlib一起工作并在the source code of pyplot中查看了一下。在我看来,Matplotlib可以处理这两种情况。执行plt.ion()
时,会调用install_repl_displayhook
函数。它的文档字符串说:
安装一个repl显示挂钩,以便自动显示任何陈旧的图形 当控件返回到repl时重绘。这适用于IPython 终端和内核,以及香草蟒蛇壳。
因此,尽管IPython不是Matplotlib的依赖项,但Matplotlib知道IPython并且可以检测它是否在IPython shell或常规Python shell中。