#---------------------------------------------------------------------- class PyOnDemandOutputWindow: """ A class that can be used for redirecting Python's stdout and stderr streams. It will do nothing until something is wrriten to the stream at which point it will create a Frame with a text area and write the text there. """ def __init__(self, title = "wxPython: stdout/stderr"): self.frame = None self.title = title self.parent = None def SetParent(self, parent): """Set the window to be used as the popup Frame's parent.""" self.parent = parent def CreateOutputWindow(self, st): self.frame = wx.Frame(self.parent, -1, self.title, style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE) self.text = wxTextCtrl(self.frame, -1, "", style = wx.TE_MULTILINE | wx.TE_READONLY) self.frame.SetSize((450, 300)) self.frame.Show(True) EVT_CLOSE(self.frame, self.OnCloseWindow) # These methods provide the file-like output behaviour. def write(self, text): """ Create the output window if needed and write the string to it. If not called in the context of the gui thread then uses CallAfter to do the work there. """ if self.frame is None: if not wx.Thread_IsMain(): wx.CallAfter(self.CreateOutputWindow, text) else: self.CreateOutputWindow(text) else: if not wx.Thread_IsMain(): wx.CallAfter(self.text.AppendText, text) else: self.text.AppendText(text) def close(self): if self.frame is not None: wx.CallAfter(self.frame.Close) def OnCloseWindow(self, event): if self.frame is not None: self.frame.Destroy() self.frame = None self.text = None #---------------------------------------------------------------------- _defRedirect = (wx.Platform == '__WXMSW__' or wx.Platform == '__WXMAC__') class App(wx.PyApp): """ The main application class. Derive from this and implement an OnInit method that creates a frame and then calls self.SetTopWindow(frame) """ outputWindowClass = PyOnDemandOutputWindow def __init__(self, redirect=_defRedirect, filename=None, useBestVisual=False): wx.PyApp.__init__(self) if wx.Platform == "__WXMAC__": try: import MacOS if not MacOS.WMAvailable(): print """\ This program needs access to the screen. Please run with 'pythonw', not 'python', and only when you are logged in on the main display of your Mac.""" _sys.exit(1) except: pass # This has to be done before OnInit self.SetUseBestVisual(useBestVisual) # Set the default handler for SIGINT. This fixes a problem # where if Ctrl-C is pressed in the console that started this # app then it will not appear to do anything, (not even send # KeyboardInterrupt???) but will later segfault on exit. By # setting the default handler then the app will exit, as # expected (depending on platform.) try: import signal signal.signal(signal.SIGINT, signal.SIG_DFL) except: pass # Save and redirect the stdio to a window? self.stdioWin = None self.saveStdio = (_sys.stdout, _sys.stderr) if redirect: self.RedirectStdio(filename) # This finishes the initialization of wxWindows and then calls # the OnInit that should be present in the derived class self._BootstrapApp() def __del__(self): try: self.RestoreStdio() # Just in case the MainLoop was overridden except: pass def SetTopWindow(self, frame): """Set the \"main\" top level window""" if self.stdioWin: self.stdioWin.SetParent(frame) wx.PyApp.SetTopWindow(self, frame) def MainLoop(self): """Execute the main GUI event loop""" wx.PyApp.MainLoop(self) self.RestoreStdio() def RedirectStdio(self, filename): """Redirect sys.stdout and sys.stderr to a file or a popup window.""" if filename: _sys.stdout = _sys.stderr = open(filename, 'a') else: self.stdioWin = self.outputWindowClass() _sys.stdout = _sys.stderr = self.stdioWin def RestoreStdio(self): _sys.stdout, _sys.stderr = self.saveStdio # change from wxPyApp_ to wxApp_ App_GetMacSupportPCMenuShortcuts = _core.PyApp_GetMacSupportPCMenuShortcuts App_GetMacAboutMenuItemId = _core.PyApp_GetMacAboutMenuItemId App_GetMacPreferencesMenuItemId = _core.PyApp_GetMacPreferencesMenuItemId App_GetMacExitMenuItemId = _core.PyApp_GetMacExitMenuItemId App_GetMacHelpMenuTitleName = _core.PyApp_GetMacHelpMenuTitleName App_SetMacSupportPCMenuShortcuts = _core.PyApp_SetMacSupportPCMenuShortcuts App_SetMacAboutMenuItemId = _core.PyApp_SetMacAboutMenuItemId App_SetMacPreferencesMenuItemId = _core.PyApp_SetMacPreferencesMenuItemId App_SetMacExitMenuItemId = _core.PyApp_SetMacExitMenuItemId App_SetMacHelpMenuTitleName = _core.PyApp_SetMacHelpMenuTitleName App_GetComCtl32Version = _core.PyApp_GetComCtl32Version #---------------------------------------------------------------------------- class PySimpleApp(wx.App): """ A simple application class. You can just create one of these and then then make your top level windows later, and not have to worry about OnInit.""" def __init__(self, redirect=False, filename=None, useBestVisual=False): wx.App.__init__(self, redirect, filename, useBestVisual) def OnInit(self): wx.InitAllImageHandlers() return True # Is anybody using this one? class PyWidgetTester(wx.App): def __init__(self, size = (250, 100)): self.size = size wx.App.__init__(self, 0) def OnInit(self): self.frame = wxFrame(None, -1, "Widget Tester", pos=(0,0), size=self.size) self.SetTopWindow(self.frame) return True def SetWidget(self, widgetClass, *args): w = widgetClass(self.frame, *args) self.frame.Show(True) #---------------------------------------------------------------------------- # DO NOT hold any other references to this object. This is how we # know when to cleanup system resources that wxWin is holding. When # the sys module is unloaded, the refcount on sys.__wxPythonCleanup # goes to zero and it calls the wxApp_CleanUp function. class __wxPyCleanup: def __init__(self): self.cleanup = _core.App_CleanUp def __del__(self): self.cleanup() _sys.__wxPythonCleanup = __wxPyCleanup() ## # another possible solution, but it gets called too early... ## if sys.version[0] == '2': ## import atexit ## atexit.register(_core.wxApp_CleanUp) ## else: ## sys.exitfunc = _core.wxApp_CleanUp #----------------------------------------------------------------------------