【问题标题】:Why does PyQt4 behave differently between Jupyter and IPython notebook?为什么 PyQt4 在 Jupyter 和 IPython 笔记本之间的行为不同?
【发布时间】:2017-10-30 05:43:43
【问题描述】:

我创建了一个基于 PyQt4 的带有 GUI 的大型 python 程序。我希望该软件包既可以在 IPython 笔记本(Windows 上使用 Python 2.7 的旧安装)、Jupyter 笔记本(最近使用 Anaconda 安装的 Python 3.5)中运行,也可以作为在命令行上传递的 python 程序运行。我在 Jupyter notebook 中运行代码时遇到问题(直接在底部查看)。

我的模块 mymodule.py 看起来像这样(非常简化,在许多其他 python 文件显示之前大约 10k 行):

from PyQt4 import QtCore, QtGui

class MyModule(object):
    def __init__(self):
        self.window = QtGui.QMainWindow()
        self.window.show()

命令行的典型用法是

python myscript.py

使用以下文件 myscript.py

from PyQt4 import QtCore, QtGui
import mymodule

m = mymodule.MyModule()

APP = QtGui.QApplication.instance()
APP.exec_()

这很好用。我知道需要 APP.exec_() 来启动某种通过 Gui 交互事件工作的 EventLoop。

在 IPython 笔记本中,用户通常会这样做

import mymodule
m = mymodule.MyModule() # opens the gui
# this still leaves the console active to allow things like this:
m.change_color("red")

我可以毫无问题地运行它,我知道 IPython 以某种方式在幕后处理了 EventLoop。

现在,在 Jupyter notebook 中运行相同的命令,会打开一个窗口,但在允许任何用户交互之前冻结。所以我相信 Jupyter notebook 没有正确处理这些事件,因为我没有告诉它这样做。我发现的一种方法是在运行我的代码之前执行命令%pylab。但是,我经常遇到与此相关的问题,例如在启动程序之前直接连续运行%pylab%matplotlib inline 时,一旦我加载我的代码,这会导致再次冻结(奇怪的是,颠倒了这两个神奇的顺序命令再次起作用)。另外,如果可以避免的话,我不想强​​迫我的程序的用户在每个新笔记本中执行 %pylab(也是因为我认为这需要安装 matlab,这不是我的程序的要求)。

我必须在 mymodule.py 中添加什么代码才能使内容与 Jupyter 笔记本中描述的用户代码兼容?谁能更清楚地解释 IPython 笔记本和 Jupyter 笔记本如何以不同的方式管理 QEventLoop/QApplication(或这里的重要概念),以及魔术命令如何与此混淆?因此,我害怕我的程序中隐藏的错误,并希望使其尽可能健壮,以免让用户感到沮丧。

【问题讨论】:

    标签: python pyqt4 jupyter-notebook ipython-notebook qeventloop


    【解决方案1】:

    这是一个有效的解决方案,它允许在不区分不同 IPython/Jupyter 版本和“原始”Python 的情况下运行代码。我的__init__.py 文件开头包含此部分:

    # enable IPython QtGui support if needed
    try:
        from IPython import get_ipython
        get_ipython().magic('gui qt')
    except BaseException as e:
        # issued if code runs in bare Python
        print('Could not enable IPython gui support: %s.' % e)
    
    # get QApplication instance
    from PyQt4 import QtCore, QtGui
    APP = QtGui.QApplication.instance()
    if APP is None:
        print('Creating new QApplication instance "mymodule"')
        APP = QtGui.QApplication(['mymodule'])
    

    在原始 Python 上运行的脚本只需要这个:

    import mymodule  # imports the above code
    from PyQt4 import QtCore, QtGui
    if __name__ == '__main__':
        QtGui.QApplication.instance().exec_()
    

    我没有发现这不起作用的用例。

    【讨论】:

      猜你喜欢
      • 2022-12-03
      • 1970-01-01
      • 2015-05-12
      • 1970-01-01
      • 2015-10-15
      • 1970-01-01
      • 1970-01-01
      • 2013-04-28
      • 2015-12-10
      相关资源
      最近更新 更多