##// END OF EJS Templates
Add docs about extending GUI integration
Thomas Kluyver -
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 the names with which to register this GUI integration. The classes
190 the names with which to register this GUI integration. The classes
191 themselves should subclass :class:`InputHookBase`.
191 themselves should subclass :class:`InputHookBase`.
192
192
193 Examples
193 ::
194 --------
195
194
196 @inputhook_manager.register('qt')
195 @inputhook_manager.register('qt')
197 class QtInputHook(InputHookBase):
196 class QtInputHook(InputHookBase):
198 def enable(self, app=None):
197 def enable(self, app=None):
199 ...
198 ...
200 """
199 """
201 def decorator(cls):
200 def decorator(cls):
202 inst = cls(self)
201 inst = cls(self)
@@ -30,3 +30,4 b' Extending and integrating with IPython'
30 custommagics
30 custommagics
31 inputtransforms
31 inputtransforms
32 callbacks
32 callbacks
33 eventloops
General Comments 0
You need to be logged in to leave comments. Login now