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 #----------------------------------------------------------------------------
16 import wx
# This module uses the new wx namespace
23 ##print os.getpid(); raw_input("Press a key...")
26 # Use Python's bool constants if available, make aliases if not
30 __builtins__
.True = 1==1
31 __builtins__
.False = 1==0
33 #---------------------------------------------------------------------------
38 ('Recent Additions', [
43 'wxXmlResourceSubclass',
47 # managed windows == things with a (optional) caption you can close
48 ('Base Frames and Dialogs', [
62 'wxFindReplaceDialog',
68 'wxSingleChoiceDialog',
72 # dialogs from libraries
76 'wxMultipleChoiceDialog',
77 'wxScrolledMessageDialog',
81 ('Core Windows/Controls', [
116 ('Custom Controls', [
129 # controls coming from other libraries
130 ('More Windows/Controls', [
131 #'wxFloatBar', deprecated
132 #'wxMVCTree', deprecated
133 #'wxRightTextCtrl', deprecated as we have wxTE_RIGHT now.
138 'MaskedEditControls',
146 'wxDynamicSashWindow',
151 'wxMimeTypesManager',
153 'wxStyledTextCtrl_1',
154 'wxStyledTextCtrl_2',
159 # How to lay out the controls in a frame/dialog
166 'wxLayoutConstraints',
169 'wxXmlResourceHandler',
170 'wxXmlResourceSubclass',
174 ('Process and Events', [
186 ('Clipboard and DnD', [
219 # need libs not coming with the demo
220 ('Objects using an external library', [
221 'ActiveXWrapper_Acrobat',
228 ('Check out the samples dir too', [
235 #---------------------------------------------------------------------------
236 # Show how to derive a custom wxLog class
238 class MyLog(wx
.PyLog
):
239 def __init__(self
, textCtrl
, logTime
=0):
240 wx
.PyLog
.__init
__(self
)
242 self
.logTime
= logTime
244 def DoLogString(self
, message
, timeStamp
):
246 message
= time
.strftime("%X", time
.localtime(timeStamp
)) + \
249 self
.tc
.AppendText(message
+ '\n')
252 class MyTP(wx
.PyTipProvider
):
254 return "This is my tip"
256 #---------------------------------------------------------------------------
257 # A class to be used to display source code in the demo. Try using the
258 # wxSTC in the wxStyledTextCtrl_2 sample first, fall back to wxTextCtrl
259 # if there is an error, such as the stc module not being present.
265 from wxStyledTextCtrl_2
import PythonSTC
266 class DemoCodeViewer(PythonSTC
):
267 def __init__(self
, parent
, ID
):
268 PythonSTC
.__init
__(self
, parent
, ID
)
269 self
.SetEdgeMode(stc
.STC_EDGE_NONE
)
270 self
.SetSelBackground(True, wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_HIGHLIGHT
))
271 self
.SetSelForeground(True, wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_HIGHLIGHTTEXT
))
273 # Some methods to make it compatible with how the wxTextCtrl is used
274 def SetValue(self
, value
):
275 self
.SetReadOnly(False)
277 self
.SetReadOnly(True)
282 def SetInsertionPoint(self
, pos
):
283 self
.SetCurrentPos(pos
)
285 def ShowPosition(self
, pos
):
288 def GetLastPosition(self
):
289 return self
.GetLength()
291 def GetRange(self
, start
, end
):
292 return self
.GetTextRange(start
, end
)
294 def GetSelection(self
):
295 return self
.GetAnchor(), self
.GetCurrentPos()
297 def SetSelection(self
, start
, end
):
298 self
.SetSelectionStart(start
)
299 self
.SetSelectionEnd(end
)
303 class DemoCodeViewer(wx
.TextCtrl
):
304 def __init__(self
, parent
, ID
):
305 wx
.TextCtrl
.__init
__(self
, parent
, ID
, style
=
306 wx
.TE_MULTILINE | wx
.TE_READONLY |
307 wx
.HSCROLL | wx
.TE_RICH2 | wx
.TE_NOHIDESEL
)
310 #---------------------------------------------------------------------------
313 """Convert paths to the platform-specific separator"""
314 return apply(os
.path
.join
, tuple(path
.split('/')))
317 #---------------------------------------------------------------------------
319 class wxPythonDemo(wx
.Frame
):
320 overviewText
= "wxPython Overview"
322 def __init__(self
, parent
, id, title
):
323 wx
.Frame
.__init
__(self
, parent
, -1, title
, size
= (800, 600),
324 style
=wx
.DEFAULT_FRAME_STYLE|wx
.NO_FULL_REPAINT_ON_RESIZE
)
326 self
.cwd
= os
.getcwd()
327 self
.curOverview
= ""
330 icon
= images
.getMondrianIcon()
333 if wx
.Platform
== '__WXMSW__':
334 # setup a taskbar icon, and catch some events from it
335 self
.tbicon
= wx
.TaskBarIcon()
336 self
.tbicon
.SetIcon(icon
, "wxPython Demo")
337 wx
.EVT_TASKBAR_LEFT_DCLICK(self
.tbicon
, self
.OnTaskBarActivate
)
338 wx
.EVT_TASKBAR_RIGHT_UP(self
.tbicon
, self
.OnTaskBarMenu
)
339 wx
.EVT_MENU(self
.tbicon
, self
.TBMENU_RESTORE
, self
.OnTaskBarActivate
)
340 wx
.EVT_MENU(self
.tbicon
, self
.TBMENU_CLOSE
, self
.OnTaskBarClose
)
342 wx
.CallAfter(self
.ShowTip
)
345 wx
.EVT_IDLE(self
, self
.OnIdle
)
346 wx
.EVT_CLOSE(self
, self
.OnCloseWindow
)
347 wx
.EVT_ICONIZE(self
, self
.OnIconfiy
)
348 wx
.EVT_MAXIMIZE(self
, self
.OnMaximize
)
351 self
.CreateStatusBar(1, wx
.ST_SIZEGRIP
)
353 splitter
= wx
.SplitterWindow(self
, -1)
354 splitter2
= wx
.SplitterWindow(splitter
, -1)
356 def EmptyHandler(evt
): pass
357 #wx.EVT_ERASE_BACKGROUND(splitter, EmptyHandler)
358 #wx.EVT_ERASE_BACKGROUND(splitter2, EmptyHandler)
360 # Prevent TreeCtrl from displaying all items after destruction when True
364 self
.mainmenu
= wx
.MenuBar()
367 menu
.Append(exitID
, 'E&xit\tAlt-X', 'Get the heck outta here!')
368 wx
.EVT_MENU(self
, exitID
, self
.OnFileExit
)
369 wx
.App_SetMacExitMenuItemId(exitID
)
370 self
.mainmenu
.Append(menu
, '&File')
374 for item
in _treeList
:
376 for childItem
in item
[1]:
378 submenu
.Append(mID
, childItem
)
379 wx
.EVT_MENU(self
, mID
, self
.OnDemoMenu
)
380 menu
.AppendMenu(wx
.NewId(), item
[0], submenu
)
381 self
.mainmenu
.Append(menu
, '&Demo')
387 findnextID
= wx
.NewId()
389 menu
.Append(findID
, '&Find\tCtrl-F', 'Find in the Demo Code')
390 menu
.Append(findnextID
, 'Find &Next\tF3', 'Find Next')
391 menu
.AppendSeparator()
392 menu
.Append(helpID
, '&About\tCtrl-H', 'wxPython RULES!!!')
393 wx
.App_SetMacAboutMenuItemId(helpID
)
394 wx
.EVT_MENU(self
, helpID
, self
.OnHelpAbout
)
395 wx
.EVT_MENU(self
, findID
, self
.OnHelpFind
)
396 wx
.EVT_MENU(self
, findnextID
, self
.OnFindNext
)
397 wx
.EVT_COMMAND_FIND(self
, -1, self
.OnFind
)
398 wx
.EVT_COMMAND_FIND_NEXT(self
, -1, self
.OnFind
)
399 wx
.EVT_COMMAND_FIND_CLOSE(self
, -1 , self
.OnFindClose
)
400 self
.mainmenu
.Append(menu
, '&Help')
401 self
.SetMenuBar(self
.mainmenu
)
403 self
.finddata
= wx
.FindReplaceData()
406 # This is another way to set Accelerators, in addition to
407 # using the '\t<key>' syntax in the menu items.
408 aTable
= wx
.AcceleratorTable([(wx
.ACCEL_ALT
, ord('X'), exitID
),
409 (wx
.ACCEL_CTRL
, ord('H'), helpID
),
410 (wx
.ACCEL_CTRL
, ord('F'), findID
),
411 (wx
.ACCEL_NORMAL
, WXK_F3
, findnextID
)
413 self
.SetAcceleratorTable(aTable
)
419 self
.tree
= wx
.TreeCtrl(splitter
, tID
, style
=
420 wx
.TR_DEFAULT_STYLE
#| wx.TR_HAS_VARIABLE_ROW_HEIGHT
423 root
= self
.tree
.AddRoot("wxPython Overview")
425 for item
in _treeList
:
426 child
= self
.tree
.AppendItem(root
, item
[0])
427 if not firstChild
: firstChild
= child
428 for childItem
in item
[1]:
429 theDemo
= self
.tree
.AppendItem(child
, childItem
)
430 self
.treeMap
[childItem
] = theDemo
432 self
.tree
.Expand(root
)
433 self
.tree
.Expand(firstChild
)
434 wx
.EVT_TREE_ITEM_EXPANDED (self
.tree
, tID
, self
.OnItemExpanded
)
435 wx
.EVT_TREE_ITEM_COLLAPSED (self
.tree
, tID
, self
.OnItemCollapsed
)
436 wx
.EVT_TREE_SEL_CHANGED (self
.tree
, tID
, self
.OnSelChanged
)
437 wx
.EVT_LEFT_DOWN (self
.tree
, self
.OnTreeLeftDown
)
440 self
.nb
= wx
.Notebook(splitter2
, -1, style
=wx
.CLIP_CHILDREN
)
442 # Set up a wx.html.HtmlWindow on the Overview Notebook page
443 # we put it in a panel first because there seems to be a
444 # refresh bug of some sort (wxGTK) when it is directly in
447 self
.ovr
= wx
.html
.HtmlWindow(self
.nb
, -1, size
=(400, 400))
448 self
.nb
.AddPage(self
.ovr
, self
.overviewText
)
450 else: # hopefully I can remove this hacky code soon, see SF bug #216861
451 panel
= wx
.Panel(self
.nb
, -1, style
=wx
.CLIP_CHILDREN
)
452 self
.ovr
= wx
.html
.HtmlWindow(panel
, -1, size
=(400, 400))
453 self
.nb
.AddPage(panel
, self
.overviewText
)
455 def OnOvrSize(evt
, ovr
=self
.ovr
):
456 ovr
.SetSize(evt
.GetSize())
458 wx
.EVT_SIZE(panel
, OnOvrSize
)
459 wx
.EVT_ERASE_BACKGROUND(panel
, EmptyHandler
)
462 self
.SetOverview(self
.overviewText
, overview
)
465 # Set up a notebook page for viewing the source code of each sample
466 self
.txt
= DemoCodeViewer(self
.nb
, -1)
467 self
.nb
.AddPage(self
.txt
, "Demo Code")
468 self
.GetDemoFile('Main.py')
471 # Set up a log on the View Log Notebook page
472 self
.log
= wx
.TextCtrl(splitter2
, -1,
473 style
= wx
.TE_MULTILINE|wx
.TE_READONLY|wx
.HSCROLL
)
475 # Set the wxWindows log target to be this textctrl
476 #wx.Log_SetActiveTarget(wx.LogTextCtrl(self.log))
478 # But instead of the above we want to show how to use our own wx.Log class
479 wx
.Log_SetActiveTarget(MyLog(self
.log
))
481 # for serious debugging
482 #wx.Log_SetActiveTarget(wx.LogStderr())
483 #wx.Log_SetTraceMask(wx.TraceMessages)
488 # add the windows to the splitter and split it.
489 splitter2
.SplitHorizontally(self
.nb
, self
.log
, -120)
490 splitter
.SplitVertically(self
.tree
, splitter2
, 180)
492 splitter
.SetMinimumPaneSize(20)
493 splitter2
.SetMinimumPaneSize(20)
496 # Make the splitter on the right expand the top wind when resized
497 def SplitterOnSize(evt
):
498 splitter
= evt
.GetEventObject()
499 sz
= splitter
.GetSize()
500 splitter
.SetSashPosition(sz
.height
- 120, False)
502 wx
.EVT_SIZE(splitter2
, SplitterOnSize
)
505 # select initial items
506 self
.nb
.SetSelection(0)
507 self
.tree
.SelectItem(root
)
509 if len(sys
.argv
) == 2:
511 selectedDemo
= self
.treeMap
[sys
.argv
[1]]
515 self
.tree
.SelectItem(selectedDemo
)
516 self
.tree
.EnsureVisible(selectedDemo
)
519 wx
.LogMessage('window handle: %s' % self
.GetHandle())
522 #---------------------------------------------
523 def WriteText(self
, text
):
524 if text
[-1:] == '\n':
529 def write(self
, txt
):
532 #---------------------------------------------
533 def OnItemExpanded(self
, event
):
534 item
= event
.GetItem()
535 wx
.LogMessage("OnItemExpanded: %s" % self
.tree
.GetItemText(item
))
538 #---------------------------------------------
539 def OnItemCollapsed(self
, event
):
540 item
= event
.GetItem()
541 wx
.LogMessage("OnItemCollapsed: %s" % self
.tree
.GetItemText(item
))
544 #---------------------------------------------
545 def OnTreeLeftDown(self
, event
):
546 pt
= event
.GetPosition();
547 item
, flags
= self
.tree
.HitTest(pt
)
548 if item
== self
.tree
.GetSelection():
549 self
.SetOverview(self
.tree
.GetItemText(item
)+" Overview", self
.curOverview
)
552 #---------------------------------------------
553 def OnSelChanged(self
, event
):
557 item
= event
.GetItem()
558 itemText
= self
.tree
.GetItemText(item
)
559 self
.RunDemo(itemText
)
562 #---------------------------------------------
563 def RunDemo(self
, itemText
):
565 if self
.nb
.GetPageCount() == 3:
566 if self
.nb
.GetSelection() == 2:
567 self
.nb
.SetSelection(0)
568 # inform the window that it's time to quit if it cares
569 if self
.window
is not None:
570 if hasattr(self
.window
, "ShutdownDemo"):
571 self
.window
.ShutdownDemo()
572 wx
.SafeYield() # in case the page has pending events
573 self
.nb
.DeletePage(2)
575 if itemText
== self
.overviewText
:
576 self
.GetDemoFile('Main.py')
577 self
.SetOverview(self
.overviewText
, overview
)
582 if os
.path
.exists(itemText
+ '.py'):
584 wx
.LogMessage("Running demo %s.py..." % itemText
)
586 self
.GetDemoFile(itemText
+ '.py')
587 module
= __import__(itemText
, globals())
588 self
.SetOverview(itemText
+ " Overview", module
.overview
)
593 # in case runTest is modal, make sure things look right...
597 self
.window
= module
.runTest(self
, self
.nb
, self
) ###
598 if self
.window
is not None:
599 self
.nb
.AddPage(self
.window
, 'Demo')
600 self
.nb
.SetSelection(2)
601 self
.nb
.Refresh() # without this wxMac has troubles showing the just added page
610 #---------------------------------------------
612 def GetDemoFile(self
, filename
):
615 self
.txt
.SetValue(open(filename
).read())
617 self
.txt
.SetValue("Cannot open %s file." % filename
)
619 self
.txt
.SetInsertionPoint(0)
620 self
.txt
.ShowPosition(0)
622 #---------------------------------------------
623 def SetOverview(self
, name
, text
):
624 self
.curOverview
= text
626 if lead
!= '<html>' and lead
!= '<HTML>':
627 text
= '<br>'.join(text
.split('\n'))
628 self
.ovr
.SetPage(text
)
629 self
.nb
.SetPageText(0, name
)
631 #---------------------------------------------
633 def OnFileExit(self
, *event
):
636 def OnHelpAbout(self
, event
):
637 from About
import MyAboutBox
638 about
= MyAboutBox(self
)
642 def OnHelpFind(self
, event
):
643 self
.nb
.SetSelection(1)
644 self
.finddlg
= wx
.FindReplaceDialog(self
, self
.finddata
, "Find",
648 self
.finddlg
.Show(True)
650 def OnFind(self
, event
):
651 self
.nb
.SetSelection(1)
652 end
= self
.txt
.GetLastPosition()
653 textstring
= self
.txt
.GetRange(0, end
).lower()
654 start
= self
.txt
.GetSelection()[1]
655 findstring
= self
.finddata
.GetFindString().lower()
656 loc
= textstring
.find(findstring
, start
)
657 if loc
== -1 and start
!= 0:
658 # string not found, start at beginning
660 loc
= textstring
.find(findstring
, start
)
662 dlg
= wx
.MessageDialog(self
, 'Find String Not Found',
663 'Find String Not Found in Demo File',
664 wx
.OK | wx
.ICON_INFORMATION
)
669 self
.finddlg
.SetFocus()
672 self
.finddlg
.Destroy()
673 self
.txt
.ShowPosition(loc
)
674 self
.txt
.SetSelection(loc
, loc
+ len(findstring
))
678 def OnFindNext(self
, event
):
679 if self
.finddata
.GetFindString():
682 self
.OnHelpFind(event
)
684 def OnFindClose(self
, event
):
685 event
.GetDialog().Destroy()
688 #---------------------------------------------
689 def OnCloseWindow(self
, event
):
693 if hasattr(self
, "tbicon"):
698 #---------------------------------------------
699 def OnIdle(self
, event
):
701 self
.otherWin
.Raise()
702 self
.window
= self
.otherWin
706 #---------------------------------------------
709 showTipText
= open(opj("data/showTips")).read()
710 showTip
, index
= eval(showTipText
)
712 showTip
, index
= (1, 0)
714 tp
= wx
.CreateFileTipProvider(opj("data/tips.txt"), index
)
716 showTip
= wx
.ShowTip(self
, tp
)
717 index
= tp
.GetCurrentTip()
718 open(opj("data/showTips"), "w").write(str( (showTip
, index
) ))
721 #---------------------------------------------
722 def OnDemoMenu(self
, event
):
724 selectedDemo
= self
.treeMap
[self
.mainmenu
.GetLabel(event
.GetId())]
728 self
.tree
.SelectItem(selectedDemo
)
729 self
.tree
.EnsureVisible(selectedDemo
)
732 #---------------------------------------------
733 def OnTaskBarActivate(self
, evt
):
734 if self
.IsIconized():
736 if not self
.IsShown():
740 #---------------------------------------------
742 TBMENU_RESTORE
= 1000
745 def OnTaskBarMenu(self
, evt
):
747 menu
.Append(self
.TBMENU_RESTORE
, "Restore wxPython Demo")
748 menu
.Append(self
.TBMENU_CLOSE
, "Close")
749 self
.tbicon
.PopupMenu(menu
)
752 #---------------------------------------------
753 def OnTaskBarClose(self
, evt
):
756 # because of the way wx.TaskBarIcon.PopupMenu is implemented we have to
757 # prod the main idle handler a bit to get the window to actually close
758 wx
.GetApp().ProcessIdle()
761 #---------------------------------------------
762 def OnIconfiy(self
, evt
):
763 wx
.LogMessage("OnIconfiy")
766 #---------------------------------------------
767 def OnMaximize(self
, evt
):
768 wx
.LogMessage("OnMaximize")
774 #---------------------------------------------------------------------------
775 #---------------------------------------------------------------------------
777 class MySplashScreen(wx
.SplashScreen
):
779 bmp
= wx
.Image(opj("bitmaps/splash.gif")).ConvertToBitmap()
780 wx
.SplashScreen
.__init
__(self
, bmp
,
781 wx
.SPLASH_CENTRE_ON_SCREEN|wx
.SPLASH_TIMEOUT
,
783 style
= wx
.SIMPLE_BORDER|wx
.FRAME_NO_TASKBAR|wx
.STAY_ON_TOP
)
784 wx
.EVT_CLOSE(self
, self
.OnClose
)
786 def OnClose(self
, evt
):
787 frame
= wxPythonDemo(None, -1, "wxPython: (A Demonstration)")
789 evt
.Skip() # Make sure the default handler runs too...
795 Create and show the splash screen. It will then create and show
796 the main frame when it is time to do so.
800 #self.locale = wx.Locale(wx.LANGUAGE_FRENCH)
801 #locale.setlocale(locale.LC_ALL, 'fr')
803 wx
.InitAllImageHandlers()
804 splash
= MySplashScreen()
810 #---------------------------------------------------------------------------
814 demoPath
= os
.path
.dirname(__file__
)
818 app
= MyApp(0) #wx.Platform == "__WXMAC__")
822 #---------------------------------------------------------------------------
826 overview
= """<html><body>
829 <p> wxPython is a <b>GUI toolkit</b> for the <a
830 href="http://www.python.org/">Python</a> programming language. It
831 allows Python programmers to create programs with a robust, highly
832 functional graphical user interface, simply and easily. It is
833 implemented as a Python extension module (native code) that wraps the
834 popular <a href="http://wxwindows.org/front.htm">wxWindows</a> cross
835 platform GUI library, which is written in C++.
837 <p> Like Python and wxWindows, wxPython is <b>Open Source</b> which
838 means that it is free for anyone to use and the source code is
839 available for anyone to look at and modify. Or anyone can contribute
840 fixes or enhancements to the project.
842 <p> wxPython is a <b>cross-platform</b> toolkit. This means that the
843 same program will run on multiple platforms without modification.
844 Currently supported platforms are 32-bit Microsoft Windows, most Unix
845 or unix-like systems, and Macintosh OS X. Since the language is
846 Python, wxPython programs are <b>simple, easy</b> to write and easy to
849 <p> <b>This demo</b> is not only a collection of test cases for
850 wxPython, but is also designed to help you learn about and how to use
851 wxPython. Each sample is listed in the tree control on the left.
852 When a sample is selected in the tree then a module is loaded and run
853 (usually in a tab of this notebook,) and the source code of the module
854 is loaded in another tab for you to browse and learn from.
859 #----------------------------------------------------------------------------
860 #----------------------------------------------------------------------------
862 if __name__
== '__main__':
865 #----------------------------------------------------------------------------