【问题标题】:embedding ipython qtconsole and passing objects嵌入 ipython qtconsole 并传递对象
【发布时间】:2014-12-27 07:06:21
【问题描述】:

我想将一个 ipython qtconsole 作为子窗口放入 MDI pyqt 应用程序中,然后从 qtconsole 创建其他子窗口。所以嵌入式 qtconsole 需要能够访问应用程序的命名空间。根据 ipython 文档中的this page,InProcessKernel 将是最好的解决方案。我从 python 终端运行this example script(在下面复制)(如果我从 ipython 运行它,我会得到一个 MultipleInstanceError)。但是暂时忘记创建子窗口,首先我需要弄清楚如何将对象传递到嵌入式 qtconsole。

  1. 我第一次运行inprocess_qtconsole.py,嵌入式qtconsole的命名空间是空的。为什么之前在初始 python 终端或脚本中创建的对象没有传递到嵌入式 qtconsole?
  2. 如果我关闭包含嵌入式 qtconsole 的应用程序,在初始终端中定义一些变量,然后再次运行脚本,为什么我现在可以访问这些变量,以及 if __name__ == __main__ 下脚本中的变量?李>
  3. 有没有办法启动嵌入式 qtconsole 而不会阻塞我启动它的 python 终端?

我主要只是希望能够将 QMainWindow 实例传递到嵌入式 qtconsole,因为创建子窗口需要传递这个对象(类似于window.mdiArea.addSubWindow())。如果我运行脚本两次,它会以一种骇人听闻的方式工作。

顺便说一句,在其他官方 ipython 示例 (ipkernel_qtapp.py) 中使用的 internal_ipkernel 模块似乎在最新版本的 ipython 中缺失。

运行 Python 2.7、IPython 2.2/2.3 和 Windows 8.1。

from __future__ import print_function
import os

from IPython.qt.console.rich_ipython_widget import RichIPythonWidget
from IPython.qt.inprocess import QtInProcessKernelManager
from IPython.lib import guisupport


def print_process_id():
    print('Process ID is:', os.getpid())


def main():
    # Print the ID of the main process
    print_process_id()

    app = guisupport.get_app_qt4()

    # Create an in-process kernel
    # >>> print_process_id()
    # will print the same process ID as the main process
    kernel_manager = QtInProcessKernelManager()
    kernel_manager.start_kernel()
    kernel = kernel_manager.kernel
    kernel.gui = 'qt4'
    kernel.shell.push({'foo': 43, 'print_process_id': print_process_id})

    kernel_client = kernel_manager.client()
    kernel_client.start_channels()

    def stop():
        kernel_client.stop_channels()
        kernel_manager.shutdown_kernel()
        app.exit()

    control = RichIPythonWidget()
    control.kernel_manager = kernel_manager
    control.kernel_client = kernel_client
    control.exit_requested.connect(stop)
    control.show()

    guisupport.start_event_loop_qt4(app)


if __name__ == '__main__':
    test = 'hello'
    main()

【问题讨论】:

    标签: python pyqt ipython qtconsole


    【解决方案1】:

    您可以使用它在给定的 qt 小部件中启动 ipython 控制台:

    from IPython.qt.console.rich_ipython_widget import RichIPythonWidget
    from IPython.qt.inprocess import QtInProcessKernelManager
    
    def put_ipy(parent):
        kernel_manager = QtInProcessKernelManager()
        kernel_manager.start_kernel()
        kernel = kernel_manager.kernel
        kernel.gui = 'qt4'
    
        kernel_client = kernel_manager.client()
        kernel_client.start_channels()
        kernel_client.namespace  = parent
    
        def stop():
            kernel_client.stop_channels()
            kernel_manager.shutdown_kernel()
    
        layout = QtGui.QVBoxLayout(parent)
        widget = RichIPythonWidget(parent=parent)
        layout.addWidget(widget)
        widget.kernel_manager = kernel_manager
        widget.kernel_client = kernel_client
        widget.exit_requested.connect(stop)
        ipython_widget = widget
        ipython_widget.show()
        kernel.shell.push({'widget':widget,'kernel':kernel, 'parent':parent})
        return {'widget':widget,'kernel':kernel}
    

    要从控制台弹出窗口,您可以运行

    app = QtGui.QApplication([])
    win = QtGui.QWidget(None)
    win.show()
    put_ipy(win)
    

    但这会将原来的python解释器换成一个空的ipy解释器,只定义你传递的变量(这里是小部件、内核、父级),即控制台和命令行都具有相同的内核,并且原来的被屏蔽了。

    您可以通过在具有另一个主窗口和一组交互的 qt 应用程序中执行上述操作来避免此类行为。要将变量传递给内核,请使用(如上)kernel.shell.push(dict)

    【讨论】:

    • 啊,好吧,不知怎的,我错过了kernel.shell.push 是传递对象的方式。避免阻塞的方法是省略通常的app.exec_()guisupport.start_event_loop_qt4(app)。谢谢!
    • 谢谢,很好的回答!从IPython.qt 导入现在已弃用,取而代之的是从qtconsole 导入。
    • 最近在控制台出现任何异常后我得到Error: execution aborted!有人有想法吗?
    猜你喜欢
    • 1970-01-01
    • 2016-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-11
    • 2014-11-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多