Show More
@@ -0,0 +1,103 b'' | |||
|
1 | ================================ | |
|
2 | Integrating with GUI event loops | |
|
3 | ================================ | |
|
4 | ||
|
5 | When the user types ``%gui qt``, IPython integrates itself with the Qt event | |
|
6 | loop, so you can use both a GUI and an interactive prompt together. IPython | |
|
7 | supports a number of common GUI toolkits, but from IPython 3.0, it is possible | |
|
8 | to integrate other event loops without modifying IPython itself. | |
|
9 | ||
|
10 | Terminal IPython handles event loops very differently from the IPython kernel, | |
|
11 | so different steps are needed to integrate with each. | |
|
12 | ||
|
13 | Event loops in the terminal | |
|
14 | --------------------------- | |
|
15 | ||
|
16 | In the terminal, IPython uses a blocking Python function to wait for user input. | |
|
17 | However, the Python C API provides a hook, :c:func:`PyOS_InputHook`, which is | |
|
18 | called frequently while waiting for input. This can be set to a function which | |
|
19 | briefly runs the event loop and then returns. | |
|
20 | ||
|
21 | IPython provides Python level wrappers for setting and resetting this hook. To | |
|
22 | use them, subclass :class:`IPython.lib.inputhook.InputHookBase`, and define | |
|
23 | an ``enable(app=None)`` method, which initialises the event loop and calls | |
|
24 | ``self.manager.set_inputhook(f)`` with a function which will briefly run the | |
|
25 | event loop before exiting. Decorate the class with a call to | |
|
26 | :func:`IPython.lib.inputhook.register`:: | |
|
27 | ||
|
28 | from IPython.lib.inputhook import register, InputHookBase | |
|
29 | ||
|
30 | @register('clutter') | |
|
31 | class ClutterInputHook(InputHookBase): | |
|
32 | def enable(self, app=None): | |
|
33 | self.manager.set_inputhook(inputhook_clutter) | |
|
34 | ||
|
35 | You can also optionally define a ``disable()`` method, taking no arguments, if | |
|
36 | there are extra steps needed to clean up. IPython will take care of resetting | |
|
37 | the hook, whether or not you provide a disable method. | |
|
38 | ||
|
39 | The simplest way to define the hook function is just to run one iteration of the | |
|
40 | event loop, or to run until no events are pending. Most event loops provide some | |
|
41 | mechanism to do one of these things. However, the GUI may lag slightly, | |
|
42 | because the hook is only called every 0.1 seconds. Alternatively, the hook can | |
|
43 | keep running the event loop until there is input ready on stdin. IPython | |
|
44 | provides a function to facilitate this: | |
|
45 | ||
|
46 | .. currentmodule:: IPython.lib.inputhook | |
|
47 | ||
|
48 | .. function:: stdin_ready() | |
|
49 | ||
|
50 | Returns True if there is something ready to read on stdin. | |
|
51 | ||
|
52 | If this is the case, the hook function should return immediately. | |
|
53 | ||
|
54 | This is implemented for Windows and POSIX systems - on other platforms, it | |
|
55 | always returns True, so that the hook always gives Python a chance to check | |
|
56 | for input. | |
|
57 | ||
|
58 | ||
|
59 | Event loops in the kernel | |
|
60 | ------------------------- | |
|
61 | ||
|
62 | The kernel runs its own event loop, so it's simpler to integrate with others. | |
|
63 | IPython allows the other event loop to take control, but it must call | |
|
64 | :meth:`IPython.kernel.zmq.kernelbase.Kernel.do_one_iteration` periodically. | |
|
65 | ||
|
66 | To integrate with this, write a function that takes a single argument, | |
|
67 | the IPython kernel instance, arranges for your event loop to call | |
|
68 | ``kernel.do_one_iteration()`` at least every ``kernel._poll_interval`` seconds, | |
|
69 | and starts the event loop. | |
|
70 | ||
|
71 | Decorate this function with :func:`IPython.kernel.zmq.eventloops.register_integration`, | |
|
72 | passing in the names you wish to register it for. Here is a slightly simplified | |
|
73 | version of the Tkinter integration already included in IPython:: | |
|
74 | ||
|
75 | @register_integration('tk') | |
|
76 | def loop_tk(kernel): | |
|
77 | """Start a kernel with the Tk event loop.""" | |
|
78 | from tkinter import Tk | |
|
79 | ||
|
80 | # Tk uses milliseconds | |
|
81 | poll_interval = int(1000*kernel._poll_interval) | |
|
82 | # For Tkinter, we create a Tk object and call its withdraw method. | |
|
83 | class Timer(object): | |
|
84 | def __init__(self, func): | |
|
85 | self.app = Tk() | |
|
86 | self.app.withdraw() | |
|
87 | self.func = func | |
|
88 | ||
|
89 | def on_timer(self): | |
|
90 | self.func() | |
|
91 | self.app.after(poll_interval, self.on_timer) | |
|
92 | ||
|
93 | def start(self): | |
|
94 | self.on_timer() # Call it once to get things going. | |
|
95 | self.app.mainloop() | |
|
96 | ||
|
97 | kernel.timer = Timer(kernel.do_one_iteration) | |
|
98 | kernel.timer.start() | |
|
99 | ||
|
100 | Some event loops can go one better, and integrate checking for messages on the | |
|
101 | kernel's ZMQ sockets, making the kernel more responsive than plain polling. How | |
|
102 | to do this is outside the scope of this document; if you are interested, look at | |
|
103 | the integration with Qt in :mod:`IPython.kernel.zmq.eventloops`. |
@@ -0,0 +1,4 b'' | |||
|
1 | * It's now possible to provide mechanisms to integrate IPython with other event | |
|
2 | loops, in addition to the ones we already support. This lets you run GUI code | |
|
3 | in IPython with an interactive prompt, and to embed the IPython | |
|
4 | kernel in GUI applications. See :doc:`/config/eventloops` for details. |
@@ -190,13 +190,12 b' class InputHookManager(object):' | |||
|
190 | 190 | the names with which to register this GUI integration. The classes |
|
191 | 191 | themselves should subclass :class:`InputHookBase`. |
|
192 | 192 | |
|
193 |
|
|
|
194 | -------- | |
|
193 | :: | |
|
195 | 194 | |
|
196 | @inputhook_manager.register('qt') | |
|
197 | class QtInputHook(InputHookBase): | |
|
198 | def enable(self, app=None): | |
|
199 | ... | |
|
195 | @inputhook_manager.register('qt') | |
|
196 | class QtInputHook(InputHookBase): | |
|
197 | def enable(self, app=None): | |
|
198 | ... | |
|
200 | 199 | """ |
|
201 | 200 | def decorator(cls): |
|
202 | 201 | inst = cls(self) |
General Comments 0
You need to be logged in to leave comments.
Login now