2 #----------------------------------------------------------------------------
4 # Purpose: Testing lots of stuff, controls, window types, etc.
8 # Created: A long time ago, in a galaxy far, far away...
10 # Copyright: (c) 1999 by Total Control Software
11 # Licence: wxWindows license
12 #----------------------------------------------------------------------------
15 # * Problems with flickering related to ERASE_BACKGROUND
16 # and the splitters. Might be a problem with this 2.5 beta...?
17 # UPDATE: can't see on 2.5.2 GTK - maybe just a faster machine :)
19 # * Annoying switching between tabs and resulting flicker
20 # how to replace a page in the notebook without deleting/adding?
21 # Where is SetPage!? tried freeze...tried reparent of dummy panel....
24 # * UI design more prefessional
25 # * save file positions (new field in demoModules) (@ LoadDemoSource)
26 # * Update main overview
28 # * Why don't we move _treeList into a separate module
30 import sys
, os
, time
, traceback
, types
32 import wx
# This module uses the new wx namespace
39 ##print "wx.VERSION_STRING = %s (%s)" % (wx.VERSION_STRING, wx.USE_UNICODE and 'unicode' or 'ansi')
40 ##print "pid:", os.getpid()
41 ##raw_input("Press Enter...")
44 #---------------------------------------------------------------------------
49 ('Recent Additions/Updates', [
51 'AUI_DockingWindowMgr',
78 # managed windows == things with a (optional) caption you can close
79 ('Frames and Dialogs', [
80 'AUI_DockingWindowMgr',
101 'SingleChoiceDialog',
105 # dialogs from libraries
108 'ScrolledMessageDialog',
112 ('Core Windows/Controls', [
149 ('"Book" Controls', [
158 ('Custom Controls', [
175 # controls coming from other libraries
176 ('More Windows/Controls', [
177 'ActiveX_FlashWindow',
178 'ActiveX_IEHtmlWindow',
183 'CheckListCtrlMixin',
200 'MaskedEditControls',
203 'MultiSplitterWindow',
204 'OwnerDrawnComboBox',
221 # How to lay out the controls in a frame/dialog
231 'XmlResourceHandler',
232 'XmlResourceSubclass',
236 ('Process and Events', [
244 ##'infoframe', # needs better explanation and some fixing
248 ('Clipboard and DnD', [
274 ##'DialogUnits', # needs more explanations
294 ('Check out the samples dir too', [
301 #---------------------------------------------------------------------------
302 # Show how to derive a custom wxLog class
304 class MyLog(wx
.PyLog
):
305 def __init__(self
, textCtrl
, logTime
=0):
306 wx
.PyLog
.__init
__(self
)
308 self
.logTime
= logTime
310 def DoLogString(self
, message
, timeStamp
):
311 #print message, timeStamp
313 # message = time.strftime("%X", time.localtime(timeStamp)) + \
316 self
.tc
.AppendText(message
+ '\n')
319 class MyTP(wx
.PyTipProvider
):
321 return "This is my tip"
323 #---------------------------------------------------------------------------
324 # A class to be used to simply display a message in the demo pane
325 # rather than running the sample itself.
327 class MessagePanel(wx
.Panel
):
328 def __init__(self
, parent
, message
, caption
='', flags
=0):
329 wx
.Panel
.__init
__(self
, parent
)
334 if flags
& wx
.ICON_EXCLAMATION
:
335 artid
= wx
.ART_WARNING
336 elif flags
& wx
.ICON_ERROR
:
338 elif flags
& wx
.ICON_QUESTION
:
339 artid
= wx
.ART_QUESTION
340 elif flags
& wx
.ICON_INFORMATION
:
341 artid
= wx
.ART_INFORMATION
343 if artid
is not None:
344 bmp
= wx
.ArtProvider
.GetBitmap(artid
, wx
.ART_MESSAGE_BOX
, (32,32))
345 icon
= wx
.StaticBitmap(self
, -1, bmp
)
347 icon
= (32,32) # make a spacer instead
350 caption
= wx
.StaticText(self
, -1, caption
)
351 caption
.SetFont(wx
.Font(28, wx
.SWISS
, wx
.NORMAL
, wx
.BOLD
))
353 message
= wx
.StaticText(self
, -1, message
)
355 # add to sizers for layout
356 tbox
= wx
.BoxSizer(wx
.VERTICAL
)
362 hbox
= wx
.BoxSizer(wx
.HORIZONTAL
)
369 box
= wx
.BoxSizer(wx
.VERTICAL
)
371 box
.Add(hbox
, 0, wx
.EXPAND
)
378 #---------------------------------------------------------------------------
379 # A class to be used to display source code in the demo. Try using the
380 # wxSTC in the StyledTextCtrl_2 sample first, fall back to wxTextCtrl
381 # if there is an error, such as the stc module not being present.
385 ##raise ImportError # for testing the alternate implementation
387 from StyledTextCtrl_2
import PythonSTC
389 class DemoCodeEditor(PythonSTC
):
390 def __init__(self
, parent
):
391 PythonSTC
.__init
__(self
, parent
, -1, style
=wx
.BORDER_NONE
)
394 # Some methods to make it compatible with how the wxTextCtrl is used
395 def SetValue(self
, value
):
397 value
= value
.decode('iso8859_1')
399 self
.EmptyUndoBuffer()
402 def IsModified(self
):
403 return self
.GetModify()
408 def SetInsertionPoint(self
, pos
):
409 self
.SetCurrentPos(pos
)
412 def ShowPosition(self
, pos
):
413 line
= self
.LineFromPosition(pos
)
414 #self.EnsureVisible(line)
417 def GetLastPosition(self
):
418 return self
.GetLength()
420 def GetPositionFromLine(self
, line
):
421 return self
.PositionFromLine(line
)
423 def GetRange(self
, start
, end
):
424 return self
.GetTextRange(start
, end
)
426 def GetSelection(self
):
427 return self
.GetAnchor(), self
.GetCurrentPos()
429 def SetSelection(self
, start
, end
):
430 self
.SetSelectionStart(start
)
431 self
.SetSelectionEnd(end
)
433 def SelectLine(self
, line
):
434 start
= self
.PositionFromLine(line
)
435 end
= self
.GetLineEndPosition(line
)
436 self
.SetSelection(start
, end
)
438 def SetUpEditor(self
):
440 This method carries out the work of setting up the demo editor.
441 It's seperate so as not to clutter up the init code.
445 self
.SetLexer(stc
.STC_LEX_PYTHON
)
446 self
.SetKeyWords(0, " ".join(keyword
.kwlist
))
449 self
.SetProperty("fold", "1" )
451 # Highlight tab/space mixing (shouldn't be any)
452 self
.SetProperty("tab.timmy.whinge.level", "1")
454 # Set left and right margins
457 # Set up the numbers in the margin for margin #1
458 self
.SetMarginType(1, wx
.stc
.STC_MARGIN_NUMBER
)
459 # Reasonable value for, say, 4-5 digits using a mono font (40 pix)
460 self
.SetMarginWidth(1, 40)
462 # Indentation and tab stuff
463 self
.SetIndent(4) # Proscribed indent size for wx
464 self
.SetIndentationGuides(True) # Show indent guides
465 self
.SetBackSpaceUnIndents(True)# Backspace unindents rather than delete 1 space
466 self
.SetTabIndents(True) # Tab key indents
467 self
.SetTabWidth(4) # Proscribed tab size for wx
468 self
.SetUseTabs(False) # Use spaces rather than tabs, or
469 # TabTimmy will complain!
471 self
.SetViewWhiteSpace(False) # Don't view white space
473 # EOL: Since we are loading/saving ourselves, and the
474 # strings will always have \n's in them, set the STC to
475 # edit them that way.
476 self
.SetEOLMode(wx
.stc
.STC_EOL_LF
)
477 self
.SetViewEOL(False)
479 # No right-edge mode indicator
480 self
.SetEdgeMode(stc
.STC_EDGE_NONE
)
482 # Setup a margin to hold fold markers
483 self
.SetMarginType(2, stc
.STC_MARGIN_SYMBOL
)
484 self
.SetMarginMask(2, stc
.STC_MASK_FOLDERS
)
485 self
.SetMarginSensitive(2, True)
486 self
.SetMarginWidth(2, 12)
488 # and now set up the fold markers
489 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEREND
, stc
.STC_MARK_BOXPLUSCONNECTED
, "white", "black")
490 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEROPENMID
, stc
.STC_MARK_BOXMINUSCONNECTED
, "white", "black")
491 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERMIDTAIL
, stc
.STC_MARK_TCORNER
, "white", "black")
492 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERTAIL
, stc
.STC_MARK_LCORNER
, "white", "black")
493 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERSUB
, stc
.STC_MARK_VLINE
, "white", "black")
494 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDER
, stc
.STC_MARK_BOXPLUS
, "white", "black")
495 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEROPEN
, stc
.STC_MARK_BOXMINUS
, "white", "black")
497 # Global default style
498 if wx
.Platform
== '__WXMSW__':
499 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,
500 'fore:#000000,back:#FFFFFF,face:Courier New,size:9')
501 elif wx
.Platform
== '__WXMAC__':
502 # TODO: if this looks fine on Linux too, remove the Mac-specific case
503 # and use this whenever OS != MSW.
504 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,
505 'fore:#000000,back:#FFFFFF,face:Courier')
507 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,
508 'fore:#000000,back:#FFFFFF,face:Courier,size:9')
510 # Clear styles and revert to default.
513 # Following style specs only indicate differences from default.
514 # The rest remains unchanged.
516 # Line numbers in margin
517 self
.StyleSetSpec(wx
.stc
.STC_STYLE_LINENUMBER
,'fore:#000000,back:#99A9C2')
519 self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACELIGHT
,'fore:#00009D,back:#FFFF00')
521 self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACEBAD
,'fore:#00009D,back:#FF0000')
523 self
.StyleSetSpec(wx
.stc
.STC_STYLE_INDENTGUIDE
, "fore:#CDCDCD")
526 self
.StyleSetSpec(wx
.stc
.STC_P_DEFAULT
, 'fore:#000000')
528 self
.StyleSetSpec(wx
.stc
.STC_P_COMMENTLINE
, 'fore:#008000,back:#F0FFF0')
529 self
.StyleSetSpec(wx
.stc
.STC_P_COMMENTBLOCK
, 'fore:#008000,back:#F0FFF0')
531 self
.StyleSetSpec(wx
.stc
.STC_P_NUMBER
, 'fore:#008080')
532 # Strings and characters
533 self
.StyleSetSpec(wx
.stc
.STC_P_STRING
, 'fore:#800080')
534 self
.StyleSetSpec(wx
.stc
.STC_P_CHARACTER
, 'fore:#800080')
536 self
.StyleSetSpec(wx
.stc
.STC_P_WORD
, 'fore:#000080,bold')
538 self
.StyleSetSpec(wx
.stc
.STC_P_TRIPLE
, 'fore:#800080,back:#FFFFEA')
539 self
.StyleSetSpec(wx
.stc
.STC_P_TRIPLEDOUBLE
, 'fore:#800080,back:#FFFFEA')
541 self
.StyleSetSpec(wx
.stc
.STC_P_CLASSNAME
, 'fore:#0000FF,bold')
543 self
.StyleSetSpec(wx
.stc
.STC_P_DEFNAME
, 'fore:#008080,bold')
545 self
.StyleSetSpec(wx
.stc
.STC_P_OPERATOR
, 'fore:#800000,bold')
546 # Identifiers. I leave this as not bold because everything seems
547 # to be an identifier if it doesn't match the above criterae
548 self
.StyleSetSpec(wx
.stc
.STC_P_IDENTIFIER
, 'fore:#000000')
551 self
.SetCaretForeground("BLUE")
552 # Selection background
553 self
.SetSelBackground(1, '#66CCFF')
555 self
.SetSelBackground(True, wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_HIGHLIGHT
))
556 self
.SetSelForeground(True, wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_HIGHLIGHTTEXT
))
558 def RegisterModifiedEvent(self
, eventHandler
):
559 self
.Bind(wx
.stc
.EVT_STC_CHANGE
, eventHandler
)
563 class DemoCodeEditor(wx
.TextCtrl
):
564 def __init__(self
, parent
):
565 wx
.TextCtrl
.__init
__(self
, parent
, -1, style
=
566 wx
.TE_MULTILINE | wx
.HSCROLL | wx
.TE_RICH2 | wx
.TE_NOHIDESEL
)
568 def RegisterModifiedEvent(self
, eventHandler
):
569 self
.Bind(wx
.EVT_TEXT
, eventHandler
)
571 def SetReadOnly(self
, flag
):
572 self
.SetEditable(not flag
)
573 # NOTE: STC already has this method
576 return self
.GetValue()
578 def GetPositionFromLine(self
, line
):
579 return self
.XYToPosition(0,line
)
581 def GotoLine(self
, line
):
582 pos
= self
.GetPositionFromLine(line
)
583 self
.SetInsertionPoint(pos
)
584 self
.ShowPosition(pos
)
586 def SelectLine(self
, line
):
587 start
= self
.GetPositionFromLine(line
)
588 end
= start
+ self
.GetLineLength(line
)
589 self
.SetSelection(start
, end
)
592 #---------------------------------------------------------------------------
593 # Constants for module versions
597 modDefault
= modOriginal
599 #---------------------------------------------------------------------------
601 class DemoCodePanel(wx
.Panel
):
602 """Panel for the 'Demo Code' tab"""
603 def __init__(self
, parent
, mainFrame
):
604 wx
.Panel
.__init
__(self
, parent
, size
=(1,1))
605 if 'wxMSW' in wx
.PlatformInfo
:
607 self
.mainFrame
= mainFrame
608 self
.editor
= DemoCodeEditor(self
)
609 self
.editor
.RegisterModifiedEvent(self
.OnCodeModified
)
611 self
.btnSave
= wx
.Button(self
, -1, "Save Changes")
612 self
.btnRestore
= wx
.Button(self
, -1, "Delete Modified")
613 self
.btnSave
.Enable(False)
614 self
.btnSave
.Bind(wx
.EVT_BUTTON
, self
.OnSave
)
615 self
.btnRestore
.Bind(wx
.EVT_BUTTON
, self
.OnRestore
)
617 self
.radioButtons
= { modOriginal
: wx
.RadioButton(self
, -1, "Original", style
= wx
.RB_GROUP
),
618 modModified
: wx
.RadioButton(self
, -1, "Modified") }
620 self
.controlBox
= wx
.BoxSizer(wx
.HORIZONTAL
)
621 self
.controlBox
.Add(wx
.StaticText(self
, -1, "Active Version:"), 0,
622 wx
.RIGHT | wx
.LEFT | wx
.ALIGN_CENTER_VERTICAL
, 5)
623 for modID
, radioButton
in self
.radioButtons
.items():
624 self
.controlBox
.Add(radioButton
, 0, wx
.EXPAND | wx
.RIGHT
, 5)
625 radioButton
.modID
= modID
# makes it easier for the event handler
626 radioButton
.Bind(wx
.EVT_RADIOBUTTON
, self
.OnRadioButton
)
628 self
.controlBox
.Add(self
.btnSave
, 0, wx
.RIGHT
, 5)
629 self
.controlBox
.Add(self
.btnRestore
, 0)
631 self
.box
= wx
.BoxSizer(wx
.VERTICAL
)
632 self
.box
.Add(self
.controlBox
, 0, wx
.EXPAND
)
633 self
.box
.Add(wx
.StaticLine(self
), 0, wx
.EXPAND
)
634 self
.box
.Add(self
.editor
, 1, wx
.EXPAND
)
637 self
.SetSizer(self
.box
)
640 # Loads a demo from a DemoModules object
641 def LoadDemo(self
, demoModules
):
642 self
.demoModules
= demoModules
643 if (modDefault
== modModified
) and demoModules
.Exists(modModified
):
644 demoModules
.SetActive(modModified
)
646 demoModules
.SetActive(modOriginal
)
647 self
.radioButtons
[demoModules
.GetActiveID()].Enable(True)
648 self
.ActiveModuleChanged()
651 def ActiveModuleChanged(self
):
652 self
.LoadDemoSource(self
.demoModules
.GetSource())
653 self
.UpdateControlState()
657 def LoadDemoSource(self
, source
):
659 self
.editor
.SetValue(source
)
661 self
.btnSave
.Enable(False)
664 def JumpToLine(self
, line
, highlight
=False):
665 self
.editor
.GotoLine(line
)
666 self
.editor
.SetFocus()
668 self
.editor
.SelectLine(line
)
671 def UpdateControlState(self
):
672 active
= self
.demoModules
.GetActiveID()
673 # Update the radio/restore buttons
674 for moduleID
in self
.radioButtons
:
675 btn
= self
.radioButtons
[moduleID
]
676 if moduleID
== active
:
681 if self
.demoModules
.Exists(moduleID
):
683 if moduleID
== modModified
:
684 self
.btnRestore
.Enable(True)
687 if moduleID
== modModified
:
688 self
.btnRestore
.Enable(False)
691 def OnRadioButton(self
, event
):
692 radioSelected
= event
.GetEventObject()
693 modSelected
= radioSelected
.modID
694 if modSelected
!= self
.demoModules
.GetActiveID():
695 busy
= wx
.BusyInfo("Reloading demo module...")
696 self
.demoModules
.SetActive(modSelected
)
697 self
.ActiveModuleChanged()
700 def ReloadDemo(self
):
701 if self
.demoModules
.name
!= __name__
:
702 self
.mainFrame
.RunModule()
705 def OnCodeModified(self
, event
):
706 self
.btnSave
.Enable(self
.editor
.IsModified())
709 def OnSave(self
, event
):
710 if self
.demoModules
.Exists(modModified
):
711 if self
.demoModules
.GetActiveID() == modOriginal
:
712 overwriteMsg
= "You are about to overwrite an already existing modified copy\n" + \
713 "Do you want to continue?"
714 dlg
= wx
.MessageDialog(self
, overwriteMsg
, "wxPython Demo",
715 wx
.YES_NO | wx
.NO_DEFAULT| wx
.ICON_EXCLAMATION
)
716 result
= dlg
.ShowModal()
717 if result
== wx
.ID_NO
:
721 self
.demoModules
.SetActive(modModified
)
722 modifiedFilename
= GetModifiedFilename(self
.demoModules
.name
)
724 # Create the demo directory if one doesn't already exist
725 if not os
.path
.exists(GetModifiedDirectory()):
727 os
.makedirs(GetModifiedDirectory())
728 if not os
.path
.exists(GetModifiedDirectory()):
729 wx
.LogMessage("BUG: Created demo directory but it still doesn't exist")
732 wx
.LogMessage("Error creating demo directory: %s" % GetModifiedDirectory())
735 wx
.LogMessage("Created directory for modified demos: %s" % GetModifiedDirectory())
738 f
= open(modifiedFilename
, "wt")
739 source
= self
.editor
.GetText()
745 busy
= wx
.BusyInfo("Reloading demo module...")
746 self
.demoModules
.LoadFromFile(modModified
, modifiedFilename
)
747 self
.ActiveModuleChanged()
750 def OnRestore(self
, event
): # Handles the "Delete Modified" button
751 modifiedFilename
= GetModifiedFilename(self
.demoModules
.name
)
752 self
.demoModules
.Delete(modModified
)
753 os
.unlink(modifiedFilename
) # Delete the modified copy
754 busy
= wx
.BusyInfo("Reloading demo module...")
755 self
.ActiveModuleChanged()
758 #---------------------------------------------------------------------------
761 """Convert paths to the platform-specific separator"""
762 str = apply(os
.path
.join
, tuple(path
.split('/')))
763 # HACK: on Linux, a leading / gets lost...
764 if path
.startswith('/'):
769 def GetModifiedDirectory():
771 Returns the directory where modified versions of the demo files
774 return opj(wx
.GetHomeDir() + "/.wxPyDemo/modified/")
777 def GetModifiedFilename(name
):
779 Returns the filename of the modified version of the specified demo
781 if not name
.endswith(".py"):
783 return GetModifiedDirectory() + name
786 def GetOriginalFilename(name
):
788 Returns the filename of the original version of the specified demo
790 if not name
.endswith(".py"):
795 def DoesModifiedExist(name
):
796 """Returns whether the specified demo has a modified copy"""
797 if os
.path
.exists(GetModifiedFilename(name
)):
803 #---------------------------------------------------------------------------
805 class ModuleDictWrapper
:
806 """Emulates a module with a dynamically compiled __dict__"""
807 def __init__(self
, dict):
810 def __getattr__(self
, name
):
811 if name
in self
.dict:
812 return self
.dict[name
]
818 Dynamically manages the original/modified versions of a demo
821 def __init__(self
, name
):
825 # (dict , source , filename , description , error information )
826 # ( 0 , 1 , 2 , 3 , 4 )
827 self
.modules
= [[None, "" , "" , "<original>" , None],
828 [None, "" , "" , "<modified>" , None]]
830 # load original module
831 self
.LoadFromFile(modOriginal
, GetOriginalFilename(name
))
832 self
.SetActive(modOriginal
)
834 # load modified module (if one exists)
835 if DoesModifiedExist(name
):
836 self
.LoadFromFile(modModified
, GetModifiedFilename(name
))
839 def LoadFromFile(self
, modID
, filename
):
840 self
.modules
[modID
][2] = filename
841 file = open(filename
, "rt")
842 self
.LoadFromSource(modID
, file.read())
846 def LoadFromSource(self
, modID
, source
):
847 self
.modules
[modID
][1] = source
851 def LoadDict(self
, modID
):
852 if self
.name
!= __name__
:
853 source
= self
.modules
[modID
][1]
854 #description = self.modules[modID][3]
855 description
= self
.modules
[modID
][2]
858 self
.modules
[modID
][0] = {}
859 code
= compile(source
, description
, "exec")
860 exec code
in self
.modules
[modID
][0]
862 self
.modules
[modID
][4] = DemoError(sys
.exc_info())
863 self
.modules
[modID
][0] = None
865 self
.modules
[modID
][4] = None
868 def SetActive(self
, modID
):
869 if modID
!= modOriginal
and modID
!= modModified
:
872 self
.modActive
= modID
876 dict = self
.modules
[self
.modActive
][0]
880 return ModuleDictWrapper(dict)
883 def GetActiveID(self
):
884 return self
.modActive
887 def GetSource(self
, modID
= None):
889 modID
= self
.modActive
890 return self
.modules
[modID
][1]
893 def GetFilename(self
, modID
= None):
895 modID
= self
.modActive
896 return self
.modules
[self
.modActive
][2]
899 def GetErrorInfo(self
, modID
= None):
901 modID
= self
.modActive
902 return self
.modules
[self
.modActive
][4]
905 def Exists(self
, modID
):
906 return self
.modules
[modID
][1] != ""
909 def UpdateFile(self
, modID
= None):
910 """Updates the file from which a module was loaded
911 with (possibly updated) source"""
913 modID
= self
.modActive
915 source
= self
.modules
[modID
][1]
916 filename
= self
.modules
[modID
][2]
919 file = open(filename
, "wt")
925 def Delete(self
, modID
):
926 if self
.modActive
== modID
:
929 self
.modules
[modID
][0] = None
930 self
.modules
[modID
][1] = ""
931 self
.modules
[modID
][2] = ""
934 #---------------------------------------------------------------------------
937 """Wraps and stores information about the current exception"""
938 def __init__(self
, exc_info
):
941 excType
, excValue
= exc_info
[:2]
942 # traceback list entries: (filename, line number, function name, text)
943 self
.traceback
= traceback
.extract_tb(exc_info
[2])
945 # --Based on traceback.py::format_exception_only()--
946 if type(excType
) == types
.ClassType
:
947 self
.exception_type
= excType
.__name
__
949 self
.exception_type
= excType
951 # If it's a syntax error, extra information needs
952 # to be added to the traceback
953 if excType
is SyntaxError:
955 msg
, (filename
, lineno
, self
.offset
, line
) = excValue
960 filename
= "<string>"
962 self
.traceback
.append( (filename
, lineno
, "", line
) )
965 self
.exception_details
= str(excValue
)
967 self
.exception_details
= "<unprintable %s object>" & type(excValue
).__name
__
974 Details : %s" % ( str(self
.exception_type
), str(self
.traceback
), self
.exception_details
)
977 #---------------------------------------------------------------------------
979 class DemoErrorPanel(wx
.Panel
):
980 """Panel put into the demo tab when the demo fails to run due to errors"""
982 def __init__(self
, parent
, codePanel
, demoError
, log
):
983 wx
.Panel
.__init
__(self
, parent
, -1)#, style=wx.NO_FULL_REPAINT_ON_RESIZE)
984 self
.codePanel
= codePanel
988 self
.box
= wx
.BoxSizer(wx
.VERTICAL
)
991 self
.box
.Add(wx
.StaticText(self
, -1, "An error has occurred while trying to run the demo")
992 , 0, wx
.ALIGN_CENTER | wx
.TOP
, 10)
994 # Exception Information
995 boxInfo
= wx
.StaticBox(self
, -1, "Exception Info" )
996 boxInfoSizer
= wx
.StaticBoxSizer(boxInfo
, wx
.VERTICAL
) # Used to center the grid within the box
997 boxInfoGrid
= wx
.FlexGridSizer(0, 2, 0, 0)
998 textFlags
= wx
.ALIGN_RIGHT | wx
.LEFT | wx
.RIGHT | wx
.TOP
999 boxInfoGrid
.Add(wx
.StaticText(self
, -1, "Type: "), 0, textFlags
, 5 )
1000 boxInfoGrid
.Add(wx
.StaticText(self
, -1, demoError
.exception_type
) , 0, textFlags
, 5 )
1001 boxInfoGrid
.Add(wx
.StaticText(self
, -1, "Details: ") , 0, textFlags
, 5 )
1002 boxInfoGrid
.Add(wx
.StaticText(self
, -1, demoError
.exception_details
) , 0, textFlags
, 5 )
1003 boxInfoSizer
.Add(boxInfoGrid
, 0, wx
.ALIGN_CENTRE | wx
.ALL
, 5 )
1004 self
.box
.Add(boxInfoSizer
, 0, wx
.ALIGN_CENTER | wx
.ALL
, 5)
1006 # Set up the traceback list
1007 # This one automatically resizes last column to take up remaining space
1008 from ListCtrl
import TestListCtrl
1009 self
.list = TestListCtrl(self
, -1, style
=wx
.LC_REPORT | wx
.SUNKEN_BORDER
)
1010 self
.list.Bind(wx
.EVT_LEFT_DCLICK
, self
.OnDoubleClick
)
1011 self
.list.Bind(wx
.EVT_LIST_ITEM_SELECTED
, self
.OnItemSelected
)
1012 self
.list.InsertColumn(0, "Filename")
1013 self
.list.InsertColumn(1, "Line", wx
.LIST_FORMAT_RIGHT
)
1014 self
.list.InsertColumn(2, "Function")
1015 self
.list.InsertColumn(3, "Code")
1016 self
.InsertTraceback(self
.list, demoError
.traceback
)
1017 self
.list.SetColumnWidth(0, wx
.LIST_AUTOSIZE
)
1018 self
.list.SetColumnWidth(2, wx
.LIST_AUTOSIZE
)
1019 self
.box
.Add(wx
.StaticText(self
, -1, "Traceback:")
1020 , 0, wx
.ALIGN_CENTER | wx
.TOP
, 5)
1021 self
.box
.Add(self
.list, 1, wx
.GROW | wx
.ALIGN_CENTER | wx
.ALL
, 5)
1022 self
.box
.Add(wx
.StaticText(self
, -1, "Entries from the demo module are shown in blue\n"
1023 + "Double-click on them to go to the offending line")
1024 , 0, wx
.ALIGN_CENTER | wx
.BOTTOM
, 5)
1027 self
.SetSizer(self
.box
)
1030 def InsertTraceback(self
, list, traceback
):
1031 #Add the traceback data
1032 for x
in range(len(traceback
)):
1034 list.InsertStringItem(x
, os
.path
.basename(data
[0])) # Filename
1035 list.SetStringItem(x
, 1, str(data
[1])) # Line
1036 list.SetStringItem(x
, 2, str(data
[2])) # Function
1037 list.SetStringItem(x
, 3, str(data
[3])) # Code
1039 # Check whether this entry is from the demo module
1040 if data
[0] == "<original>" or data
[0] == "<modified>": # FIXME: make more generalised
1041 self
.list.SetItemData(x
, int(data
[1])) # Store line number for easy access
1042 # Give it a blue colour
1043 item
= self
.list.GetItem(x
)
1044 item
.SetTextColour(wx
.BLUE
)
1045 self
.list.SetItem(item
)
1047 self
.list.SetItemData(x
, -1) # Editor can't jump into this one's code
1050 def OnItemSelected(self
, event
):
1051 # This occurs before OnDoubleClick and can be used to set the
1052 # currentItem. OnDoubleClick doesn't get a wxListEvent....
1053 self
.currentItem
= event
.m_itemIndex
1057 def OnDoubleClick(self
, event
):
1058 # If double-clicking on a demo's entry, jump to the line number
1059 line
= self
.list.GetItemData(self
.currentItem
)
1061 self
.nb
.SetSelection(1) # Switch to the code viewer tab
1062 wx
.CallAfter(self
.codePanel
.JumpToLine
, line
-1, True)
1066 #---------------------------------------------------------------------------
1068 class DemoTaskBarIcon(wx
.TaskBarIcon
):
1069 TBMENU_RESTORE
= wx
.NewId()
1070 TBMENU_CLOSE
= wx
.NewId()
1071 TBMENU_CHANGE
= wx
.NewId()
1072 TBMENU_REMOVE
= wx
.NewId()
1074 def __init__(self
, frame
):
1075 wx
.TaskBarIcon
.__init
__(self
)
1079 icon
= self
.MakeIcon(images
.getWXPdemoImage())
1080 self
.SetIcon(icon
, "wxPython Demo")
1084 self
.Bind(wx
.EVT_TASKBAR_LEFT_DCLICK
, self
.OnTaskBarActivate
)
1085 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarActivate
, id=self
.TBMENU_RESTORE
)
1086 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarClose
, id=self
.TBMENU_CLOSE
)
1087 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarChange
, id=self
.TBMENU_CHANGE
)
1088 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarRemove
, id=self
.TBMENU_REMOVE
)
1091 def CreatePopupMenu(self
):
1093 This method is called by the base class when it needs to popup
1094 the menu for the default EVT_RIGHT_DOWN event. Just create
1095 the menu how you want it and return it from this function,
1096 the base class takes care of the rest.
1099 menu
.Append(self
.TBMENU_RESTORE
, "Restore wxPython Demo")
1100 menu
.Append(self
.TBMENU_CLOSE
, "Close wxPython Demo")
1101 menu
.AppendSeparator()
1102 menu
.Append(self
.TBMENU_CHANGE
, "Change the TB Icon")
1103 menu
.Append(self
.TBMENU_REMOVE
, "Remove the TB Icon")
1107 def MakeIcon(self
, img
):
1109 The various platforms have different requirements for the
1112 if "wxMSW" in wx
.PlatformInfo
:
1113 img
= img
.Scale(16, 16)
1114 elif "wxGTK" in wx
.PlatformInfo
:
1115 img
= img
.Scale(22, 22)
1116 # wxMac can be any size upto 128x128, so leave the source img alone....
1117 icon
= wx
.IconFromBitmap(img
.ConvertToBitmap() )
1121 def OnTaskBarActivate(self
, evt
):
1122 if self
.frame
.IsIconized():
1123 self
.frame
.Iconize(False)
1124 if not self
.frame
.IsShown():
1125 self
.frame
.Show(True)
1129 def OnTaskBarClose(self
, evt
):
1133 def OnTaskBarChange(self
, evt
):
1134 names
= [ "WXPdemo", "Mondrian", "Pencil", "Carrot" ]
1135 name
= names
[self
.imgidx
]
1137 getFunc
= getattr(images
, "get%sImage" % name
)
1139 if self
.imgidx
>= len(names
):
1142 icon
= self
.MakeIcon(getFunc())
1143 self
.SetIcon(icon
, "This is a new icon: " + name
)
1146 def OnTaskBarRemove(self
, evt
):
1150 #---------------------------------------------------------------------------
1151 class wxPythonDemo(wx
.Frame
):
1152 overviewText
= "wxPython Overview"
1154 def __init__(self
, parent
, title
):
1155 wx
.Frame
.__init
__(self
, parent
, -1, title
, size
= (950, 720),
1156 style
=wx
.DEFAULT_FRAME_STYLE | wx
.NO_FULL_REPAINT_ON_RESIZE
)
1158 self
.SetMinSize((640,480))
1161 self
.cwd
= os
.getcwd()
1162 self
.curOverview
= ""
1163 self
.demoPage
= None
1164 self
.codePage
= None
1166 self
.firstTime
= True
1169 icon
= images
.getWXPdemoIcon()
1173 self
.tbicon
= DemoTaskBarIcon(self
)
1177 wx
.CallAfter(self
.ShowTip
)
1179 self
.otherWin
= None
1180 self
.Bind(wx
.EVT_IDLE
, self
.OnIdle
)
1181 self
.Bind(wx
.EVT_CLOSE
, self
.OnCloseWindow
)
1182 self
.Bind(wx
.EVT_ICONIZE
, self
.OnIconfiy
)
1183 self
.Bind(wx
.EVT_MAXIMIZE
, self
.OnMaximize
)
1185 self
.Centre(wx
.BOTH
)
1186 self
.CreateStatusBar(1, wx
.ST_SIZEGRIP
)
1188 splitter
= wx
.SplitterWindow(self
, -1, style
=wx
.CLIP_CHILDREN | wx
.SP_LIVE_UPDATE | wx
.SP_3D
)
1189 splitter2
= wx
.SplitterWindow(splitter
, -1, style
=wx
.CLIP_CHILDREN | wx
.SP_LIVE_UPDATE | wx
.SP_3D
)
1191 def EmptyHandler(evt
): pass
1192 #splitter.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
1193 #splitter2.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
1195 # Prevent TreeCtrl from displaying all items after destruction when True
1199 self
.nb
= wx
.Notebook(splitter2
, -1, style
=wx
.CLIP_CHILDREN
)
1202 self
.mainmenu
= wx
.MenuBar()
1204 item
= menu
.Append(-1, '&Redirect Output',
1205 'Redirect print statements to a window',
1207 self
.Bind(wx
.EVT_MENU
, self
.OnToggleRedirect
, item
)
1209 item
= menu
.Append(-1, 'E&xit\tAlt-X', 'Get the heck outta here!')
1210 self
.Bind(wx
.EVT_MENU
, self
.OnFileExit
, item
)
1211 wx
.App
.SetMacExitMenuItemId(item
.GetId())
1212 self
.mainmenu
.Append(menu
, '&File')
1216 for item
in _treeList
:
1218 for childItem
in item
[1]:
1219 mi
= submenu
.Append(-1, childItem
)
1220 self
.Bind(wx
.EVT_MENU
, self
.OnDemoMenu
, mi
)
1221 menu
.AppendMenu(wx
.NewId(), item
[0], submenu
)
1222 self
.mainmenu
.Append(menu
, '&Demo')
1227 findItem
= menu
.Append(-1, '&Find\tCtrl-F', 'Find in the Demo Code')
1228 findnextItem
= menu
.Append(-1, 'Find &Next\tF3', 'Find Next')
1229 menu
.AppendSeparator()
1231 shellItem
= menu
.Append(-1, 'Open Py&Shell Window\tF5',
1232 'An interactive interpreter window with the demo app and frame objects in the namesapce')
1233 menu
.AppendSeparator()
1234 helpItem
= menu
.Append(-1, '&About wxPython Demo', 'wxPython RULES!!!')
1235 wx
.App
.SetMacAboutMenuItemId(helpItem
.GetId())
1237 self
.Bind(wx
.EVT_MENU
, self
.OnOpenShellWindow
, shellItem
)
1238 self
.Bind(wx
.EVT_MENU
, self
.OnHelpAbout
, helpItem
)
1239 self
.Bind(wx
.EVT_MENU
, self
.OnHelpFind
, findItem
)
1240 self
.Bind(wx
.EVT_MENU
, self
.OnFindNext
, findnextItem
)
1241 self
.Bind(wx
.EVT_FIND
, self
.OnFind
)
1242 self
.Bind(wx
.EVT_FIND_NEXT
, self
.OnFind
)
1243 self
.Bind(wx
.EVT_FIND_CLOSE
, self
.OnFindClose
)
1244 self
.Bind(wx
.EVT_UPDATE_UI
, self
.OnUpdateFindItems
, findItem
)
1245 self
.Bind(wx
.EVT_UPDATE_UI
, self
.OnUpdateFindItems
, findnextItem
)
1246 self
.mainmenu
.Append(menu
, '&Help')
1247 self
.SetMenuBar(self
.mainmenu
)
1249 self
.finddata
= wx
.FindReplaceData()
1250 self
.finddata
.SetFlags(wx
.FR_DOWN
)
1253 # This is another way to set Accelerators, in addition to
1254 # using the '\t<key>' syntax in the menu items.
1255 aTable
= wx
.AcceleratorTable([(wx
.ACCEL_ALT
, ord('X'), exitID
),
1256 (wx
.ACCEL_CTRL
, ord('H'), helpID
),
1257 (wx
.ACCEL_CTRL
, ord('F'), findID
),
1258 (wx
.ACCEL_NORMAL
, WXK_F3
, findnextID
)
1260 self
.SetAcceleratorTable(aTable
)
1265 leftPanel
= wx
.Panel(splitter
)
1267 self
.filter = wx
.TextCtrl(leftPanel
)
1268 self
.filter.Bind(wx
.EVT_TEXT
, self
.RecreateTree
)
1271 self
.tree
= wx
.TreeCtrl(leftPanel
, tID
, style
=
1272 wx
.TR_DEFAULT_STYLE
#| wx.TR_HAS_VARIABLE_ROW_HEIGHT
1275 self
.root
= self
.tree
.AddRoot("wxPython Overview")
1277 self
.tree
.Bind(wx
.EVT_TREE_ITEM_EXPANDED
, self
.OnItemExpanded
, id=tID
)
1278 self
.tree
.Bind(wx
.EVT_TREE_ITEM_COLLAPSED
, self
.OnItemCollapsed
, id=tID
)
1279 self
.tree
.Bind(wx
.EVT_TREE_SEL_CHANGED
, self
.OnSelChanged
, id=tID
)
1280 self
.tree
.Bind(wx
.EVT_LEFT_DOWN
, self
.OnTreeLeftDown
)
1282 # Set up a wx.html.HtmlWindow on the Overview Notebook page
1283 # we put it in a panel first because there seems to be a
1284 # refresh bug of some sort (wxGTK) when it is directly in
1287 self
.ovr
= wx
.html
.HtmlWindow(self
.nb
, -1, size
=(400, 400))
1288 self
.nb
.AddPage(self
.ovr
, self
.overviewText
)
1290 else: # hopefully I can remove this hacky code soon, see SF bug #216861
1291 panel
= wx
.Panel(self
.nb
, -1, style
=wx
.CLIP_CHILDREN
)
1292 self
.ovr
= wx
.html
.HtmlWindow(panel
, -1, size
=(400, 400))
1293 self
.nb
.AddPage(panel
, self
.overviewText
)
1295 def OnOvrSize(evt
, ovr
=self
.ovr
):
1296 ovr
.SetSize(evt
.GetSize())
1297 panel
.Bind(wx
.EVT_SIZE
, OnOvrSize
)
1298 panel
.Bind(wx
.EVT_ERASE_BACKGROUND
, EmptyHandler
)
1300 if "gtk2" in wx
.PlatformInfo
:
1301 self
.ovr
.SetStandardFonts()
1302 self
.SetOverview(self
.overviewText
, mainOverview
)
1305 # Set up a log window
1306 self
.log
= wx
.TextCtrl(splitter2
, -1,
1307 style
= wx
.TE_MULTILINE|wx
.TE_READONLY|wx
.HSCROLL
)
1308 if wx
.Platform
== "__WXMAC__":
1309 self
.log
.MacCheckSpelling(False)
1311 # Set the wxWindows log target to be this textctrl
1312 #wx.Log_SetActiveTarget(wx.LogTextCtrl(self.log))
1314 # But instead of the above we want to show how to use our own wx.Log class
1315 wx
.Log_SetActiveTarget(MyLog(self
.log
))
1317 # for serious debugging
1318 #wx.Log_SetActiveTarget(wx.LogStderr())
1319 #wx.Log_SetTraceMask(wx.TraceMessages)
1322 self
.Bind(wx
.EVT_ACTIVATE
, self
.OnActivate
)
1323 wx
.GetApp().Bind(wx
.EVT_ACTIVATE_APP
, self
.OnAppActivate
)
1325 # add the windows to the splitter and split it.
1326 splitter2
.SplitHorizontally(self
.nb
, self
.log
, -160)
1327 leftBox
= wx
.BoxSizer(wx
.VERTICAL
)
1328 leftBox
.Add(self
.tree
, 1, wx
.EXPAND
)
1329 leftBox
.Add(wx
.StaticText(leftPanel
, label
= "Filter Demos:"), 0, wx
.TOP|wx
.LEFT
, 5)
1330 leftBox
.Add(self
.filter, 0, wx
.EXPAND|wx
.ALL
, 5)
1331 leftPanel
.SetSizer(leftBox
)
1332 splitter
.SplitVertically(leftPanel
, splitter2
, 220)
1334 splitter
.SetMinimumPaneSize(120)
1335 splitter2
.SetMinimumPaneSize(60)
1337 # Make the splitter on the right expand the top window when resized
1338 def SplitterOnSize(evt
):
1339 splitter
= evt
.GetEventObject()
1340 sz
= splitter
.GetSize()
1341 splitter
.SetSashPosition(sz
.height
- 160, False)
1344 splitter2
.Bind(wx
.EVT_SIZE
, SplitterOnSize
)
1346 # select initial items
1347 self
.nb
.SetSelection(0)
1348 self
.tree
.SelectItem(self
.root
)
1350 # Load 'Main' module
1351 self
.LoadDemo(self
.overviewText
)
1354 # select some other initial module?
1355 if len(sys
.argv
) > 1:
1357 if arg
.endswith('.py'):
1359 selectedDemo
= self
.treeMap
.get(arg
, None)
1361 self
.tree
.SelectItem(selectedDemo
)
1362 self
.tree
.EnsureVisible(selectedDemo
)
1365 #---------------------------------------------
1367 def RecreateTree(self
, evt
=None):
1368 self
.tree
.DeleteAllItems()
1369 self
.root
= self
.tree
.AddRoot("wxPython Overview")
1371 filter = self
.filter.GetValue()
1372 for category
, items
in _treeList
:
1374 items
= [item
for item
in items
if filter.lower() in item
.lower()]
1376 child
= self
.tree
.AppendItem(self
.root
, category
)
1377 if not firstChild
: firstChild
= child
1378 for childItem
in items
:
1379 theDemo
= self
.tree
.AppendItem(child
, childItem
)
1380 self
.treeMap
[childItem
] = theDemo
1382 self
.tree
.Expand(self
.root
)
1384 self
.tree
.Expand(firstChild
)
1387 def WriteText(self
, text
):
1388 if text
[-1:] == '\n':
1392 def write(self
, txt
):
1395 #---------------------------------------------
1396 def OnItemExpanded(self
, event
):
1397 item
= event
.GetItem()
1398 wx
.LogMessage("OnItemExpanded: %s" % self
.tree
.GetItemText(item
))
1401 #---------------------------------------------
1402 def OnItemCollapsed(self
, event
):
1403 item
= event
.GetItem()
1404 wx
.LogMessage("OnItemCollapsed: %s" % self
.tree
.GetItemText(item
))
1407 #---------------------------------------------
1408 def OnTreeLeftDown(self
, event
):
1409 # reset the overview text if the tree item is clicked on again
1410 pt
= event
.GetPosition();
1411 item
, flags
= self
.tree
.HitTest(pt
)
1412 if item
== self
.tree
.GetSelection():
1413 self
.SetOverview(self
.tree
.GetItemText(item
)+" Overview", self
.curOverview
)
1416 #---------------------------------------------
1417 def OnSelChanged(self
, event
):
1418 if self
.dying
or not self
.loaded
:
1421 item
= event
.GetItem()
1422 itemText
= self
.tree
.GetItemText(item
)
1423 self
.LoadDemo(itemText
)
1425 #---------------------------------------------
1426 def LoadDemo(self
, demoName
):
1428 wx
.BeginBusyCursor()
1431 self
.ShutdownDemoModule()
1433 if demoName
== self
.overviewText
:
1434 # User selected the "wxPython Overview" node
1436 # Changing the main window at runtime not yet supported...
1437 self
.demoModules
= DemoModules(__name__
)
1438 self
.SetOverview(self
.overviewText
, mainOverview
)
1439 self
.LoadDemoSource()
1440 self
.UpdateNotebook(0)
1442 if os
.path
.exists(GetOriginalFilename(demoName
)):
1443 wx
.LogMessage("Loading demo %s.py..." % demoName
)
1444 self
.demoModules
= DemoModules(demoName
)
1445 self
.LoadDemoSource()
1448 self
.SetOverview("wxPython", mainOverview
)
1449 self
.codePage
= None
1450 self
.UpdateNotebook(0)
1454 #---------------------------------------------
1455 def LoadDemoSource(self
):
1456 self
.codePage
= None
1457 self
.codePage
= DemoCodePanel(self
.nb
, self
)
1458 self
.codePage
.LoadDemo(self
.demoModules
)
1460 #---------------------------------------------
1461 def RunModule(self
):
1462 """Runs the active module"""
1464 module
= self
.demoModules
.GetActive()
1465 self
.ShutdownDemoModule()
1468 # o The RunTest() for all samples must now return a window that can
1469 # be palced in a tab in the main notebook.
1470 # o If an error occurs (or has occurred before) an error tab is created.
1472 if module
is not None:
1473 wx
.LogMessage("Running demo module...")
1474 if hasattr(module
, "overview"):
1475 overviewText
= module
.overview
1478 self
.demoPage
= module
.runTest(self
, self
.nb
, self
)
1480 self
.demoPage
= DemoErrorPanel(self
.nb
, self
.codePage
,
1481 DemoError(sys
.exc_info()), self
)
1483 assert self
.demoPage
is not None, "runTest must return a window!"
1486 # There was a previous error in compiling or exec-ing
1487 self
.demoPage
= DemoErrorPanel(self
.nb
, self
.codePage
,
1488 self
.demoModules
.GetErrorInfo(), self
)
1490 self
.SetOverview(self
.demoModules
.name
+ " Overview", overviewText
)
1493 # cahnge to the demo page the first time a module is run
1494 self
.UpdateNotebook(2)
1495 self
.firstTime
= False
1497 # otherwise just stay on the same tab in case the user has changed to another one
1498 self
.UpdateNotebook()
1500 #---------------------------------------------
1501 def ShutdownDemoModule(self
):
1503 # inform the window that it's time to quit if it cares
1504 if hasattr(self
.demoPage
, "ShutdownDemo"):
1505 self
.demoPage
.ShutdownDemo()
1506 wx
.YieldIfNeeded() # in case the page has pending events
1507 self
.demoPage
= None
1509 #---------------------------------------------
1510 def UpdateNotebook(self
, select
= -1):
1514 def UpdatePage(page
, pageText
):
1517 for i
in range(nb
.GetPageCount()):
1518 if nb
.GetPageText(i
) == pageText
:
1526 nb
.AddPage(page
, pageText
)
1527 if debug
: wx
.LogMessage("DBG: ADDED %s" % pageText
)
1529 if nb
.GetPage(pagePos
) != page
:
1530 # Reload an existing page
1532 nb
.DeletePage(pagePos
)
1533 nb
.InsertPage(pagePos
, page
, pageText
)
1535 if debug
: wx
.LogMessage("DBG: RELOADED %s" % pageText
)
1537 # Excellent! No redraw/flicker
1538 if debug
: wx
.LogMessage("DBG: SAVED from reloading %s" % pageText
)
1541 nb
.DeletePage(pagePos
)
1542 if debug
: wx
.LogMessage("DBG: DELETED %s" % pageText
)
1544 if debug
: wx
.LogMessage("DBG: STILL GONE - %s" % pageText
)
1547 select
= nb
.GetSelection()
1549 UpdatePage(self
.codePage
, "Demo Code")
1550 UpdatePage(self
.demoPage
, "Demo")
1552 if select
>= 0 and select
< nb
.GetPageCount():
1553 nb
.SetSelection(select
)
1555 #---------------------------------------------
1556 def SetOverview(self
, name
, text
):
1557 self
.curOverview
= text
1559 if lead
!= '<html>' and lead
!= '<HTML>':
1560 text
= '<br>'.join(text
.split('\n'))
1562 text
= text
.decode('iso8859_1')
1563 self
.ovr
.SetPage(text
)
1564 self
.nb
.SetPageText(0, name
)
1566 #---------------------------------------------
1568 def OnFileExit(self
, *event
):
1571 def OnToggleRedirect(self
, event
):
1575 print "Print statements and other standard output will now be directed to this window."
1578 print "Print statements and other standard output will now be sent to the usual location."
1580 def OnHelpAbout(self
, event
):
1581 from About
import MyAboutBox
1582 about
= MyAboutBox(self
)
1586 def OnHelpFind(self
, event
):
1587 if self
.finddlg
!= None:
1590 self
.nb
.SetSelection(1)
1591 self
.finddlg
= wx
.FindReplaceDialog(self
, self
.finddata
, "Find",
1592 wx
.FR_NOMATCHCASE | wx
.FR_NOWHOLEWORD
)
1593 self
.finddlg
.Show(True)
1596 def OnUpdateFindItems(self
, evt
):
1597 evt
.Enable(self
.finddlg
== None)
1600 def OnFind(self
, event
):
1601 editor
= self
.codePage
.editor
1602 self
.nb
.SetSelection(1)
1603 end
= editor
.GetLastPosition()
1604 textstring
= editor
.GetRange(0, end
).lower()
1605 findstring
= self
.finddata
.GetFindString().lower()
1606 backward
= not (self
.finddata
.GetFlags() & wx
.FR_DOWN
)
1608 start
= editor
.GetSelection()[0]
1609 loc
= textstring
.rfind(findstring
, 0, start
)
1611 start
= editor
.GetSelection()[1]
1612 loc
= textstring
.find(findstring
, start
)
1613 if loc
== -1 and start
!= 0:
1614 # string not found, start at beginning
1617 loc
= textstring
.rfind(findstring
, 0, start
)
1620 loc
= textstring
.find(findstring
, start
)
1622 dlg
= wx
.MessageDialog(self
, 'Find String Not Found',
1623 'Find String Not Found in Demo File',
1624 wx
.OK | wx
.ICON_INFORMATION
)
1629 self
.finddlg
.SetFocus()
1632 self
.finddlg
.Destroy()
1634 editor
.ShowPosition(loc
)
1635 editor
.SetSelection(loc
, loc
+ len(findstring
))
1639 def OnFindNext(self
, event
):
1640 if self
.finddata
.GetFindString():
1643 self
.OnHelpFind(event
)
1645 def OnFindClose(self
, event
):
1646 event
.GetDialog().Destroy()
1650 def OnOpenShellWindow(self
, evt
):
1652 # if it already exists then just make sure it's visible
1658 # Make a PyShell window
1660 namespace
= { 'wx' : wx
,
1661 'app' : wx
.GetApp(),
1664 self
.shell
= py
.shell
.ShellFrame(None, locals=namespace
)
1665 self
.shell
.SetSize((640,480))
1668 # Hook the close event of the main frame window so that we
1669 # close the shell at the same time if it still exists
1670 def CloseShell(evt
):
1674 self
.Bind(wx
.EVT_CLOSE
, CloseShell
)
1677 #---------------------------------------------
1678 def OnCloseWindow(self
, event
):
1680 self
.demoPage
= None
1681 self
.codePage
= None
1682 self
.mainmenu
= None
1683 if self
.tbicon
is not None:
1684 self
.tbicon
.Destroy()
1688 #---------------------------------------------
1689 def OnIdle(self
, event
):
1691 self
.otherWin
.Raise()
1692 self
.demoPage
= self
.otherWin
1693 self
.otherWin
= None
1696 #---------------------------------------------
1699 showTipText
= open(opj("data/showTips")).read()
1700 showTip
, index
= eval(showTipText
)
1702 showTip
, index
= (1, 0)
1704 tp
= wx
.CreateFileTipProvider(opj("data/tips.txt"), index
)
1706 showTip
= wx
.ShowTip(self
, tp
)
1707 index
= tp
.GetCurrentTip()
1708 open(opj("data/showTips"), "w").write(str( (showTip
, index
) ))
1711 #---------------------------------------------
1712 def OnDemoMenu(self
, event
):
1714 selectedDemo
= self
.treeMap
[self
.mainmenu
.GetLabel(event
.GetId())]
1718 self
.tree
.SelectItem(selectedDemo
)
1719 self
.tree
.EnsureVisible(selectedDemo
)
1723 #---------------------------------------------
1724 def OnIconfiy(self
, evt
):
1725 wx
.LogMessage("OnIconfiy: %s" % evt
.Iconized())
1728 #---------------------------------------------
1729 def OnMaximize(self
, evt
):
1730 wx
.LogMessage("OnMaximize")
1733 #---------------------------------------------
1734 def OnActivate(self
, evt
):
1735 wx
.LogMessage("OnActivate: %s" % evt
.GetActive())
1738 #---------------------------------------------
1739 def OnAppActivate(self
, evt
):
1740 wx
.LogMessage("OnAppActivate: %s" % evt
.GetActive())
1743 #---------------------------------------------------------------------------
1744 #---------------------------------------------------------------------------
1746 class MySplashScreen(wx
.SplashScreen
):
1748 bmp
= wx
.Image(opj("bitmaps/splash.png")).ConvertToBitmap()
1749 wx
.SplashScreen
.__init
__(self
, bmp
,
1750 wx
.SPLASH_CENTRE_ON_SCREEN | wx
.SPLASH_TIMEOUT
,
1752 self
.Bind(wx
.EVT_CLOSE
, self
.OnClose
)
1753 self
.fc
= wx
.FutureCall(2000, self
.ShowMain
)
1756 def OnClose(self
, evt
):
1757 # Make sure the default handler runs too so this window gets
1762 # if the timer is still running then go ahead and show the
1764 if self
.fc
.IsRunning():
1770 frame
= wxPythonDemo(None, "wxPython: (A Demonstration)")
1772 if self
.fc
.IsRunning():
1775 import wx
.lib
.mixins
.inspect
1777 class MyApp(wx
.App
, wx
.lib
.mixins
.inspect
.InspectionMixin
):
1780 Create and show the splash screen. It will then create and show
1781 the main frame when it is time to do so.
1784 wx
.SystemOptions
.SetOptionInt("mac.window-plain-transition", 1)
1787 #self.SetAssertMode(wx.PYAPP_ASSERT_DIALOG)
1789 # Normally when using a SplashScreen you would create it, show
1790 # it and then continue on with the applicaiton's
1791 # initialization, finally creating and showing the main
1792 # application window(s). In this case we have nothing else to
1793 # do so we'll delay showing the main frame until later (see
1794 # ShowMain above) so the users can see the SplashScreen effect.
1795 splash
= MySplashScreen()
1798 # Setup the InspectionMixin
1805 #---------------------------------------------------------------------------
1809 demoPath
= os
.path
.dirname(__file__
)
1816 #---------------------------------------------------------------------------
1819 mainOverview
= """<html><body>
1822 <p> wxPython is a <b>GUI toolkit</b> for the Python programming
1823 language. It allows Python programmers to create programs with a
1824 robust, highly functional graphical user interface, simply and easily.
1825 It is implemented as a Python extension module (native code) that
1826 wraps the popular wxWindows cross platform GUI library, which is
1829 <p> Like Python and wxWindows, wxPython is <b>Open Source</b> which
1830 means that it is free for anyone to use and the source code is
1831 available for anyone to look at and modify. Or anyone can contribute
1832 fixes or enhancements to the project.
1834 <p> wxPython is a <b>cross-platform</b> toolkit. This means that the
1835 same program will run on multiple platforms without modification.
1836 Currently supported platforms are 32-bit Microsoft Windows, most Unix
1837 or unix-like systems, and Macintosh OS X. Since the language is
1838 Python, wxPython programs are <b>simple, easy</b> to write and easy to
1841 <p> <b>This demo</b> is not only a collection of test cases for
1842 wxPython, but is also designed to help you learn about and how to use
1843 wxPython. Each sample is listed in the tree control on the left.
1844 When a sample is selected in the tree then a module is loaded and run
1845 (usually in a tab of this notebook,) and the source code of the module
1846 is loaded in another tab for you to browse and learn from.
1851 #----------------------------------------------------------------------------
1852 #----------------------------------------------------------------------------
1854 if __name__
== '__main__':
1858 #----------------------------------------------------------------------------