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 #----------------------------------------------------------------------------
14 import sys
, os
, time
, string
15 from wxPython
.wx
import *
16 from wxPython
.html
import wxHtmlWindow
20 #---------------------------------------------------------------------------
24 ## ('New since last release', ['wxGenericDirCtrl',
25 ## 'wxImageFromStream',
31 ## ('Windows', ['wxFrame', 'wxDialog', 'wxMiniFrame',
32 ## 'wxGrid', 'wxSashWindow',
33 ## 'wxScrolledWindow', 'wxSplitterWindow',
34 ## 'wxStatusBar', 'wxNotebook',
36 ## 'wxStyledTextCtrl_1', 'wxStyledTextCtrl_2',
38 ## 'wxDynamicSashWindow',
41 ## ('Common Dialogs', ['wxColourDialog', 'wxDirDialog', 'wxFileDialog',
42 ## 'wxSingleChoiceDialog', 'wxTextEntryDialog',
43 ## 'wxFontDialog', 'wxPageSetupDialog', 'wxPrintDialog',
44 ## 'wxMessageDialog', 'wxProgressDialog', 'wxFindReplaceDialog',
47 ## ('Controls', ['wxButton', 'wxCheckBox', 'wxCheckListBox', 'wxChoice',
48 ## 'wxComboBox', 'wxGauge', 'wxListBox', 'wxListCtrl', 'VirtualListCtrl',
50 ## 'wxTreeCtrl', 'wxSpinButton', 'wxSpinCtrl', 'wxStaticText',
51 ## 'wxStaticBitmap', 'wxRadioBox', 'wxSlider', 'wxToolBar',
52 ## 'wxCalendarCtrl', 'wxToggleButton',
53 ## 'wxEditableListBox', 'wxLEDNumberCtrl',
56 ## ('Window Layout', ['wxLayoutConstraints', 'LayoutAnchors', 'Sizers', 'XML_Resource',
60 ## ('Miscellaneous', [ 'DragAndDrop', 'CustomDragAndDrop', 'URLDragAndDrop',
62 ## 'wxTimer', 'wxValidator', 'wxGLCanvas', 'DialogUnits',
63 ## 'wxImage', 'wxMask', 'PrintFramework', 'wxOGL',
64 ## 'PythonEvents', 'Threads',
65 ## 'ActiveXWrapper_Acrobat', 'ActiveXWrapper_IE',
66 ## 'wxDragImage', "wxProcess", "FancyText", "OOR", "wxWave",
67 ## 'wxJoystick', 'DrawXXXList', 'ErrorDialogs', 'wxMimeTypesManager',
68 ## 'ContextHelp', 'SplitTree', 'Unicode', 'wxFileHistory',
71 ## ('wxPython Library', ['Layoutf', 'wxScrolledMessageDialog',
72 ## 'wxMultipleChoiceDialog', 'wxPlotCanvas', 'wxFloatBar',
73 ## 'wxCalendar', 'wxMVCTree', 'wxVTKRenderWindow',
74 ## 'FileBrowseButton', 'GenericButtons', 'wxEditor',
75 ## 'ColourSelect', 'ImageBrowser',
76 ## 'infoframe', 'ColourDB', 'PyCrust', 'PyCrustWithFilling',
81 ## ('Cool Contribs', ['pyTree', 'hangman',
91 ('New since last release', [
99 # managed windows == things with a caption you can close
100 ('Base Frames and Dialogs', [
112 'wxFindReplaceDialog',
118 'wxSingleChoiceDialog',
122 # dialogs form libraries
126 'wxMultipleChoiceDialog',
127 'wxScrolledMessageDialog',
131 ('Core Windows/Controls', [
163 # controls coming from other librairies
164 ('More Windows/Controls', [
171 'PyCrustWithFilling',
176 'wxDynamicSashWindow',
182 'wxMimeTypesManager',
184 'wxStyledTextCtrl_1',
185 'wxStyledTextCtrl_2',
189 # How to lay out the controls in a frame/dialog
195 'wxLayoutConstraints',
200 ('Process and Events', [
210 ('Clipboard and DnD', [
238 # need libs not coming with the demo
239 ('Objects using an external library', [
240 'ActiveXWrapper_Acrobat',
247 # pyTree, hangman, ... in the samples dir
248 ('Check out the samples dir too', [
251 #~ ('Cool Contribs', [
261 #---------------------------------------------------------------------------
263 class MyLog(wxPyLog
):
264 def __init__(self
, textCtrl
, logTime
=0):
265 wxPyLog
.__init
__(self
)
267 self
.logTime
= logTime
269 def DoLogString(self
, message
, timeStamp
):
271 message
= time
.strftime("%X", time
.localtime(timeStamp
)) + \
273 self
.tc
.AppendText(message
+ '\n')
276 #---------------------------------------------------------------------------
279 """Convert paths to the platform-specific separator"""
280 return apply(os
.path
.join
, tuple(string
.split(path
, '/')))
283 #---------------------------------------------------------------------------
285 class wxPythonDemo(wxFrame
):
286 overviewText
= "wxPython Overview"
288 def __init__(self
, parent
, id, title
):
289 wxFrame
.__init
__(self
, parent
, -1, title
, size
= (800, 600),
290 style
=wxDEFAULT_FRAME_STYLE|wxNO_FULL_REPAINT_ON_RESIZE
)
292 self
.cwd
= os
.getcwd()
293 self
.curOverview
= ""
295 icon
= images
.getMondrianIcon()
298 if wxPlatform
== '__WXMSW__':
299 # setup a taskbar icon, and catch some events from it
300 self
.tbicon
= wxTaskBarIcon()
301 self
.tbicon
.SetIcon(icon
, "wxPython Demo")
302 EVT_TASKBAR_LEFT_DCLICK(self
.tbicon
, self
.OnTaskBarActivate
)
303 EVT_TASKBAR_RIGHT_UP(self
.tbicon
, self
.OnTaskBarMenu
)
304 EVT_MENU(self
.tbicon
, self
.TBMENU_RESTORE
, self
.OnTaskBarActivate
)
305 EVT_MENU(self
.tbicon
, self
.TBMENU_CLOSE
, self
.OnTaskBarClose
)
310 EVT_IDLE(self
, self
.OnIdle
)
311 EVT_CLOSE(self
, self
.OnCloseWindow
)
312 EVT_ICONIZE(self
, self
.OnIconfiy
)
313 EVT_MAXIMIZE(self
, self
.OnMaximize
)
316 self
.CreateStatusBar(1, wxST_SIZEGRIP
)
318 splitter
= wxSplitterWindow(self
, -1, style
=wxNO_3D|wxSP_3D
)
319 splitter2
= wxSplitterWindow(splitter
, -1, style
=wxNO_3D|wxSP_3D
)
321 def EmptyHandler(evt
): pass
322 EVT_ERASE_BACKGROUND(splitter
, EmptyHandler
)
323 EVT_ERASE_BACKGROUND(splitter2
, EmptyHandler
)
325 # Prevent TreeCtrl from displaying all items after destruction when true
329 self
.mainmenu
= wxMenuBar()
332 menu
.Append(exitID
, 'E&xit\tAlt-X', 'Get the heck outta here!')
333 EVT_MENU(self
, exitID
, self
.OnFileExit
)
334 self
.mainmenu
.Append(menu
, '&File')
338 for item
in _treeList
:
340 for childItem
in item
[1]:
342 submenu
.Append(mID
, childItem
)
343 EVT_MENU(self
, mID
, self
.OnDemoMenu
)
344 menu
.AppendMenu(wxNewId(), item
[0], submenu
)
345 self
.mainmenu
.Append(menu
, '&Demo')
351 menu
.Append(helpID
, '&About\tCtrl-H', 'wxPython RULES!!!')
352 EVT_MENU(self
, helpID
, self
.OnHelpAbout
)
353 self
.mainmenu
.Append(menu
, '&Help')
354 self
.SetMenuBar(self
.mainmenu
)
356 # set the menu accellerator table...
357 aTable
= wxAcceleratorTable([(wxACCEL_ALT
, ord('X'), exitID
),
358 (wxACCEL_CTRL
, ord('H'), helpID
)])
359 self
.SetAcceleratorTable(aTable
)
365 self
.tree
= wxTreeCtrl(splitter
, tID
,
366 style
=wxTR_HAS_BUTTONS |
368 wxTR_HAS_VARIABLE_ROW_HEIGHT
)
370 #self.tree.SetBackgroundColour(wxNamedColour("Pink"))
371 root
= self
.tree
.AddRoot("wxPython Overview")
373 for item
in _treeList
:
374 child
= self
.tree
.AppendItem(root
, item
[0])
375 if not firstChild
: firstChild
= child
376 for childItem
in item
[1]:
377 theDemo
= self
.tree
.AppendItem(child
, childItem
)
378 self
.treeMap
[childItem
] = theDemo
380 self
.tree
.Expand(root
)
381 self
.tree
.Expand(firstChild
)
382 EVT_TREE_ITEM_EXPANDED (self
.tree
, tID
, self
.OnItemExpanded
)
383 EVT_TREE_ITEM_COLLAPSED (self
.tree
, tID
, self
.OnItemCollapsed
)
384 EVT_TREE_SEL_CHANGED (self
.tree
, tID
, self
.OnSelChanged
)
385 EVT_LEFT_DOWN (self
.tree
, self
.OnTreeLeftDown
)
388 self
.nb
= wxNotebook(splitter2
, -1, style
=wxCLIP_CHILDREN
)
390 # Set up a wxHtmlWindow on the Overview Notebook page
391 # we put it in a panel first because there seems to be a
392 # refresh bug of some sort (wxGTK) when it is directly in
395 self
.ovr
= wxHtmlWindow(self
.nb
, -1, size
=(400, 400))
396 self
.nb
.AddPage(self
.ovr
, self
.overviewText
)
398 else: # hopefully I can remove this hacky code soon, see bug #216861
399 panel
= wxPanel(self
.nb
, -1, style
=wxCLIP_CHILDREN
)
400 self
.ovr
= wxHtmlWindow(panel
, -1, size
=(400, 400))
401 self
.nb
.AddPage(panel
, self
.overviewText
)
403 def OnOvrSize(evt
, ovr
=self
.ovr
):
404 ovr
.SetSize(evt
.GetSize())
406 EVT_SIZE(panel
, OnOvrSize
)
407 EVT_ERASE_BACKGROUND(panel
, EmptyHandler
)
410 self
.SetOverview(self
.overviewText
, overview
)
413 # Set up a TextCtrl on the Demo Code Notebook page
414 self
.txt
= wxTextCtrl(self
.nb
, -1,
415 style
= wxTE_MULTILINE|wxTE_READONLY|wxHSCROLL
)
416 self
.nb
.AddPage(self
.txt
, "Demo Code")
419 # Set up a log on the View Log Notebook page
420 self
.log
= wxTextCtrl(splitter2
, -1,
421 style
= wxTE_MULTILINE|wxTE_READONLY|wxHSCROLL
)
423 # Set the wxWindows log target to be this textctrl
424 #wxLog_SetActiveTarget(wxLogTextCtrl(self.log))
426 # But instead of the above we want to show how to use our own wxLog class
427 wxLog_SetActiveTarget(MyLog(self
.log
))
433 # add the windows to the splitter and split it.
434 splitter2
.SplitHorizontally(self
.nb
, self
.log
)
435 splitter
.SplitVertically(self
.tree
, splitter2
)
437 splitter
.SetSashPosition(180, true
)
438 splitter
.SetMinimumPaneSize(20)
439 splitter2
.SetSashPosition(450, true
)
440 splitter2
.SetMinimumPaneSize(20)
444 # select initial items
445 self
.nb
.SetSelection(0)
446 self
.tree
.SelectItem(root
)
448 if len(sys
.argv
) == 2:
450 selectedDemo
= self
.treeMap
[sys
.argv
[1]]
454 self
.tree
.SelectItem(selectedDemo
)
455 self
.tree
.EnsureVisible(selectedDemo
)
458 wxLogMessage('window handle: %s' % self
.GetHandle())
461 #---------------------------------------------
462 def WriteText(self
, text
):
463 if text
[-1:] == '\n':
468 def write(self
, txt
):
471 #---------------------------------------------
472 def OnItemExpanded(self
, event
):
473 item
= event
.GetItem()
474 wxLogMessage("OnItemExpanded: %s" % self
.tree
.GetItemText(item
))
477 #---------------------------------------------
478 def OnItemCollapsed(self
, event
):
479 item
= event
.GetItem()
480 wxLogMessage("OnItemCollapsed: %s" % self
.tree
.GetItemText(item
))
483 #---------------------------------------------
484 def OnTreeLeftDown(self
, event
):
485 pt
= event
.GetPosition();
486 item
, flags
= self
.tree
.HitTest(pt
)
487 if item
== self
.tree
.GetSelection():
488 self
.SetOverview(self
.tree
.GetItemText(item
), self
.curOverview
)
491 #---------------------------------------------
492 def OnSelChanged(self
, event
):
496 item
= event
.GetItem()
497 itemText
= self
.tree
.GetItemText(item
)
498 self
.RunDemo(itemText
)
501 #---------------------------------------------
502 def RunDemo(self
, itemText
):
504 if self
.nb
.GetPageCount() == 3:
505 if self
.nb
.GetSelection() == 2:
506 self
.nb
.SetSelection(0)
507 self
.nb
.DeletePage(2)
509 if itemText
== self
.overviewText
:
510 self
.GetDemoFile('Main.py')
511 self
.SetOverview(self
.overviewText
, overview
)
516 if os
.path
.exists(itemText
+ '.py'):
518 wxLogMessage("Running demo %s.py..." % itemText
)
520 self
.GetDemoFile(itemText
+ '.py')
521 module
= __import__(itemText
, globals())
522 self
.SetOverview(itemText
+ " Overview", module
.overview
)
526 # in case runTest is modal, make sure things look right...
530 self
.window
= module
.runTest(self
, self
.nb
, self
) ###
532 self
.nb
.AddPage(self
.window
, 'Demo')
534 self
.nb
.SetSelection(2)
543 #---------------------------------------------
545 def GetDemoFile(self
, filename
):
548 self
.txt
.SetValue(open(filename
).read())
550 self
.txt
.WriteText("Cannot open %s file." % filename
)
552 self
.txt
.SetInsertionPoint(0)
553 self
.txt
.ShowPosition(0)
555 #---------------------------------------------
556 def SetOverview(self
, name
, text
):
557 self
.curOverview
= text
559 if lead
!= '<html>' and lead
!= '<HTML>':
560 text
= string
.join(string
.split(text
, '\n'), '<br>')
561 self
.ovr
.SetPage(text
)
562 self
.nb
.SetPageText(0, name
)
564 #---------------------------------------------
566 def OnFileExit(self
, *event
):
570 def OnHelpAbout(self
, event
):
571 from About
import MyAboutBox
572 about
= MyAboutBox(self
)
577 #---------------------------------------------
578 def OnCloseWindow(self
, event
):
582 if hasattr(self
, "tbicon"):
587 #---------------------------------------------
588 def OnIdle(self
, event
):
590 self
.otherWin
.Raise()
591 self
.window
= self
.otherWin
599 #---------------------------------------------
602 showTipText
= open(opj("data/showTips")).read()
603 showTip
, index
= eval(showTipText
)
605 showTip
, index
= (1, 0)
607 tp
= wxCreateFileTipProvider(opj("data/tips.txt"), index
)
608 showTip
= wxShowTip(self
, tp
)
609 index
= tp
.GetCurrentTip()
610 open(opj("data/showTips"), "w").write(str( (showTip
, index
) ))
613 #---------------------------------------------
614 def OnDemoMenu(self
, event
):
616 selectedDemo
= self
.treeMap
[self
.mainmenu
.GetLabel(event
.GetId())]
620 self
.tree
.SelectItem(selectedDemo
)
621 self
.tree
.EnsureVisible(selectedDemo
)
624 #---------------------------------------------
625 def OnTaskBarActivate(self
, evt
):
626 if self
.IsIconized():
628 if not self
.IsShown():
632 #---------------------------------------------
634 TBMENU_RESTORE
= 1000
637 def OnTaskBarMenu(self
, evt
):
639 menu
.Append(self
.TBMENU_RESTORE
, "Restore wxPython Demo")
640 menu
.Append(self
.TBMENU_CLOSE
, "Close")
641 self
.tbicon
.PopupMenu(menu
)
644 #---------------------------------------------
645 def OnTaskBarClose(self
, evt
):
648 # because of the way wxTaskBarIcon.PopupMenu is implemented we have to
649 # prod the main idle handler a bit to get the window to actually close
650 wxGetApp().ProcessIdle()
653 #---------------------------------------------
654 def OnIconfiy(self
, evt
):
655 wxLogMessage("OnIconfiy")
658 #---------------------------------------------
659 def OnMaximize(self
, evt
):
660 wxLogMessage("OnMaximize")
666 #---------------------------------------------------------------------------
667 #---------------------------------------------------------------------------
669 class MySplashScreen(wxSplashScreen
):
671 bmp
= wxImage(opj("bitmaps/splash.gif")).ConvertToBitmap()
672 wxSplashScreen
.__init
__(self
, bmp
,
673 wxSPLASH_CENTRE_ON_SCREEN|wxSPLASH_TIMEOUT
,
675 EVT_CLOSE(self
, self
.OnClose
)
677 def OnClose(self
, evt
):
678 frame
= wxPythonDemo(None, -1, "wxPython: (A Demonstration)")
680 evt
.Skip() # Make sure the default handler runs too...
686 Create and show the splash screen. It will then create and show
687 the main frame when it is time to do so.
689 wxInitAllImageHandlers()
690 splash
= MySplashScreen()
696 #---------------------------------------------------------------------------
700 demoPath
= os
.path
.dirname(__file__
)
708 #---------------------------------------------------------------------------
712 overview
= """<html><body>
715 Python is an interpreted, interactive, object-oriented programming
716 language often compared to Tcl, Perl, Scheme, or Java.
718 <p> Python combines remarkable power with very clear syntax. It has
719 modules, classes, exceptions, very high level dynamic data types, and
720 dynamic typing. There are interfaces to many system calls and
721 libraries, and new built-in modules are easily written in C or
722 C++. Python is also usable as an extension language for applications
723 that need a programmable interface. <p>
727 wxWindows is a free C++ framework designed to make cross-platform
728 programming child's play. Well, almost. wxWindows 2 supports Windows
729 3.1/95/98/NT, Unix with GTK/Motif/Lesstif, with a Mac version
730 underway. Other ports are under consideration. <p>
732 wxWindows is a set of libraries that allows C++ applications to
733 compile and run on several different types of computers, with minimal
734 source code changes. There is one library per supported GUI (such as
735 Motif, or Windows). As well as providing a common API (Application
736 Programming Interface) for GUI functionality, it provides
737 functionality for accessing some commonly-used operating system
738 facilities, such as copying or deleting files. wxWindows is a
739 'framework' in the sense that it provides a lot of built-in
740 functionality, which the application can use or replace as required,
741 thus saving a great deal of coding effort. Basic data structures such
742 as strings, linked lists and hash tables are also supported.
747 wxPython is a Python extension module that encapsulates the wxWindows
748 GUI classes. Currently it is only available for the Win32 and GTK
749 ports of wxWindows, but as soon as the other ports are brought up to
750 the same level as Win32 and GTK, it should be fairly trivial to
751 enable wxPython to be used with the new GUI.
755 The wxPython extension module attempts to mirror the class heiarchy
756 of wxWindows as closely as possible. This means that there is a
757 wxFrame class in wxPython that looks, smells, tastes and acts almost
758 the same as the wxFrame class in the C++ version. Unfortunately,
759 because of differences in the languages, wxPython doesn't match
760 wxWindows exactly, but the differences should be easy to absorb
761 because they are natural to Python. For example, some methods that
762 return multiple values via argument pointers in C++ will return a
763 tuple of values in Python.
767 There is still much to be done for wxPython, many classes still need
768 to be mirrored. Also, wxWindows is still somewhat of a moving target
769 so it is a bit of an effort just keeping wxPython up to date. On the
770 other hand, there are enough of the core classes completed that
771 useful applications can be written.
775 wxPython is close enough to the C++ version that the majority of
776 the wxPython documentation is actually just notes attached to the C++
777 documents that describe the places where wxPython is different. There
778 is also a series of sample programs included, and a series of
779 documentation pages that assist the programmer in getting started
785 #----------------------------------------------------------------------------
786 #----------------------------------------------------------------------------
788 if __name__
== '__main__':
791 #----------------------------------------------------------------------------