简体   繁体   English

嵌入ipython qtconsole并传递对象

[英]embedding ipython qtconsole and passing objects

I want to put an ipython qtconsole in an MDI pyqt application as a subwindow, and then create other subwindows from the qtconsole. 我想将ipython qtconsole放在MDI pyqt应用程序中作为子窗口,然后从qtconsole创建其他子窗口。 So the embedded qtconsole needs to be able to access the namespace of the application. 因此,嵌入式qtconsole需要能够访问应用程序的名称空间。 According to this page from the ipython docs, an InProcessKernel would be the best solution. 根据该页面从IPython中的文档,一个InProcessKernel将是最好的解决方案。 I ran this example script (reproduced below) from a python terminal (if I run it from ipython, I get a MultipleInstanceError). 我从python终端运行了这个示例脚本 (如下所示)(如果从ipython运行它,则会收到MultipleInstanceError)。 But forget about creating subwindows for now, first I need to figure out how to pass objects into the embedded qtconsole. 但是暂时不要创建子窗口,首先,我需要弄清楚如何将对象传递到嵌入式qtconsole中。

  1. The first time I run inprocess_qtconsole.py, the embedded qtconsole's namespace is empty. 我第一次运行inprocess_qtconsole.py时,嵌入式qtconsole的名称空间为空。 Why do objects previously created in the initial python terminal, or in the script, not get passed to the embedded qtconsole? 为什么先前在初始python终端或脚本中创建的对象不会传递给嵌入式qtconsole?
  2. If I close the application containing the embedded qtconsole, define some variables in the initial terminal, and run the script again, why can I now access these variables, as well as the ones from the script under if __name__ == __main__ ? 如果关闭包含嵌入式qtconsole的应用程序,在初始终端中定义一些变量,然后再次运行脚本,为什么现在可以访问这些变量以及if __name__ == __main__下脚本中的变量?
  3. Is there a way to start the embedded qtconsole without blocking the python terminal that I started it from? 有没有一种方法可以启动嵌入式qtconsole而不阻止我从中启动的python终端?

I mostly just want to be able to pass the QMainWindow instance into the embedded qtconsole, because creating subwindows requires passing this object (something like window.mdiArea.addSubWindow() ). 我主要只是希望能够将QMainWindow实例传递到嵌入式qtconsole中,因为创建子窗口需要传递该对象(类似于window.mdiArea.addSubWindow() )。 It sort of works in a hackish way if I run the script twice. 如果我两次运行脚本,它的工作方式会有些怪异。

By the way, the internal_ipkernel module used in one of the other official ipython examples (ipkernel_qtapp.py) seems to be missing from the latest versions of ipython. 顺便说一下,最新版本的ipython中似乎缺少其他官方ipython示例之一(ipkernel_qtapp.py)中使用的internal_ipkernel模块。

Running Python 2.7, IPython 2.2/2.3 and Windows 8.1. 运行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()

You can use this to start an ipython console in a given qt widget: 您可以使用它在给定的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}

To pop up windows from the console, you can run 要从控制台弹出窗口,可以运行

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

but this will swap the original python interpreter with an empty ipy one, with only the variables defined that you passed (widget, kernel, parent here), ie, both the console and the command line have the same kernels, and the original one is blocked. 但这会将原来的python解释器换成一个空的ipy解释器,只带有您传递的已定义变量(widget,kernel,parent在这里),即控制台和命令行具有相同的内核,而原来的是受阻。

You can get around such behaviour by doing the above within a qt application with another main window and set of interactions. 通过在带有另一个主窗口和一组交互的qt应用程序中执行上述操作,可以避免这种行为。 To pass variables to the kernel, use (as above) kernel.shell.push(dict) . 要将变量传递给内核,请使用(如上所述) kernel.shell.push(dict)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM