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',
81 # managed windows == things with a (optional) caption you can close
82 ('Frames and Dialogs', [
83 'AUI_DockingWindowMgr',
104 'SingleChoiceDialog',
108 # dialogs from libraries
111 'ScrolledMessageDialog',
115 ('Core Windows/Controls', [
153 ('"Book" Controls', [
162 ('Custom Controls', [
179 # controls coming from other libraries
180 ('More Windows/Controls', [
181 'ActiveX_FlashWindow',
182 'ActiveX_IEHtmlWindow',
187 'CheckListCtrlMixin',
204 'MaskedEditControls',
207 'MultiSplitterWindow',
208 'OwnerDrawnComboBox',
225 # How to lay out the controls in a frame/dialog
235 'XmlResourceHandler',
236 'XmlResourceSubclass',
240 ('Process and Events', [
248 ##'infoframe', # needs better explanation and some fixing
252 ('Clipboard and DnD', [
279 ##'DialogUnits', # needs more explanations
300 ('Check out the samples dir too', [
307 #---------------------------------------------------------------------------
308 # Show how to derive a custom wxLog class
310 class MyLog(wx
.PyLog
):
311 def __init__(self
, textCtrl
, logTime
=0):
312 wx
.PyLog
.__init
__(self
)
314 self
.logTime
= logTime
316 def DoLogString(self
, message
, timeStamp
):
317 #print message, timeStamp
319 # message = time.strftime("%X", time.localtime(timeStamp)) + \
322 self
.tc
.AppendText(message
+ '\n')
325 class MyTP(wx
.PyTipProvider
):
327 return "This is my tip"
329 #---------------------------------------------------------------------------
330 # A class to be used to simply display a message in the demo pane
331 # rather than running the sample itself.
333 class MessagePanel(wx
.Panel
):
334 def __init__(self
, parent
, message
, caption
='', flags
=0):
335 wx
.Panel
.__init
__(self
, parent
)
340 if flags
& wx
.ICON_EXCLAMATION
:
341 artid
= wx
.ART_WARNING
342 elif flags
& wx
.ICON_ERROR
:
344 elif flags
& wx
.ICON_QUESTION
:
345 artid
= wx
.ART_QUESTION
346 elif flags
& wx
.ICON_INFORMATION
:
347 artid
= wx
.ART_INFORMATION
349 if artid
is not None:
350 bmp
= wx
.ArtProvider
.GetBitmap(artid
, wx
.ART_MESSAGE_BOX
, (32,32))
351 icon
= wx
.StaticBitmap(self
, -1, bmp
)
353 icon
= (32,32) # make a spacer instead
356 caption
= wx
.StaticText(self
, -1, caption
)
357 caption
.SetFont(wx
.Font(28, wx
.SWISS
, wx
.NORMAL
, wx
.BOLD
))
359 message
= wx
.StaticText(self
, -1, message
)
361 # add to sizers for layout
362 tbox
= wx
.BoxSizer(wx
.VERTICAL
)
368 hbox
= wx
.BoxSizer(wx
.HORIZONTAL
)
375 box
= wx
.BoxSizer(wx
.VERTICAL
)
377 box
.Add(hbox
, 0, wx
.EXPAND
)
384 #---------------------------------------------------------------------------
385 # A class to be used to display source code in the demo. Try using the
386 # wxSTC in the StyledTextCtrl_2 sample first, fall back to wxTextCtrl
387 # if there is an error, such as the stc module not being present.
391 ##raise ImportError # for testing the alternate implementation
393 from StyledTextCtrl_2
import PythonSTC
395 class DemoCodeEditor(PythonSTC
):
396 def __init__(self
, parent
):
397 PythonSTC
.__init
__(self
, parent
, -1, style
=wx
.BORDER_NONE
)
400 # Some methods to make it compatible with how the wxTextCtrl is used
401 def SetValue(self
, value
):
403 value
= value
.decode('iso8859_1')
405 self
.EmptyUndoBuffer()
408 def IsModified(self
):
409 return self
.GetModify()
414 def SetInsertionPoint(self
, pos
):
415 self
.SetCurrentPos(pos
)
418 def ShowPosition(self
, pos
):
419 line
= self
.LineFromPosition(pos
)
420 #self.EnsureVisible(line)
423 def GetLastPosition(self
):
424 return self
.GetLength()
426 def GetPositionFromLine(self
, line
):
427 return self
.PositionFromLine(line
)
429 def GetRange(self
, start
, end
):
430 return self
.GetTextRange(start
, end
)
432 def GetSelection(self
):
433 return self
.GetAnchor(), self
.GetCurrentPos()
435 def SetSelection(self
, start
, end
):
436 self
.SetSelectionStart(start
)
437 self
.SetSelectionEnd(end
)
439 def SelectLine(self
, line
):
440 start
= self
.PositionFromLine(line
)
441 end
= self
.GetLineEndPosition(line
)
442 self
.SetSelection(start
, end
)
444 def SetUpEditor(self
):
446 This method carries out the work of setting up the demo editor.
447 It's seperate so as not to clutter up the init code.
451 self
.SetLexer(stc
.STC_LEX_PYTHON
)
452 self
.SetKeyWords(0, " ".join(keyword
.kwlist
))
455 self
.SetProperty("fold", "1" )
457 # Highlight tab/space mixing (shouldn't be any)
458 self
.SetProperty("tab.timmy.whinge.level", "1")
460 # Set left and right margins
463 # Set up the numbers in the margin for margin #1
464 self
.SetMarginType(1, wx
.stc
.STC_MARGIN_NUMBER
)
465 # Reasonable value for, say, 4-5 digits using a mono font (40 pix)
466 self
.SetMarginWidth(1, 40)
468 # Indentation and tab stuff
469 self
.SetIndent(4) # Proscribed indent size for wx
470 self
.SetIndentationGuides(True) # Show indent guides
471 self
.SetBackSpaceUnIndents(True)# Backspace unindents rather than delete 1 space
472 self
.SetTabIndents(True) # Tab key indents
473 self
.SetTabWidth(4) # Proscribed tab size for wx
474 self
.SetUseTabs(False) # Use spaces rather than tabs, or
475 # TabTimmy will complain!
477 self
.SetViewWhiteSpace(False) # Don't view white space
479 # EOL: Since we are loading/saving ourselves, and the
480 # strings will always have \n's in them, set the STC to
481 # edit them that way.
482 self
.SetEOLMode(wx
.stc
.STC_EOL_LF
)
483 self
.SetViewEOL(False)
485 # No right-edge mode indicator
486 self
.SetEdgeMode(stc
.STC_EDGE_NONE
)
488 # Setup a margin to hold fold markers
489 self
.SetMarginType(2, stc
.STC_MARGIN_SYMBOL
)
490 self
.SetMarginMask(2, stc
.STC_MASK_FOLDERS
)
491 self
.SetMarginSensitive(2, True)
492 self
.SetMarginWidth(2, 12)
494 # and now set up the fold markers
495 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEREND
, stc
.STC_MARK_BOXPLUSCONNECTED
, "white", "black")
496 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEROPENMID
, stc
.STC_MARK_BOXMINUSCONNECTED
, "white", "black")
497 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERMIDTAIL
, stc
.STC_MARK_TCORNER
, "white", "black")
498 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERTAIL
, stc
.STC_MARK_LCORNER
, "white", "black")
499 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERSUB
, stc
.STC_MARK_VLINE
, "white", "black")
500 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDER
, stc
.STC_MARK_BOXPLUS
, "white", "black")
501 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEROPEN
, stc
.STC_MARK_BOXMINUS
, "white", "black")
503 # Global default style
504 if wx
.Platform
== '__WXMSW__':
505 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,
506 'fore:#000000,back:#FFFFFF,face:Courier New,size:9')
507 elif wx
.Platform
== '__WXMAC__':
508 # TODO: if this looks fine on Linux too, remove the Mac-specific case
509 # and use this whenever OS != MSW.
510 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,
511 'fore:#000000,back:#FFFFFF,face:Courier')
513 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,
514 'fore:#000000,back:#FFFFFF,face:Courier,size:9')
516 # Clear styles and revert to default.
519 # Following style specs only indicate differences from default.
520 # The rest remains unchanged.
522 # Line numbers in margin
523 self
.StyleSetSpec(wx
.stc
.STC_STYLE_LINENUMBER
,'fore:#000000,back:#99A9C2')
525 self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACELIGHT
,'fore:#00009D,back:#FFFF00')
527 self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACEBAD
,'fore:#00009D,back:#FF0000')
529 self
.StyleSetSpec(wx
.stc
.STC_STYLE_INDENTGUIDE
, "fore:#CDCDCD")
532 self
.StyleSetSpec(wx
.stc
.STC_P_DEFAULT
, 'fore:#000000')
534 self
.StyleSetSpec(wx
.stc
.STC_P_COMMENTLINE
, 'fore:#008000,back:#F0FFF0')
535 self
.StyleSetSpec(wx
.stc
.STC_P_COMMENTBLOCK
, 'fore:#008000,back:#F0FFF0')
537 self
.StyleSetSpec(wx
.stc
.STC_P_NUMBER
, 'fore:#008080')
538 # Strings and characters
539 self
.StyleSetSpec(wx
.stc
.STC_P_STRING
, 'fore:#800080')
540 self
.StyleSetSpec(wx
.stc
.STC_P_CHARACTER
, 'fore:#800080')
542 self
.StyleSetSpec(wx
.stc
.STC_P_WORD
, 'fore:#000080,bold')
544 self
.StyleSetSpec(wx
.stc
.STC_P_TRIPLE
, 'fore:#800080,back:#FFFFEA')
545 self
.StyleSetSpec(wx
.stc
.STC_P_TRIPLEDOUBLE
, 'fore:#800080,back:#FFFFEA')
547 self
.StyleSetSpec(wx
.stc
.STC_P_CLASSNAME
, 'fore:#0000FF,bold')
549 self
.StyleSetSpec(wx
.stc
.STC_P_DEFNAME
, 'fore:#008080,bold')
551 self
.StyleSetSpec(wx
.stc
.STC_P_OPERATOR
, 'fore:#800000,bold')
552 # Identifiers. I leave this as not bold because everything seems
553 # to be an identifier if it doesn't match the above criterae
554 self
.StyleSetSpec(wx
.stc
.STC_P_IDENTIFIER
, 'fore:#000000')
557 self
.SetCaretForeground("BLUE")
558 # Selection background
559 self
.SetSelBackground(1, '#66CCFF')
561 self
.SetSelBackground(True, wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_HIGHLIGHT
))
562 self
.SetSelForeground(True, wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_HIGHLIGHTTEXT
))
564 def RegisterModifiedEvent(self
, eventHandler
):
565 self
.Bind(wx
.stc
.EVT_STC_CHANGE
, eventHandler
)
569 class DemoCodeEditor(wx
.TextCtrl
):
570 def __init__(self
, parent
):
571 wx
.TextCtrl
.__init
__(self
, parent
, -1, style
=
572 wx
.TE_MULTILINE | wx
.HSCROLL | wx
.TE_RICH2 | wx
.TE_NOHIDESEL
)
574 def RegisterModifiedEvent(self
, eventHandler
):
575 self
.Bind(wx
.EVT_TEXT
, eventHandler
)
577 def SetReadOnly(self
, flag
):
578 self
.SetEditable(not flag
)
579 # NOTE: STC already has this method
582 return self
.GetValue()
584 def GetPositionFromLine(self
, line
):
585 return self
.XYToPosition(0,line
)
587 def GotoLine(self
, line
):
588 pos
= self
.GetPositionFromLine(line
)
589 self
.SetInsertionPoint(pos
)
590 self
.ShowPosition(pos
)
592 def SelectLine(self
, line
):
593 start
= self
.GetPositionFromLine(line
)
594 end
= start
+ self
.GetLineLength(line
)
595 self
.SetSelection(start
, end
)
598 #---------------------------------------------------------------------------
599 # Constants for module versions
603 modDefault
= modOriginal
605 #---------------------------------------------------------------------------
607 class DemoCodePanel(wx
.Panel
):
608 """Panel for the 'Demo Code' tab"""
609 def __init__(self
, parent
, mainFrame
):
610 wx
.Panel
.__init
__(self
, parent
, size
=(1,1))
611 if 'wxMSW' in wx
.PlatformInfo
:
613 self
.mainFrame
= mainFrame
614 self
.editor
= DemoCodeEditor(self
)
615 self
.editor
.RegisterModifiedEvent(self
.OnCodeModified
)
617 self
.btnSave
= wx
.Button(self
, -1, "Save Changes")
618 self
.btnRestore
= wx
.Button(self
, -1, "Delete Modified")
619 self
.btnSave
.Enable(False)
620 self
.btnSave
.Bind(wx
.EVT_BUTTON
, self
.OnSave
)
621 self
.btnRestore
.Bind(wx
.EVT_BUTTON
, self
.OnRestore
)
623 self
.radioButtons
= { modOriginal
: wx
.RadioButton(self
, -1, "Original", style
= wx
.RB_GROUP
),
624 modModified
: wx
.RadioButton(self
, -1, "Modified") }
626 self
.controlBox
= wx
.BoxSizer(wx
.HORIZONTAL
)
627 self
.controlBox
.Add(wx
.StaticText(self
, -1, "Active Version:"), 0,
628 wx
.RIGHT | wx
.LEFT | wx
.ALIGN_CENTER_VERTICAL
, 5)
629 for modID
, radioButton
in self
.radioButtons
.items():
630 self
.controlBox
.Add(radioButton
, 0, wx
.EXPAND | wx
.RIGHT
, 5)
631 radioButton
.modID
= modID
# makes it easier for the event handler
632 radioButton
.Bind(wx
.EVT_RADIOBUTTON
, self
.OnRadioButton
)
634 self
.controlBox
.Add(self
.btnSave
, 0, wx
.RIGHT
, 5)
635 self
.controlBox
.Add(self
.btnRestore
, 0)
637 self
.box
= wx
.BoxSizer(wx
.VERTICAL
)
638 self
.box
.Add(self
.controlBox
, 0, wx
.EXPAND
)
639 self
.box
.Add(wx
.StaticLine(self
), 0, wx
.EXPAND
)
640 self
.box
.Add(self
.editor
, 1, wx
.EXPAND
)
643 self
.SetSizer(self
.box
)
646 # Loads a demo from a DemoModules object
647 def LoadDemo(self
, demoModules
):
648 self
.demoModules
= demoModules
649 if (modDefault
== modModified
) and demoModules
.Exists(modModified
):
650 demoModules
.SetActive(modModified
)
652 demoModules
.SetActive(modOriginal
)
653 self
.radioButtons
[demoModules
.GetActiveID()].Enable(True)
654 self
.ActiveModuleChanged()
657 def ActiveModuleChanged(self
):
658 self
.LoadDemoSource(self
.demoModules
.GetSource())
659 self
.UpdateControlState()
663 def LoadDemoSource(self
, source
):
665 self
.editor
.SetValue(source
)
667 self
.btnSave
.Enable(False)
670 def JumpToLine(self
, line
, highlight
=False):
671 self
.editor
.GotoLine(line
)
672 self
.editor
.SetFocus()
674 self
.editor
.SelectLine(line
)
677 def UpdateControlState(self
):
678 active
= self
.demoModules
.GetActiveID()
679 # Update the radio/restore buttons
680 for moduleID
in self
.radioButtons
:
681 btn
= self
.radioButtons
[moduleID
]
682 if moduleID
== active
:
687 if self
.demoModules
.Exists(moduleID
):
689 if moduleID
== modModified
:
690 self
.btnRestore
.Enable(True)
693 if moduleID
== modModified
:
694 self
.btnRestore
.Enable(False)
697 def OnRadioButton(self
, event
):
698 radioSelected
= event
.GetEventObject()
699 modSelected
= radioSelected
.modID
700 if modSelected
!= self
.demoModules
.GetActiveID():
701 busy
= wx
.BusyInfo("Reloading demo module...")
702 self
.demoModules
.SetActive(modSelected
)
703 self
.ActiveModuleChanged()
706 def ReloadDemo(self
):
707 if self
.demoModules
.name
!= __name__
:
708 self
.mainFrame
.RunModule()
711 def OnCodeModified(self
, event
):
712 self
.btnSave
.Enable(self
.editor
.IsModified())
715 def OnSave(self
, event
):
716 if self
.demoModules
.Exists(modModified
):
717 if self
.demoModules
.GetActiveID() == modOriginal
:
718 overwriteMsg
= "You are about to overwrite an already existing modified copy\n" + \
719 "Do you want to continue?"
720 dlg
= wx
.MessageDialog(self
, overwriteMsg
, "wxPython Demo",
721 wx
.YES_NO | wx
.NO_DEFAULT| wx
.ICON_EXCLAMATION
)
722 result
= dlg
.ShowModal()
723 if result
== wx
.ID_NO
:
727 self
.demoModules
.SetActive(modModified
)
728 modifiedFilename
= GetModifiedFilename(self
.demoModules
.name
)
730 # Create the demo directory if one doesn't already exist
731 if not os
.path
.exists(GetModifiedDirectory()):
733 os
.makedirs(GetModifiedDirectory())
734 if not os
.path
.exists(GetModifiedDirectory()):
735 wx
.LogMessage("BUG: Created demo directory but it still doesn't exist")
738 wx
.LogMessage("Error creating demo directory: %s" % GetModifiedDirectory())
741 wx
.LogMessage("Created directory for modified demos: %s" % GetModifiedDirectory())
744 f
= open(modifiedFilename
, "wt")
745 source
= self
.editor
.GetText()
751 busy
= wx
.BusyInfo("Reloading demo module...")
752 self
.demoModules
.LoadFromFile(modModified
, modifiedFilename
)
753 self
.ActiveModuleChanged()
756 def OnRestore(self
, event
): # Handles the "Delete Modified" button
757 modifiedFilename
= GetModifiedFilename(self
.demoModules
.name
)
758 self
.demoModules
.Delete(modModified
)
759 os
.unlink(modifiedFilename
) # Delete the modified copy
760 busy
= wx
.BusyInfo("Reloading demo module...")
761 self
.ActiveModuleChanged()
764 #---------------------------------------------------------------------------
767 """Convert paths to the platform-specific separator"""
768 str = apply(os
.path
.join
, tuple(path
.split('/')))
769 # HACK: on Linux, a leading / gets lost...
770 if path
.startswith('/'):
775 def GetModifiedDirectory():
777 Returns the directory where modified versions of the demo files
780 return opj(wx
.GetHomeDir() + "/.wxPyDemo/modified/")
783 def GetModifiedFilename(name
):
785 Returns the filename of the modified version of the specified demo
787 if not name
.endswith(".py"):
789 return GetModifiedDirectory() + name
792 def GetOriginalFilename(name
):
794 Returns the filename of the original version of the specified demo
796 if not name
.endswith(".py"):
801 def DoesModifiedExist(name
):
802 """Returns whether the specified demo has a modified copy"""
803 if os
.path
.exists(GetModifiedFilename(name
)):
809 #---------------------------------------------------------------------------
811 class ModuleDictWrapper
:
812 """Emulates a module with a dynamically compiled __dict__"""
813 def __init__(self
, dict):
816 def __getattr__(self
, name
):
817 if name
in self
.dict:
818 return self
.dict[name
]
824 Dynamically manages the original/modified versions of a demo
827 def __init__(self
, name
):
831 # (dict , source , filename , description , error information )
832 # ( 0 , 1 , 2 , 3 , 4 )
833 self
.modules
= [[None, "" , "" , "<original>" , None],
834 [None, "" , "" , "<modified>" , None]]
836 # load original module
837 self
.LoadFromFile(modOriginal
, GetOriginalFilename(name
))
838 self
.SetActive(modOriginal
)
840 # load modified module (if one exists)
841 if DoesModifiedExist(name
):
842 self
.LoadFromFile(modModified
, GetModifiedFilename(name
))
845 def LoadFromFile(self
, modID
, filename
):
846 self
.modules
[modID
][2] = filename
847 file = open(filename
, "rt")
848 self
.LoadFromSource(modID
, file.read())
852 def LoadFromSource(self
, modID
, source
):
853 self
.modules
[modID
][1] = source
857 def LoadDict(self
, modID
):
858 if self
.name
!= __name__
:
859 source
= self
.modules
[modID
][1]
860 #description = self.modules[modID][3]
861 description
= self
.modules
[modID
][2]
864 self
.modules
[modID
][0] = {}
865 code
= compile(source
, description
, "exec")
866 exec code
in self
.modules
[modID
][0]
868 self
.modules
[modID
][4] = DemoError(sys
.exc_info())
869 self
.modules
[modID
][0] = None
871 self
.modules
[modID
][4] = None
874 def SetActive(self
, modID
):
875 if modID
!= modOriginal
and modID
!= modModified
:
878 self
.modActive
= modID
882 dict = self
.modules
[self
.modActive
][0]
886 return ModuleDictWrapper(dict)
889 def GetActiveID(self
):
890 return self
.modActive
893 def GetSource(self
, modID
= None):
895 modID
= self
.modActive
896 return self
.modules
[modID
][1]
899 def GetFilename(self
, modID
= None):
901 modID
= self
.modActive
902 return self
.modules
[self
.modActive
][2]
905 def GetErrorInfo(self
, modID
= None):
907 modID
= self
.modActive
908 return self
.modules
[self
.modActive
][4]
911 def Exists(self
, modID
):
912 return self
.modules
[modID
][1] != ""
915 def UpdateFile(self
, modID
= None):
916 """Updates the file from which a module was loaded
917 with (possibly updated) source"""
919 modID
= self
.modActive
921 source
= self
.modules
[modID
][1]
922 filename
= self
.modules
[modID
][2]
925 file = open(filename
, "wt")
931 def Delete(self
, modID
):
932 if self
.modActive
== modID
:
935 self
.modules
[modID
][0] = None
936 self
.modules
[modID
][1] = ""
937 self
.modules
[modID
][2] = ""
940 #---------------------------------------------------------------------------
943 """Wraps and stores information about the current exception"""
944 def __init__(self
, exc_info
):
947 excType
, excValue
= exc_info
[:2]
948 # traceback list entries: (filename, line number, function name, text)
949 self
.traceback
= traceback
.extract_tb(exc_info
[2])
951 # --Based on traceback.py::format_exception_only()--
952 if type(excType
) == types
.ClassType
:
953 self
.exception_type
= excType
.__name
__
955 self
.exception_type
= excType
957 # If it's a syntax error, extra information needs
958 # to be added to the traceback
959 if excType
is SyntaxError:
961 msg
, (filename
, lineno
, self
.offset
, line
) = excValue
966 filename
= "<string>"
968 self
.traceback
.append( (filename
, lineno
, "", line
) )
971 self
.exception_details
= str(excValue
)
973 self
.exception_details
= "<unprintable %s object>" & type(excValue
).__name
__
980 Details : %s" % ( str(self
.exception_type
), str(self
.traceback
), self
.exception_details
)
983 #---------------------------------------------------------------------------
985 class DemoErrorPanel(wx
.Panel
):
986 """Panel put into the demo tab when the demo fails to run due to errors"""
988 def __init__(self
, parent
, codePanel
, demoError
, log
):
989 wx
.Panel
.__init
__(self
, parent
, -1)#, style=wx.NO_FULL_REPAINT_ON_RESIZE)
990 self
.codePanel
= codePanel
994 self
.box
= wx
.BoxSizer(wx
.VERTICAL
)
997 self
.box
.Add(wx
.StaticText(self
, -1, "An error has occurred while trying to run the demo")
998 , 0, wx
.ALIGN_CENTER | wx
.TOP
, 10)
1000 # Exception Information
1001 boxInfo
= wx
.StaticBox(self
, -1, "Exception Info" )
1002 boxInfoSizer
= wx
.StaticBoxSizer(boxInfo
, wx
.VERTICAL
) # Used to center the grid within the box
1003 boxInfoGrid
= wx
.FlexGridSizer(0, 2, 0, 0)
1004 textFlags
= wx
.ALIGN_RIGHT | wx
.LEFT | wx
.RIGHT | wx
.TOP
1005 boxInfoGrid
.Add(wx
.StaticText(self
, -1, "Type: "), 0, textFlags
, 5 )
1006 boxInfoGrid
.Add(wx
.StaticText(self
, -1, str(demoError
.exception_type
)) , 0, textFlags
, 5 )
1007 boxInfoGrid
.Add(wx
.StaticText(self
, -1, "Details: ") , 0, textFlags
, 5 )
1008 boxInfoGrid
.Add(wx
.StaticText(self
, -1, demoError
.exception_details
) , 0, textFlags
, 5 )
1009 boxInfoSizer
.Add(boxInfoGrid
, 0, wx
.ALIGN_CENTRE | wx
.ALL
, 5 )
1010 self
.box
.Add(boxInfoSizer
, 0, wx
.ALIGN_CENTER | wx
.ALL
, 5)
1012 # Set up the traceback list
1013 # This one automatically resizes last column to take up remaining space
1014 from ListCtrl
import TestListCtrl
1015 self
.list = TestListCtrl(self
, -1, style
=wx
.LC_REPORT | wx
.SUNKEN_BORDER
)
1016 self
.list.Bind(wx
.EVT_LEFT_DCLICK
, self
.OnDoubleClick
)
1017 self
.list.Bind(wx
.EVT_LIST_ITEM_SELECTED
, self
.OnItemSelected
)
1018 self
.list.InsertColumn(0, "Filename")
1019 self
.list.InsertColumn(1, "Line", wx
.LIST_FORMAT_RIGHT
)
1020 self
.list.InsertColumn(2, "Function")
1021 self
.list.InsertColumn(3, "Code")
1022 self
.InsertTraceback(self
.list, demoError
.traceback
)
1023 self
.list.SetColumnWidth(0, wx
.LIST_AUTOSIZE
)
1024 self
.list.SetColumnWidth(2, wx
.LIST_AUTOSIZE
)
1025 self
.box
.Add(wx
.StaticText(self
, -1, "Traceback:")
1026 , 0, wx
.ALIGN_CENTER | wx
.TOP
, 5)
1027 self
.box
.Add(self
.list, 1, wx
.GROW | wx
.ALIGN_CENTER | wx
.ALL
, 5)
1028 self
.box
.Add(wx
.StaticText(self
, -1, "Entries from the demo module are shown in blue\n"
1029 + "Double-click on them to go to the offending line")
1030 , 0, wx
.ALIGN_CENTER | wx
.BOTTOM
, 5)
1033 self
.SetSizer(self
.box
)
1036 def InsertTraceback(self
, list, traceback
):
1037 #Add the traceback data
1038 for x
in range(len(traceback
)):
1040 list.InsertStringItem(x
, os
.path
.basename(data
[0])) # Filename
1041 list.SetStringItem(x
, 1, str(data
[1])) # Line
1042 list.SetStringItem(x
, 2, str(data
[2])) # Function
1043 list.SetStringItem(x
, 3, str(data
[3])) # Code
1045 # Check whether this entry is from the demo module
1046 if data
[0] == "<original>" or data
[0] == "<modified>": # FIXME: make more generalised
1047 self
.list.SetItemData(x
, int(data
[1])) # Store line number for easy access
1048 # Give it a blue colour
1049 item
= self
.list.GetItem(x
)
1050 item
.SetTextColour(wx
.BLUE
)
1051 self
.list.SetItem(item
)
1053 self
.list.SetItemData(x
, -1) # Editor can't jump into this one's code
1056 def OnItemSelected(self
, event
):
1057 # This occurs before OnDoubleClick and can be used to set the
1058 # currentItem. OnDoubleClick doesn't get a wxListEvent....
1059 self
.currentItem
= event
.m_itemIndex
1063 def OnDoubleClick(self
, event
):
1064 # If double-clicking on a demo's entry, jump to the line number
1065 line
= self
.list.GetItemData(self
.currentItem
)
1067 self
.nb
.SetSelection(1) # Switch to the code viewer tab
1068 wx
.CallAfter(self
.codePanel
.JumpToLine
, line
-1, True)
1072 #---------------------------------------------------------------------------
1074 class DemoTaskBarIcon(wx
.TaskBarIcon
):
1075 TBMENU_RESTORE
= wx
.NewId()
1076 TBMENU_CLOSE
= wx
.NewId()
1077 TBMENU_CHANGE
= wx
.NewId()
1078 TBMENU_REMOVE
= wx
.NewId()
1080 def __init__(self
, frame
):
1081 wx
.TaskBarIcon
.__init
__(self
)
1085 icon
= self
.MakeIcon(images
.getWXPdemoImage())
1086 self
.SetIcon(icon
, "wxPython Demo")
1090 self
.Bind(wx
.EVT_TASKBAR_LEFT_DCLICK
, self
.OnTaskBarActivate
)
1091 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarActivate
, id=self
.TBMENU_RESTORE
)
1092 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarClose
, id=self
.TBMENU_CLOSE
)
1093 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarChange
, id=self
.TBMENU_CHANGE
)
1094 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarRemove
, id=self
.TBMENU_REMOVE
)
1097 def CreatePopupMenu(self
):
1099 This method is called by the base class when it needs to popup
1100 the menu for the default EVT_RIGHT_DOWN event. Just create
1101 the menu how you want it and return it from this function,
1102 the base class takes care of the rest.
1105 menu
.Append(self
.TBMENU_RESTORE
, "Restore wxPython Demo")
1106 menu
.Append(self
.TBMENU_CLOSE
, "Close wxPython Demo")
1107 menu
.AppendSeparator()
1108 menu
.Append(self
.TBMENU_CHANGE
, "Change the TB Icon")
1109 menu
.Append(self
.TBMENU_REMOVE
, "Remove the TB Icon")
1113 def MakeIcon(self
, img
):
1115 The various platforms have different requirements for the
1118 if "wxMSW" in wx
.PlatformInfo
:
1119 img
= img
.Scale(16, 16)
1120 elif "wxGTK" in wx
.PlatformInfo
:
1121 img
= img
.Scale(22, 22)
1122 # wxMac can be any size upto 128x128, so leave the source img alone....
1123 icon
= wx
.IconFromBitmap(img
.ConvertToBitmap() )
1127 def OnTaskBarActivate(self
, evt
):
1128 if self
.frame
.IsIconized():
1129 self
.frame
.Iconize(False)
1130 if not self
.frame
.IsShown():
1131 self
.frame
.Show(True)
1135 def OnTaskBarClose(self
, evt
):
1139 def OnTaskBarChange(self
, evt
):
1140 names
= [ "WXPdemo", "Mondrian", "Pencil", "Carrot" ]
1141 name
= names
[self
.imgidx
]
1143 getFunc
= getattr(images
, "get%sImage" % name
)
1145 if self
.imgidx
>= len(names
):
1148 icon
= self
.MakeIcon(getFunc())
1149 self
.SetIcon(icon
, "This is a new icon: " + name
)
1152 def OnTaskBarRemove(self
, evt
):
1156 #---------------------------------------------------------------------------
1157 class wxPythonDemo(wx
.Frame
):
1158 overviewText
= "wxPython Overview"
1160 def __init__(self
, parent
, title
):
1161 wx
.Frame
.__init
__(self
, parent
, -1, title
, size
= (950, 720),
1162 style
=wx
.DEFAULT_FRAME_STYLE | wx
.NO_FULL_REPAINT_ON_RESIZE
)
1164 self
.SetMinSize((640,480))
1167 self
.cwd
= os
.getcwd()
1168 self
.curOverview
= ""
1169 self
.demoPage
= None
1170 self
.codePage
= None
1172 self
.firstTime
= True
1175 icon
= images
.getWXPdemoIcon()
1179 self
.tbicon
= DemoTaskBarIcon(self
)
1183 wx
.CallAfter(self
.ShowTip
)
1185 self
.otherWin
= None
1186 self
.Bind(wx
.EVT_IDLE
, self
.OnIdle
)
1187 self
.Bind(wx
.EVT_CLOSE
, self
.OnCloseWindow
)
1188 self
.Bind(wx
.EVT_ICONIZE
, self
.OnIconfiy
)
1189 self
.Bind(wx
.EVT_MAXIMIZE
, self
.OnMaximize
)
1191 self
.Centre(wx
.BOTH
)
1192 self
.CreateStatusBar(1, wx
.ST_SIZEGRIP
)
1194 splitter
= wx
.SplitterWindow(self
, -1, style
=wx
.CLIP_CHILDREN | wx
.SP_LIVE_UPDATE | wx
.SP_3D
)
1195 splitter2
= wx
.SplitterWindow(splitter
, -1, style
=wx
.CLIP_CHILDREN | wx
.SP_LIVE_UPDATE | wx
.SP_3D
)
1197 def EmptyHandler(evt
): pass
1198 #splitter.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
1199 #splitter2.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
1201 # Prevent TreeCtrl from displaying all items after destruction when True
1205 self
.nb
= wx
.Notebook(splitter2
, -1, style
=wx
.CLIP_CHILDREN
)
1208 self
.mainmenu
= wx
.MenuBar()
1210 item
= menu
.Append(-1, '&Redirect Output',
1211 'Redirect print statements to a window',
1213 self
.Bind(wx
.EVT_MENU
, self
.OnToggleRedirect
, item
)
1215 item
= menu
.Append(-1, 'E&xit\tAlt-X', 'Get the heck outta here!')
1216 self
.Bind(wx
.EVT_MENU
, self
.OnFileExit
, item
)
1217 wx
.App
.SetMacExitMenuItemId(item
.GetId())
1218 self
.mainmenu
.Append(menu
, '&File')
1222 for item
in _treeList
:
1224 for childItem
in item
[1]:
1225 mi
= submenu
.Append(-1, childItem
)
1226 self
.Bind(wx
.EVT_MENU
, self
.OnDemoMenu
, mi
)
1227 menu
.AppendMenu(wx
.NewId(), item
[0], submenu
)
1228 self
.mainmenu
.Append(menu
, '&Demo')
1233 findItem
= menu
.Append(-1, '&Find\tCtrl-F', 'Find in the Demo Code')
1234 findnextItem
= menu
.Append(-1, 'Find &Next\tF3', 'Find Next')
1235 menu
.AppendSeparator()
1237 shellItem
= menu
.Append(-1, 'Open Py&Shell Window\tF5',
1238 'An interactive interpreter window with the demo app and frame objects in the namesapce')
1239 menu
.AppendSeparator()
1240 helpItem
= menu
.Append(-1, '&About wxPython Demo', 'wxPython RULES!!!')
1241 wx
.App
.SetMacAboutMenuItemId(helpItem
.GetId())
1243 self
.Bind(wx
.EVT_MENU
, self
.OnOpenShellWindow
, shellItem
)
1244 self
.Bind(wx
.EVT_MENU
, self
.OnHelpAbout
, helpItem
)
1245 self
.Bind(wx
.EVT_MENU
, self
.OnHelpFind
, findItem
)
1246 self
.Bind(wx
.EVT_MENU
, self
.OnFindNext
, findnextItem
)
1247 self
.Bind(wx
.EVT_FIND
, self
.OnFind
)
1248 self
.Bind(wx
.EVT_FIND_NEXT
, self
.OnFind
)
1249 self
.Bind(wx
.EVT_FIND_CLOSE
, self
.OnFindClose
)
1250 self
.Bind(wx
.EVT_UPDATE_UI
, self
.OnUpdateFindItems
, findItem
)
1251 self
.Bind(wx
.EVT_UPDATE_UI
, self
.OnUpdateFindItems
, findnextItem
)
1252 self
.mainmenu
.Append(menu
, '&Help')
1253 self
.SetMenuBar(self
.mainmenu
)
1255 self
.finddata
= wx
.FindReplaceData()
1256 self
.finddata
.SetFlags(wx
.FR_DOWN
)
1259 # This is another way to set Accelerators, in addition to
1260 # using the '\t<key>' syntax in the menu items.
1261 aTable
= wx
.AcceleratorTable([(wx
.ACCEL_ALT
, ord('X'), exitID
),
1262 (wx
.ACCEL_CTRL
, ord('H'), helpID
),
1263 (wx
.ACCEL_CTRL
, ord('F'), findID
),
1264 (wx
.ACCEL_NORMAL
, WXK_F3
, findnextID
)
1266 self
.SetAcceleratorTable(aTable
)
1271 leftPanel
= wx
.Panel(splitter
)
1273 self
.filter = wx
.TextCtrl(leftPanel
)
1274 self
.filter.Bind(wx
.EVT_TEXT
, self
.RecreateTree
)
1277 self
.tree
= wx
.TreeCtrl(leftPanel
, tID
, style
=
1278 wx
.TR_DEFAULT_STYLE
#| wx.TR_HAS_VARIABLE_ROW_HEIGHT
1281 self
.root
= self
.tree
.AddRoot("wxPython Overview")
1283 self
.tree
.Bind(wx
.EVT_TREE_ITEM_EXPANDED
, self
.OnItemExpanded
, id=tID
)
1284 self
.tree
.Bind(wx
.EVT_TREE_ITEM_COLLAPSED
, self
.OnItemCollapsed
, id=tID
)
1285 self
.tree
.Bind(wx
.EVT_TREE_SEL_CHANGED
, self
.OnSelChanged
, id=tID
)
1286 self
.tree
.Bind(wx
.EVT_LEFT_DOWN
, self
.OnTreeLeftDown
)
1288 # Set up a wx.html.HtmlWindow on the Overview Notebook page
1289 # we put it in a panel first because there seems to be a
1290 # refresh bug of some sort (wxGTK) when it is directly in
1293 self
.ovr
= wx
.html
.HtmlWindow(self
.nb
, -1, size
=(400, 400))
1294 self
.nb
.AddPage(self
.ovr
, self
.overviewText
)
1296 else: # hopefully I can remove this hacky code soon, see SF bug #216861
1297 panel
= wx
.Panel(self
.nb
, -1, style
=wx
.CLIP_CHILDREN
)
1298 self
.ovr
= wx
.html
.HtmlWindow(panel
, -1, size
=(400, 400))
1299 self
.nb
.AddPage(panel
, self
.overviewText
)
1301 def OnOvrSize(evt
, ovr
=self
.ovr
):
1302 ovr
.SetSize(evt
.GetSize())
1303 panel
.Bind(wx
.EVT_SIZE
, OnOvrSize
)
1304 panel
.Bind(wx
.EVT_ERASE_BACKGROUND
, EmptyHandler
)
1306 if "gtk2" in wx
.PlatformInfo
:
1307 self
.ovr
.SetStandardFonts()
1308 self
.SetOverview(self
.overviewText
, mainOverview
)
1311 # Set up a log window
1312 self
.log
= wx
.TextCtrl(splitter2
, -1,
1313 style
= wx
.TE_MULTILINE|wx
.TE_READONLY|wx
.HSCROLL
)
1314 if wx
.Platform
== "__WXMAC__":
1315 self
.log
.MacCheckSpelling(False)
1317 # Set the wxWindows log target to be this textctrl
1318 #wx.Log_SetActiveTarget(wx.LogTextCtrl(self.log))
1320 # But instead of the above we want to show how to use our own wx.Log class
1321 wx
.Log_SetActiveTarget(MyLog(self
.log
))
1323 # for serious debugging
1324 #wx.Log_SetActiveTarget(wx.LogStderr())
1325 #wx.Log_SetTraceMask(wx.TraceMessages)
1328 self
.Bind(wx
.EVT_ACTIVATE
, self
.OnActivate
)
1329 wx
.GetApp().Bind(wx
.EVT_ACTIVATE_APP
, self
.OnAppActivate
)
1331 # add the windows to the splitter and split it.
1332 splitter2
.SplitHorizontally(self
.nb
, self
.log
, -160)
1333 leftBox
= wx
.BoxSizer(wx
.VERTICAL
)
1334 leftBox
.Add(self
.tree
, 1, wx
.EXPAND
)
1335 leftBox
.Add(wx
.StaticText(leftPanel
, label
= "Filter Demos:"), 0, wx
.TOP|wx
.LEFT
, 5)
1336 leftBox
.Add(self
.filter, 0, wx
.EXPAND|wx
.ALL
, 5)
1337 leftPanel
.SetSizer(leftBox
)
1338 splitter
.SplitVertically(leftPanel
, splitter2
, 220)
1340 splitter
.SetMinimumPaneSize(120)
1341 splitter2
.SetMinimumPaneSize(60)
1343 # Make the splitter on the right expand the top window when resized
1344 def SplitterOnSize(evt
):
1345 splitter
= evt
.GetEventObject()
1346 sz
= splitter
.GetSize()
1347 splitter
.SetSashPosition(sz
.height
- 160, False)
1350 splitter2
.Bind(wx
.EVT_SIZE
, SplitterOnSize
)
1352 # select initial items
1353 self
.nb
.SetSelection(0)
1354 self
.tree
.SelectItem(self
.root
)
1356 # Load 'Main' module
1357 self
.LoadDemo(self
.overviewText
)
1360 # select some other initial module?
1361 if len(sys
.argv
) > 1:
1363 if arg
.endswith('.py'):
1365 selectedDemo
= self
.treeMap
.get(arg
, None)
1367 self
.tree
.SelectItem(selectedDemo
)
1368 self
.tree
.EnsureVisible(selectedDemo
)
1371 #---------------------------------------------
1373 def RecreateTree(self
, evt
=None):
1374 self
.tree
.DeleteAllItems()
1375 self
.root
= self
.tree
.AddRoot("wxPython Overview")
1377 filter = self
.filter.GetValue()
1378 for category
, items
in _treeList
:
1380 items
= [item
for item
in items
if filter.lower() in item
.lower()]
1382 child
= self
.tree
.AppendItem(self
.root
, category
)
1383 if not firstChild
: firstChild
= child
1384 for childItem
in items
:
1385 theDemo
= self
.tree
.AppendItem(child
, childItem
)
1386 self
.treeMap
[childItem
] = theDemo
1388 self
.tree
.Expand(self
.root
)
1390 self
.tree
.Expand(firstChild
)
1393 def WriteText(self
, text
):
1394 if text
[-1:] == '\n':
1398 def write(self
, txt
):
1401 #---------------------------------------------
1402 def OnItemExpanded(self
, event
):
1403 item
= event
.GetItem()
1404 wx
.LogMessage("OnItemExpanded: %s" % self
.tree
.GetItemText(item
))
1407 #---------------------------------------------
1408 def OnItemCollapsed(self
, event
):
1409 item
= event
.GetItem()
1410 wx
.LogMessage("OnItemCollapsed: %s" % self
.tree
.GetItemText(item
))
1413 #---------------------------------------------
1414 def OnTreeLeftDown(self
, event
):
1415 # reset the overview text if the tree item is clicked on again
1416 pt
= event
.GetPosition();
1417 item
, flags
= self
.tree
.HitTest(pt
)
1418 if item
== self
.tree
.GetSelection():
1419 self
.SetOverview(self
.tree
.GetItemText(item
)+" Overview", self
.curOverview
)
1422 #---------------------------------------------
1423 def OnSelChanged(self
, event
):
1424 if self
.dying
or not self
.loaded
:
1427 item
= event
.GetItem()
1428 itemText
= self
.tree
.GetItemText(item
)
1429 self
.LoadDemo(itemText
)
1431 #---------------------------------------------
1432 def LoadDemo(self
, demoName
):
1434 wx
.BeginBusyCursor()
1437 self
.ShutdownDemoModule()
1439 if demoName
== self
.overviewText
:
1440 # User selected the "wxPython Overview" node
1442 # Changing the main window at runtime not yet supported...
1443 self
.demoModules
= DemoModules(__name__
)
1444 self
.SetOverview(self
.overviewText
, mainOverview
)
1445 self
.LoadDemoSource()
1446 self
.UpdateNotebook(0)
1448 if os
.path
.exists(GetOriginalFilename(demoName
)):
1449 wx
.LogMessage("Loading demo %s.py..." % demoName
)
1450 self
.demoModules
= DemoModules(demoName
)
1451 self
.LoadDemoSource()
1454 self
.SetOverview("wxPython", mainOverview
)
1455 self
.codePage
= None
1456 self
.UpdateNotebook(0)
1460 #---------------------------------------------
1461 def LoadDemoSource(self
):
1462 self
.codePage
= None
1463 self
.codePage
= DemoCodePanel(self
.nb
, self
)
1464 self
.codePage
.LoadDemo(self
.demoModules
)
1466 #---------------------------------------------
1467 def RunModule(self
):
1468 """Runs the active module"""
1470 module
= self
.demoModules
.GetActive()
1471 self
.ShutdownDemoModule()
1474 # o The RunTest() for all samples must now return a window that can
1475 # be palced in a tab in the main notebook.
1476 # o If an error occurs (or has occurred before) an error tab is created.
1478 if module
is not None:
1479 wx
.LogMessage("Running demo module...")
1480 if hasattr(module
, "overview"):
1481 overviewText
= module
.overview
1484 self
.demoPage
= module
.runTest(self
, self
.nb
, self
)
1486 self
.demoPage
= DemoErrorPanel(self
.nb
, self
.codePage
,
1487 DemoError(sys
.exc_info()), self
)
1489 assert self
.demoPage
is not None, "runTest must return a window!"
1492 # There was a previous error in compiling or exec-ing
1493 self
.demoPage
= DemoErrorPanel(self
.nb
, self
.codePage
,
1494 self
.demoModules
.GetErrorInfo(), self
)
1496 self
.SetOverview(self
.demoModules
.name
+ " Overview", overviewText
)
1499 # cahnge to the demo page the first time a module is run
1500 self
.UpdateNotebook(2)
1501 self
.firstTime
= False
1503 # otherwise just stay on the same tab in case the user has changed to another one
1504 self
.UpdateNotebook()
1506 #---------------------------------------------
1507 def ShutdownDemoModule(self
):
1509 # inform the window that it's time to quit if it cares
1510 if hasattr(self
.demoPage
, "ShutdownDemo"):
1511 self
.demoPage
.ShutdownDemo()
1512 wx
.YieldIfNeeded() # in case the page has pending events
1513 self
.demoPage
= None
1515 #---------------------------------------------
1516 def UpdateNotebook(self
, select
= -1):
1520 def UpdatePage(page
, pageText
):
1523 for i
in range(nb
.GetPageCount()):
1524 if nb
.GetPageText(i
) == pageText
:
1532 nb
.AddPage(page
, pageText
)
1533 if debug
: wx
.LogMessage("DBG: ADDED %s" % pageText
)
1535 if nb
.GetPage(pagePos
) != page
:
1536 # Reload an existing page
1538 nb
.DeletePage(pagePos
)
1539 nb
.InsertPage(pagePos
, page
, pageText
)
1541 if debug
: wx
.LogMessage("DBG: RELOADED %s" % pageText
)
1543 # Excellent! No redraw/flicker
1544 if debug
: wx
.LogMessage("DBG: SAVED from reloading %s" % pageText
)
1547 nb
.DeletePage(pagePos
)
1548 if debug
: wx
.LogMessage("DBG: DELETED %s" % pageText
)
1550 if debug
: wx
.LogMessage("DBG: STILL GONE - %s" % pageText
)
1553 select
= nb
.GetSelection()
1555 UpdatePage(self
.codePage
, "Demo Code")
1556 UpdatePage(self
.demoPage
, "Demo")
1558 if select
>= 0 and select
< nb
.GetPageCount():
1559 nb
.SetSelection(select
)
1561 #---------------------------------------------
1562 def SetOverview(self
, name
, text
):
1563 self
.curOverview
= text
1565 if lead
!= '<html>' and lead
!= '<HTML>':
1566 text
= '<br>'.join(text
.split('\n'))
1568 text
= text
.decode('iso8859_1')
1569 self
.ovr
.SetPage(text
)
1570 self
.nb
.SetPageText(0, name
)
1572 #---------------------------------------------
1574 def OnFileExit(self
, *event
):
1577 def OnToggleRedirect(self
, event
):
1581 print "Print statements and other standard output will now be directed to this window."
1584 print "Print statements and other standard output will now be sent to the usual location."
1586 def OnHelpAbout(self
, event
):
1587 from About
import MyAboutBox
1588 about
= MyAboutBox(self
)
1592 def OnHelpFind(self
, event
):
1593 if self
.finddlg
!= None:
1596 self
.nb
.SetSelection(1)
1597 self
.finddlg
= wx
.FindReplaceDialog(self
, self
.finddata
, "Find",
1598 wx
.FR_NOMATCHCASE | wx
.FR_NOWHOLEWORD
)
1599 self
.finddlg
.Show(True)
1602 def OnUpdateFindItems(self
, evt
):
1603 evt
.Enable(self
.finddlg
== None)
1606 def OnFind(self
, event
):
1607 editor
= self
.codePage
.editor
1608 self
.nb
.SetSelection(1)
1609 end
= editor
.GetLastPosition()
1610 textstring
= editor
.GetRange(0, end
).lower()
1611 findstring
= self
.finddata
.GetFindString().lower()
1612 backward
= not (self
.finddata
.GetFlags() & wx
.FR_DOWN
)
1614 start
= editor
.GetSelection()[0]
1615 loc
= textstring
.rfind(findstring
, 0, start
)
1617 start
= editor
.GetSelection()[1]
1618 loc
= textstring
.find(findstring
, start
)
1619 if loc
== -1 and start
!= 0:
1620 # string not found, start at beginning
1623 loc
= textstring
.rfind(findstring
, 0, start
)
1626 loc
= textstring
.find(findstring
, start
)
1628 dlg
= wx
.MessageDialog(self
, 'Find String Not Found',
1629 'Find String Not Found in Demo File',
1630 wx
.OK | wx
.ICON_INFORMATION
)
1635 self
.finddlg
.SetFocus()
1638 self
.finddlg
.Destroy()
1640 editor
.ShowPosition(loc
)
1641 editor
.SetSelection(loc
, loc
+ len(findstring
))
1645 def OnFindNext(self
, event
):
1646 if self
.finddata
.GetFindString():
1649 self
.OnHelpFind(event
)
1651 def OnFindClose(self
, event
):
1652 event
.GetDialog().Destroy()
1656 def OnOpenShellWindow(self
, evt
):
1658 # if it already exists then just make sure it's visible
1664 # Make a PyShell window
1666 namespace
= { 'wx' : wx
,
1667 'app' : wx
.GetApp(),
1670 self
.shell
= py
.shell
.ShellFrame(None, locals=namespace
)
1671 self
.shell
.SetSize((640,480))
1674 # Hook the close event of the main frame window so that we
1675 # close the shell at the same time if it still exists
1676 def CloseShell(evt
):
1680 self
.Bind(wx
.EVT_CLOSE
, CloseShell
)
1683 #---------------------------------------------
1684 def OnCloseWindow(self
, event
):
1686 self
.demoPage
= None
1687 self
.codePage
= None
1688 self
.mainmenu
= None
1689 if self
.tbicon
is not None:
1690 self
.tbicon
.Destroy()
1694 #---------------------------------------------
1695 def OnIdle(self
, event
):
1697 self
.otherWin
.Raise()
1698 self
.demoPage
= self
.otherWin
1699 self
.otherWin
= None
1702 #---------------------------------------------
1705 showTipText
= open(opj("data/showTips")).read()
1706 showTip
, index
= eval(showTipText
)
1708 showTip
, index
= (1, 0)
1710 tp
= wx
.CreateFileTipProvider(opj("data/tips.txt"), index
)
1712 showTip
= wx
.ShowTip(self
, tp
)
1713 index
= tp
.GetCurrentTip()
1714 open(opj("data/showTips"), "w").write(str( (showTip
, index
) ))
1717 #---------------------------------------------
1718 def OnDemoMenu(self
, event
):
1720 selectedDemo
= self
.treeMap
[self
.mainmenu
.GetLabel(event
.GetId())]
1724 self
.tree
.SelectItem(selectedDemo
)
1725 self
.tree
.EnsureVisible(selectedDemo
)
1729 #---------------------------------------------
1730 def OnIconfiy(self
, evt
):
1731 wx
.LogMessage("OnIconfiy: %s" % evt
.Iconized())
1734 #---------------------------------------------
1735 def OnMaximize(self
, evt
):
1736 wx
.LogMessage("OnMaximize")
1739 #---------------------------------------------
1740 def OnActivate(self
, evt
):
1741 wx
.LogMessage("OnActivate: %s" % evt
.GetActive())
1744 #---------------------------------------------
1745 def OnAppActivate(self
, evt
):
1746 wx
.LogMessage("OnAppActivate: %s" % evt
.GetActive())
1749 #---------------------------------------------------------------------------
1750 #---------------------------------------------------------------------------
1752 class MySplashScreen(wx
.SplashScreen
):
1754 bmp
= wx
.Image(opj("bitmaps/splash.png")).ConvertToBitmap()
1755 wx
.SplashScreen
.__init
__(self
, bmp
,
1756 wx
.SPLASH_CENTRE_ON_SCREEN | wx
.SPLASH_TIMEOUT
,
1758 self
.Bind(wx
.EVT_CLOSE
, self
.OnClose
)
1759 self
.fc
= wx
.FutureCall(2000, self
.ShowMain
)
1762 def OnClose(self
, evt
):
1763 # Make sure the default handler runs too so this window gets
1768 # if the timer is still running then go ahead and show the
1770 if self
.fc
.IsRunning():
1776 frame
= wxPythonDemo(None, "wxPython: (A Demonstration)")
1778 if self
.fc
.IsRunning():
1781 import wx
.lib
.mixins
.inspect
1783 class MyApp(wx
.App
, wx
.lib
.mixins
.inspect
.InspectionMixin
):
1786 Create and show the splash screen. It will then create and show
1787 the main frame when it is time to do so.
1790 wx
.SystemOptions
.SetOptionInt("mac.window-plain-transition", 1)
1793 #self.SetAssertMode(wx.PYAPP_ASSERT_DIALOG)
1795 # Normally when using a SplashScreen you would create it, show
1796 # it and then continue on with the applicaiton's
1797 # initialization, finally creating and showing the main
1798 # application window(s). In this case we have nothing else to
1799 # do so we'll delay showing the main frame until later (see
1800 # ShowMain above) so the users can see the SplashScreen effect.
1801 splash
= MySplashScreen()
1804 # Setup the InspectionMixin
1811 #---------------------------------------------------------------------------
1815 demoPath
= os
.path
.dirname(__file__
)
1822 #---------------------------------------------------------------------------
1825 mainOverview
= """<html><body>
1828 <p> wxPython is a <b>GUI toolkit</b> for the Python programming
1829 language. It allows Python programmers to create programs with a
1830 robust, highly functional graphical user interface, simply and easily.
1831 It is implemented as a Python extension module (native code) that
1832 wraps the popular wxWindows cross platform GUI library, which is
1835 <p> Like Python and wxWindows, wxPython is <b>Open Source</b> which
1836 means that it is free for anyone to use and the source code is
1837 available for anyone to look at and modify. Or anyone can contribute
1838 fixes or enhancements to the project.
1840 <p> wxPython is a <b>cross-platform</b> toolkit. This means that the
1841 same program will run on multiple platforms without modification.
1842 Currently supported platforms are 32-bit Microsoft Windows, most Unix
1843 or unix-like systems, and Macintosh OS X. Since the language is
1844 Python, wxPython programs are <b>simple, easy</b> to write and easy to
1847 <p> <b>This demo</b> is not only a collection of test cases for
1848 wxPython, but is also designed to help you learn about and how to use
1849 wxPython. Each sample is listed in the tree control on the left.
1850 When a sample is selected in the tree then a module is loaded and run
1851 (usually in a tab of this notebook,) and the source code of the module
1852 is loaded in another tab for you to browse and learn from.
1857 #----------------------------------------------------------------------------
1858 #----------------------------------------------------------------------------
1860 if __name__
== '__main__':
1864 #----------------------------------------------------------------------------