git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@28366 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
		
			
				
	
	
		
			299 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			299 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
 | 
						|
#----------------------------------------------------------------------
 | 
						|
 | 
						|
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)
 | 
						|
        EVT_CLOSE(self.frame, self.OnCloseWindow)
 | 
						|
        
 | 
						|
 | 
						|
    def OnCloseWindow(self, event):
 | 
						|
        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, 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 flush(self):
 | 
						|
        pass
 | 
						|
    
 | 
						|
 | 
						|
 | 
						|
#----------------------------------------------------------------------
 | 
						|
 | 
						|
_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, 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 SystemExit:
 | 
						|
                raise
 | 
						|
            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.)
 | 
						|
        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
 | 
						|
        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=None):
 | 
						|
        """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
 | 
						|
 | 
						|
 | 
						|
    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):
 | 
						|
    """
 | 
						|
    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):
 | 
						|
        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 = wx.Frame(None, -1, "Widget Tester", pos=(0,0), size=self.size)
 | 
						|
        self.SetTopWindow(self.frame)
 | 
						|
        return True
 | 
						|
 | 
						|
    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 wxWidgets is holding.  When
 | 
						|
# the sys module is unloaded, the refcount on sys.__wxPythonCleanup
 | 
						|
# goes to zero and it calls the wx.App_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...
 | 
						|
## import atexit
 | 
						|
## atexit.register(_core_.wxApp_CleanUp)
 | 
						|
 | 
						|
 | 
						|
#----------------------------------------------------------------------------
 |