diff --git a/IPython/frontend/qt/console/scripts/ipythonqt.py b/IPython/frontend/qt/console/scripts/ipythonqt.py index f4409aa..ac892a0 100755 --- a/IPython/frontend/qt/console/scripts/ipythonqt.py +++ b/IPython/frontend/qt/console/scripts/ipythonqt.py @@ -35,8 +35,11 @@ def main(): group = parser.add_mutually_exclusive_group() group.add_argument('--pure', action='store_true', help = \ 'use a pure Python kernel instead of an IPython kernel') - group.add_argument('--pylab', action='store_true', - help='use a kernel with PyLab enabled') + group.add_argument('--pylab', type=str, metavar='GUI', nargs='?', + const='auto', help = \ + "Pre-load matplotlib and numpy for interactive use. If GUI is not \ + given, the GUI backend is matplotlib's, otherwise use one of: \ + ['tk', 'gtk', 'qt', 'wx', 'payload-svg'].") parser.add_argument('--rich', action='store_true', help='use a rich text frontend') args = parser.parse_args() @@ -56,7 +59,10 @@ def main(): if args.rich: kernel_manager.start_kernel(pylab='payload-svg') else: - kernel_manager.start_kernel(pylab='qt4') + if args.pylab == 'auto': + kernel_manager.start_kernel(pylab='qt4') + else: + kernel_manager.start_kernel(pylab=args.pylab) else: kernel_manager.start_kernel() kernel_manager.start_channels() diff --git a/IPython/lib/pylabtools.py b/IPython/lib/pylabtools.py index ad8ed7d..297c60a 100644 --- a/IPython/lib/pylabtools.py +++ b/IPython/lib/pylabtools.py @@ -73,8 +73,20 @@ def activate_matplotlib(backend): else: matplotlib.use(backend) matplotlib.interactive(True) + + # This must be imported last in the matplotlib series, after + # backend/interactivity choices have been made import matplotlib.pylab as pylab + # XXX For now leave this commented out, but depending on discussions with + # mpl-dev, we may be able to allow interactive switching... + #import matplotlib.pyplot + #matplotlib.pyplot.switch_backend(backend) + + pylab.show._needmain = False + # We need to detect at runtime whether show() is called by the user. + # For this, we wrap it into a decorator which adds a 'called' flag. + pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive) def import_pylab(user_ns, import_all=True): """Import the standard pylab symbols into user_ns.""" @@ -115,24 +127,8 @@ def pylab_activate(user_ns, gui=None, import_all=True): The actual gui used (if not given as input, it was obtained from matplotlib itself, and will be needed next to configure IPython's gui integration. """ - gui, backend = find_gui_and_backend(gui) activate_matplotlib(backend) - - # This must be imported last in the matplotlib series, after - # backend/interactivity choices have been made - import matplotlib.pylab as pylab - - # XXX For now leave this commented out, but depending on discussions with - # mpl-dev, we may be able to allow interactive switching... - #import matplotlib.pyplot - #matplotlib.pyplot.switch_backend(backend) - - pylab.show._needmain = False - # We need to detect at runtime whether show() is called by the user. - # For this, we wrap it into a decorator which adds a 'called' flag. - pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive) - import_pylab(user_ns) print """ diff --git a/IPython/zmq/ipkernel.py b/IPython/zmq/ipkernel.py index 6be1be3..3f7d5d2 100755 --- a/IPython/zmq/ipkernel.py +++ b/IPython/zmq/ipkernel.py @@ -293,16 +293,79 @@ class Kernel(Configurable): class QtKernel(Kernel): + """A Kernel subclass with Qt support.""" def start(self): """Start a kernel with QtPy4 event loop integration.""" + from PyQt4 import QtGui, QtCore - self.qapp = app = QtGui.QApplication([]) - self.qtimer = QtCore.QTimer() - self.qtimer.timeout.connect(self.do_one_iteration) - self.qtimer.start(50) - self.qapp.exec_() + self.app = QtGui.QApplication([]) + self.app.setQuitOnLastWindowClosed (False) + self.timer = QtCore.QTimer() + self.timer.timeout.connect(self.do_one_iteration) + self.timer.start(50) + self.app.exec_() + + +class WxKernel(Kernel): + """A Kernel subclass with Wx support.""" + def start(self): + """Start a kernel with wx event loop support.""" + + import wx + doi = self.do_one_iteration + + # We have to put the wx.Timer in a wx.Frame for it to fire properly. + # We make the Frame hidden when we create it in the main app below. + class TimerFrame(wx.Frame): + def __init__(self, func): + wx.Frame.__init__(self, None, -1) + self.timer = wx.Timer(self) + self.timer.Start(50) + self.Bind(wx.EVT_TIMER, self.on_timer) + self.func = func + def on_timer(self, event): + self.func() + + # We need a custom wx.App to create our Frame subclass that has the + # wx.Timer to drive the ZMQ event loop. + class IPWxApp(wx.App): + def OnInit(self): + self.frame = TimerFrame(doi) + self.frame.Show(False) + return True + + # The redirect=False here makes sure that wx doesn't replace + # sys.stdout/stderr with its own classes. + self.app = IPWxApp(redirect=False) + self.app.MainLoop() + + +class TkKernel(Kernel): + """A Kernel subclass with Tk support.""" + + def start(self): + """Start a Tk enabled event loop.""" + + import Tkinter + doi = self.do_one_iteration + + # For Tkinter, we create a Tk object and call its withdraw method. + class Timer(object): + def __init__(self, func): + self.app = Tkinter.Tk() + self.app.withdraw() + self.func = func + def on_timer(self): + self.func() + self.app.after(50, self.on_timer) + def start(self): + self.on_timer() # Call it once to get things going. + self.app.mainloop() + + self.timer = Timer(doi) + self.timer.start() #----------------------------------------------------------------------------- # Kernel main and launch functions @@ -365,22 +428,21 @@ given, the GUI backend is matplotlib's, otherwise use one of: \ _kernel_classes = { 'qt' : QtKernel, 'qt4' : QtKernel, - 'payload-svg':Kernel + 'payload-svg':Kernel, + 'wx' : WxKernel, + 'tk' : TkKernel } if namespace.pylab: if namespace.pylab == 'auto': gui, backend = pylabtools.find_gui_and_backend() else: gui, backend = pylabtools.find_gui_and_backend(namespace.pylab) - print gui, backend kernel_class = _kernel_classes.get(gui) if kernel_class is None: raise ValueError('GUI is not supported: %r' % gui) pylabtools.activate_matplotlib(backend) - print>>sys.__stdout__, kernel_class kernel = make_kernel(namespace, kernel_class, OutStream) - print >>sys.__stdout__, kernel if namespace.pylab: pylabtools.import_pylab(kernel.shell.user_ns)