X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/d14a1e28567de23c586bc80017073d0c39f8d18f..84bc0d49e411fd74ddac8b13318fc2edfba9258a:/wxPython/src/_app_ex.py diff --git a/wxPython/src/_app_ex.py b/wxPython/src/_app_ex.py index 8408aa6f23..a7fef27613 100644 --- a/wxPython/src/_app_ex.py +++ b/wxPython/src/_app_ex.py @@ -2,68 +2,151 @@ #---------------------------------------------------------------------- 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.pos = wx.DefaultPosition + self.size = (450, 300) 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, self.pos, self.size, + style=wx.DEFAULT_FRAME_STYLE) + self.text = wx.TextCtrl(self.frame, -1, "", + style=wx.TE_MULTILINE|wx.TE_READONLY) + self.text.AppendText(st) + self.frame.Show(True) + self.frame.Bind(wx.EVT_CLOSE, self.OnCloseWindow) + + def OnCloseWindow(self, event): - if self.frame != None: + if self.frame is not None: self.frame.Destroy() self.frame = None self.text = None + # These methods provide the file-like output behaviour. - def write(self, str): - if not wx.Thread_IsMain(): - # Aquire the GUI mutex before making GUI calls. Mutex is released - # when locker is deleted at the end of this function. - locker = wx.MutexGuiLocker() - - if not self.frame: - 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) - self.text.AppendText(str) + 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 != None: - if not wx.Thread_IsMain(): - locker = wx.MutexGuiLocker() - self.frame.Close() + if self.frame is not None: + wx.CallAfter(self.frame.Close) + + + def flush(self): + pass + #---------------------------------------------------------------------- -# The main application class. Derive from this and implement an OnInit -# method that creates a frame and then calls self.SetTopWindow(frame) _defRedirect = (wx.Platform == '__WXMSW__' or wx.Platform == '__WXMAC__') - + class App(wx.PyApp): + """ + The ``wx.App`` class represents the application and is used to: + + * bootstrap the wxPython system and initialize the underlying + gui toolkit + * set and get application-wide properties + * implement the windowing system main message or event loop, + and to dispatch events to window instances + * etc. + + Every application must have a ``wx.App`` instance, and all + creation of UI objects should be delayed until after the + ``wx.App`` object has been created in order to ensure that the gui + platform and wxWidgets have been fully initialized. + + Normally you would derive from this class and implement an + ``OnInit`` method that creates a frame and then calls + ``self.SetTopWindow(frame)``. + + :see: `wx.PySimpleApp` for a simpler app class that can be used + directly. + """ + outputWindowClass = PyOnDemandOutputWindow - def __init__(self, redirect=_defRedirect, filename=None, useBestVisual=False): + def __init__(self, redirect=_defRedirect, filename=None, + useBestVisual=False, clearSigInt=True): + """ + Construct a ``wx.App`` object. + + :param redirect: Should ``sys.stdout`` and ``sys.stderr`` be + redirected? Defaults to True on Windows and Mac, False + otherwise. If `filename` is None then output will be + redirected to a window that pops up as needed. (You can + control what kind of window is created for the output by + resetting the class variable ``outputWindowClass`` to a + class of your choosing.) + + :param filename: The name of a file to redirect output to, if + redirect is True. + + :param useBestVisual: Should the app try to use the best + available visual provided by the system (only relevant on + systems that have more than one visual.) This parameter + must be used instead of calling `SetUseBestVisual` later + on because it must be set before the underlying GUI + toolkit is initialized. + + :param clearSigInt: Should SIGINT be cleared? This allows the + app to terminate upon a Ctrl-C in the console like other + GUI apps will. + + :note: You should override OnInit to do applicaition + initialization to ensure that the system, toolkit and + wxWidgets are fully initialized. + """ + 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 - + # make sure we can create a GUI + if not self.IsDisplayAvailable(): + + if wx.Platform == "__WXMAC__": + msg = """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.""" + + elif wx.Platform == "__WXGTK__": + msg ="Unable to access the X Display, is $DISPLAY set properly?" + + else: + msg = "Unable to create GUI" + # TODO: more description is needed for wxMSW... + + raise SystemExit(msg) + # This has to be done before OnInit self.SetUseBestVisual(useBestVisual) @@ -73,11 +156,12 @@ your Mac.""" # 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 + if clearSigInt: + try: + import signal + signal.signal(signal.SIGINT, signal.SIG_DFL) + except: + pass # Save and redirect the stdio to a window? self.stdioWin = None @@ -85,30 +169,49 @@ your Mac.""" if redirect: self.RedirectStdio(filename) + # Use Python's install prefix as the default + wx.StandardPaths.Get().SetInstallPrefix(_sys.prefix) + + # Until the new native control for wxMac is up to par, still use the generic one. + wx.SystemOptions.SetOptionInt("mac.listctrl.always_use_generic", 1) + # 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 OnPreInit(self): + """ + Things that must be done after _BootstrapApp has done its + thing, but would be nice if they were already done by the time + that OnInit is called. + """ + wx.StockGDI._initStockObjects() + + + def __del__(self, destroy=wx.PyApp.__del__): + self.RestoreStdio() # Just in case the MainLoop was overridden + destroy(self) + def Destroy(self): + self.this.own(False) + wx.PyApp.Destroy(self) 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): + def RedirectStdio(self, filename=None): + """Redirect sys.stdout and sys.stderr to a file or a popup window.""" if filename: _sys.stdout = _sys.stderr = open(filename, 'a') else: @@ -117,67 +220,102 @@ your Mac.""" def RestoreStdio(self): - _sys.stdout, _sys.stderr = self.saveStdio - + try: + _sys.stdout, _sys.stderr = self.saveStdio + except: + pass -# 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 + def SetOutputWindowAttributes(self, title=None, pos=None, size=None): + """ + Set the title, position and/or size of the output window if + the stdio has been redirected. This should be called before + any output would cause the output window to be created. + """ + if self.stdioWin: + if title is not None: + self.stdioWin.title = title + if pos is not None: + self.stdioWin.pos = pos + if size is not None: + self.stdioWin.size = size + + + + +# change from wx.PyApp_XX to wx.App_XX +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): - def __init__(self, redirect=False, filename=None): - wx.App.__init__(self, redirect, filename) + """ + 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. For example:: + + app = wx.PySimpleApp() + frame = wx.Frame(None, title='Hello World') + frame.Show() + app.MainLoop() + + :see: `wx.App` + """ + + def __init__(self, redirect=False, filename=None, + useBestVisual=False, clearSigInt=True): + """ + :see: `wx.App.__init__` + """ + wx.App.__init__(self, redirect, filename, useBestVisual, clearSigInt) + 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.frame = wx.Frame(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) + def SetWidget(self, widgetClass, *args, **kwargs): + w = widgetClass(self.frame, *args, **kwargs) 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 +# know when to cleanup system resources that wxWidgets is holding. When # the sys module is unloaded, the refcount on sys.__wxPythonCleanup -# goes to zero and it calls the wxApp_CleanUp function. +# goes to zero and it calls the wx.App_CleanUp function. class __wxPyCleanup: def __init__(self): - self.cleanup = _core.App_CleanUp + 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 +## import atexit +## atexit.register(_core_.wxApp_CleanUp) #----------------------------------------------------------------------------