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 #---------------------------------------------------------------------------
25 ('New since last release', [
33 # managed windows == things with a caption you can close
34 ('Base Frames and Dialogs', [
46 'wxFindReplaceDialog',
52 'wxSingleChoiceDialog',
56 # dialogs form libraries
60 'wxMultipleChoiceDialog',
61 'wxScrolledMessageDialog',
65 ('Core Windows/Controls', [
96 # controls coming from other librairies
97 ('More Windows/Controls', [
104 'PyCrustWithFilling',
109 'wxDynamicSashWindow',
115 'wxMimeTypesManager',
117 'wxStyledTextCtrl_1',
118 'wxStyledTextCtrl_2',
122 # How to lay out the controls in a frame/dialog
128 'wxLayoutConstraints',
133 ('Process and Events', [
143 ('Clipboard and DnD', [
171 # need libs not coming with the demo
172 ('Objects using an external library', [
173 'ActiveXWrapper_Acrobat',
179 # pyTree, hangman, ... in the samples dir
180 ('Check out the samples dir too', [
187 #---------------------------------------------------------------------------
189 class MyLog(wxPyLog
):
190 def __init__(self
, textCtrl
, logTime
=0):
191 wxPyLog
.__init
__(self
)
193 self
.logTime
= logTime
195 def DoLogString(self
, message
, timeStamp
):
197 message
= time
.strftime("%X", time
.localtime(timeStamp
)) + \
199 self
.tc
.AppendText(message
+ '\n')
202 #---------------------------------------------------------------------------
205 """Convert paths to the platform-specific separator"""
206 return apply(os
.path
.join
, tuple(string
.split(path
, '/')))
209 #---------------------------------------------------------------------------
211 class wxPythonDemo(wxFrame
):
212 overviewText
= "wxPython Overview"
214 def __init__(self
, parent
, id, title
):
215 wxFrame
.__init
__(self
, parent
, -1, title
, size
= (800, 600),
216 style
=wxDEFAULT_FRAME_STYLE|wxNO_FULL_REPAINT_ON_RESIZE
)
218 self
.cwd
= os
.getcwd()
219 self
.curOverview
= ""
221 icon
= images
.getMondrianIcon()
224 if wxPlatform
== '__WXMSW__':
225 # setup a taskbar icon, and catch some events from it
226 self
.tbicon
= wxTaskBarIcon()
227 self
.tbicon
.SetIcon(icon
, "wxPython Demo")
228 EVT_TASKBAR_LEFT_DCLICK(self
.tbicon
, self
.OnTaskBarActivate
)
229 EVT_TASKBAR_RIGHT_UP(self
.tbicon
, self
.OnTaskBarMenu
)
230 EVT_MENU(self
.tbicon
, self
.TBMENU_RESTORE
, self
.OnTaskBarActivate
)
231 EVT_MENU(self
.tbicon
, self
.TBMENU_CLOSE
, self
.OnTaskBarClose
)
236 EVT_IDLE(self
, self
.OnIdle
)
237 EVT_CLOSE(self
, self
.OnCloseWindow
)
238 EVT_ICONIZE(self
, self
.OnIconfiy
)
239 EVT_MAXIMIZE(self
, self
.OnMaximize
)
242 self
.CreateStatusBar(1, wxST_SIZEGRIP
)
244 splitter
= wxSplitterWindow(self
, -1, style
=wxNO_3D|wxSP_3D
)
245 splitter2
= wxSplitterWindow(splitter
, -1, style
=wxNO_3D|wxSP_3D
)
247 def EmptyHandler(evt
): pass
248 EVT_ERASE_BACKGROUND(splitter
, EmptyHandler
)
249 EVT_ERASE_BACKGROUND(splitter2
, EmptyHandler
)
251 # Prevent TreeCtrl from displaying all items after destruction when true
255 self
.mainmenu
= wxMenuBar()
258 menu
.Append(exitID
, 'E&xit\tAlt-X', 'Get the heck outta here!')
259 EVT_MENU(self
, exitID
, self
.OnFileExit
)
260 self
.mainmenu
.Append(menu
, '&File')
264 for item
in _treeList
:
266 for childItem
in item
[1]:
268 submenu
.Append(mID
, childItem
)
269 EVT_MENU(self
, mID
, self
.OnDemoMenu
)
270 menu
.AppendMenu(wxNewId(), item
[0], submenu
)
271 self
.mainmenu
.Append(menu
, '&Demo')
277 menu
.Append(helpID
, '&About\tCtrl-H', 'wxPython RULES!!!')
278 EVT_MENU(self
, helpID
, self
.OnHelpAbout
)
279 self
.mainmenu
.Append(menu
, '&Help')
280 self
.SetMenuBar(self
.mainmenu
)
282 # set the menu accellerator table...
283 aTable
= wxAcceleratorTable([(wxACCEL_ALT
, ord('X'), exitID
),
284 (wxACCEL_CTRL
, ord('H'), helpID
)])
285 self
.SetAcceleratorTable(aTable
)
291 self
.tree
= wxTreeCtrl(splitter
, tID
,
292 style
=wxTR_HAS_BUTTONS |
294 wxTR_HAS_VARIABLE_ROW_HEIGHT
)
296 #self.tree.SetBackgroundColour(wxNamedColour("Pink"))
297 root
= self
.tree
.AddRoot("wxPython Overview")
299 for item
in _treeList
:
300 child
= self
.tree
.AppendItem(root
, item
[0])
301 if not firstChild
: firstChild
= child
302 for childItem
in item
[1]:
303 theDemo
= self
.tree
.AppendItem(child
, childItem
)
304 self
.treeMap
[childItem
] = theDemo
306 self
.tree
.Expand(root
)
307 self
.tree
.Expand(firstChild
)
308 EVT_TREE_ITEM_EXPANDED (self
.tree
, tID
, self
.OnItemExpanded
)
309 EVT_TREE_ITEM_COLLAPSED (self
.tree
, tID
, self
.OnItemCollapsed
)
310 EVT_TREE_SEL_CHANGED (self
.tree
, tID
, self
.OnSelChanged
)
311 EVT_LEFT_DOWN (self
.tree
, self
.OnTreeLeftDown
)
314 self
.nb
= wxNotebook(splitter2
, -1, style
=wxCLIP_CHILDREN
)
316 # Set up a wxHtmlWindow on the Overview Notebook page
317 # we put it in a panel first because there seems to be a
318 # refresh bug of some sort (wxGTK) when it is directly in
321 self
.ovr
= wxHtmlWindow(self
.nb
, -1, size
=(400, 400))
322 self
.nb
.AddPage(self
.ovr
, self
.overviewText
)
324 else: # hopefully I can remove this hacky code soon, see bug #216861
325 panel
= wxPanel(self
.nb
, -1, style
=wxCLIP_CHILDREN
)
326 self
.ovr
= wxHtmlWindow(panel
, -1, size
=(400, 400))
327 self
.nb
.AddPage(panel
, self
.overviewText
)
329 def OnOvrSize(evt
, ovr
=self
.ovr
):
330 ovr
.SetSize(evt
.GetSize())
332 EVT_SIZE(panel
, OnOvrSize
)
333 EVT_ERASE_BACKGROUND(panel
, EmptyHandler
)
336 self
.SetOverview(self
.overviewText
, overview
)
339 # Set up a TextCtrl on the Demo Code Notebook page
340 self
.txt
= wxTextCtrl(self
.nb
, -1,
341 style
= wxTE_MULTILINE|wxTE_READONLY|wxHSCROLL
)
342 self
.nb
.AddPage(self
.txt
, "Demo Code")
345 # Set up a log on the View Log Notebook page
346 self
.log
= wxTextCtrl(splitter2
, -1,
347 style
= wxTE_MULTILINE|wxTE_READONLY|wxHSCROLL
)
349 # Set the wxWindows log target to be this textctrl
350 #wxLog_SetActiveTarget(wxLogTextCtrl(self.log))
352 # But instead of the above we want to show how to use our own wxLog class
353 wxLog_SetActiveTarget(MyLog(self
.log
))
359 # add the windows to the splitter and split it.
360 splitter2
.SplitHorizontally(self
.nb
, self
.log
)
361 splitter
.SplitVertically(self
.tree
, splitter2
)
363 splitter
.SetSashPosition(180, true
)
364 splitter
.SetMinimumPaneSize(20)
365 splitter2
.SetSashPosition(450, true
)
366 splitter2
.SetMinimumPaneSize(20)
370 # select initial items
371 self
.nb
.SetSelection(0)
372 self
.tree
.SelectItem(root
)
374 if len(sys
.argv
) == 2:
376 selectedDemo
= self
.treeMap
[sys
.argv
[1]]
380 self
.tree
.SelectItem(selectedDemo
)
381 self
.tree
.EnsureVisible(selectedDemo
)
384 wxLogMessage('window handle: %s' % self
.GetHandle())
387 #---------------------------------------------
388 def WriteText(self
, text
):
389 if text
[-1:] == '\n':
394 def write(self
, txt
):
397 #---------------------------------------------
398 def OnItemExpanded(self
, event
):
399 item
= event
.GetItem()
400 wxLogMessage("OnItemExpanded: %s" % self
.tree
.GetItemText(item
))
403 #---------------------------------------------
404 def OnItemCollapsed(self
, event
):
405 item
= event
.GetItem()
406 wxLogMessage("OnItemCollapsed: %s" % self
.tree
.GetItemText(item
))
409 #---------------------------------------------
410 def OnTreeLeftDown(self
, event
):
411 pt
= event
.GetPosition();
412 item
, flags
= self
.tree
.HitTest(pt
)
413 if item
== self
.tree
.GetSelection():
414 self
.SetOverview(self
.tree
.GetItemText(item
)+" Overview", self
.curOverview
)
417 #---------------------------------------------
418 def OnSelChanged(self
, event
):
422 item
= event
.GetItem()
423 itemText
= self
.tree
.GetItemText(item
)
424 self
.RunDemo(itemText
)
427 #---------------------------------------------
428 def RunDemo(self
, itemText
):
430 if self
.nb
.GetPageCount() == 3:
431 if self
.nb
.GetSelection() == 2:
432 self
.nb
.SetSelection(0)
433 self
.nb
.DeletePage(2)
435 if itemText
== self
.overviewText
:
436 self
.GetDemoFile('Main.py')
437 self
.SetOverview(self
.overviewText
, overview
)
442 if os
.path
.exists(itemText
+ '.py'):
444 wxLogMessage("Running demo %s.py..." % itemText
)
446 self
.GetDemoFile(itemText
+ '.py')
447 module
= __import__(itemText
, globals())
448 self
.SetOverview(itemText
+ " Overview", module
.overview
)
452 # in case runTest is modal, make sure things look right...
456 self
.window
= module
.runTest(self
, self
.nb
, self
) ###
458 self
.nb
.AddPage(self
.window
, 'Demo')
459 #wxYield() TODO: Is this still needed?
460 self
.nb
.SetSelection(2)
461 self
.nb
.Refresh() # without this wxMac has troubles showing the just added page
470 #---------------------------------------------
472 def GetDemoFile(self
, filename
):
475 self
.txt
.SetValue(open(filename
).read())
477 self
.txt
.WriteText("Cannot open %s file." % filename
)
479 self
.txt
.SetInsertionPoint(0)
480 self
.txt
.ShowPosition(0)
482 #---------------------------------------------
483 def SetOverview(self
, name
, text
):
484 self
.curOverview
= text
486 if lead
!= '<html>' and lead
!= '<HTML>':
487 text
= string
.join(string
.split(text
, '\n'), '<br>')
488 self
.ovr
.SetPage(text
)
489 self
.nb
.SetPageText(0, name
)
491 #---------------------------------------------
493 def OnFileExit(self
, *event
):
497 def OnHelpAbout(self
, event
):
498 from About
import MyAboutBox
499 about
= MyAboutBox(self
)
504 #---------------------------------------------
505 def OnCloseWindow(self
, event
):
509 if hasattr(self
, "tbicon"):
514 #---------------------------------------------
515 def OnIdle(self
, event
):
517 self
.otherWin
.Raise()
518 self
.window
= self
.otherWin
526 #---------------------------------------------
529 showTipText
= open(opj("data/showTips")).read()
530 showTip
, index
= eval(showTipText
)
532 showTip
, index
= (1, 0)
534 tp
= wxCreateFileTipProvider(opj("data/tips.txt"), index
)
535 showTip
= wxShowTip(self
, tp
)
536 index
= tp
.GetCurrentTip()
537 open(opj("data/showTips"), "w").write(str( (showTip
, index
) ))
540 #---------------------------------------------
541 def OnDemoMenu(self
, event
):
543 selectedDemo
= self
.treeMap
[self
.mainmenu
.GetLabel(event
.GetId())]
547 self
.tree
.SelectItem(selectedDemo
)
548 self
.tree
.EnsureVisible(selectedDemo
)
551 #---------------------------------------------
552 def OnTaskBarActivate(self
, evt
):
553 if self
.IsIconized():
555 if not self
.IsShown():
559 #---------------------------------------------
561 TBMENU_RESTORE
= 1000
564 def OnTaskBarMenu(self
, evt
):
566 menu
.Append(self
.TBMENU_RESTORE
, "Restore wxPython Demo")
567 menu
.Append(self
.TBMENU_CLOSE
, "Close")
568 self
.tbicon
.PopupMenu(menu
)
571 #---------------------------------------------
572 def OnTaskBarClose(self
, evt
):
575 # because of the way wxTaskBarIcon.PopupMenu is implemented we have to
576 # prod the main idle handler a bit to get the window to actually close
577 wxGetApp().ProcessIdle()
580 #---------------------------------------------
581 def OnIconfiy(self
, evt
):
582 wxLogMessage("OnIconfiy")
585 #---------------------------------------------
586 def OnMaximize(self
, evt
):
587 wxLogMessage("OnMaximize")
593 #---------------------------------------------------------------------------
594 #---------------------------------------------------------------------------
596 class MySplashScreen(wxSplashScreen
):
598 bmp
= wxImage(opj("bitmaps/splash.gif")).ConvertToBitmap()
599 wxSplashScreen
.__init
__(self
, bmp
,
600 wxSPLASH_CENTRE_ON_SCREEN|wxSPLASH_TIMEOUT
,
602 EVT_CLOSE(self
, self
.OnClose
)
604 def OnClose(self
, evt
):
605 frame
= wxPythonDemo(None, -1, "wxPython: (A Demonstration)")
607 evt
.Skip() # Make sure the default handler runs too...
613 Create and show the splash screen. It will then create and show
614 the main frame when it is time to do so.
616 wxInitAllImageHandlers()
617 splash
= MySplashScreen()
623 #---------------------------------------------------------------------------
627 demoPath
= os
.path
.dirname(__file__
)
635 #---------------------------------------------------------------------------
639 overview
= """<html><body>
642 Python is an interpreted, interactive, object-oriented programming
643 language often compared to Tcl, Perl, Scheme, or Java.
645 <p> Python combines remarkable power with very clear syntax. It has
646 modules, classes, exceptions, very high level dynamic data types, and
647 dynamic typing. There are interfaces to many system calls and
648 libraries, and new built-in modules are easily written in C or
649 C++. Python is also usable as an extension language for applications
650 that need a programmable interface. <p>
654 wxWindows is a free C++ framework designed to make cross-platform
655 programming child's play. Well, almost. wxWindows 2 supports Windows
656 3.1/95/98/NT, Unix with GTK/Motif/Lesstif, with a Mac version
657 underway. Other ports are under consideration. <p>
659 wxWindows is a set of libraries that allows C++ applications to
660 compile and run on several different types of computers, with minimal
661 source code changes. There is one library per supported GUI (such as
662 Motif, or Windows). As well as providing a common API (Application
663 Programming Interface) for GUI functionality, it provides
664 functionality for accessing some commonly-used operating system
665 facilities, such as copying or deleting files. wxWindows is a
666 'framework' in the sense that it provides a lot of built-in
667 functionality, which the application can use or replace as required,
668 thus saving a great deal of coding effort. Basic data structures such
669 as strings, linked lists and hash tables are also supported.
674 wxPython is a Python extension module that encapsulates the wxWindows
675 GUI classes. Currently it is only available for the Win32 and GTK
676 ports of wxWindows, but as soon as the other ports are brought up to
677 the same level as Win32 and GTK, it should be fairly trivial to
678 enable wxPython to be used with the new GUI.
682 The wxPython extension module attempts to mirror the class heiarchy
683 of wxWindows as closely as possible. This means that there is a
684 wxFrame class in wxPython that looks, smells, tastes and acts almost
685 the same as the wxFrame class in the C++ version. Unfortunately,
686 because of differences in the languages, wxPython doesn't match
687 wxWindows exactly, but the differences should be easy to absorb
688 because they are natural to Python. For example, some methods that
689 return multiple values via argument pointers in C++ will return a
690 tuple of values in Python.
694 There is still much to be done for wxPython, many classes still need
695 to be mirrored. Also, wxWindows is still somewhat of a moving target
696 so it is a bit of an effort just keeping wxPython up to date. On the
697 other hand, there are enough of the core classes completed that
698 useful applications can be written.
702 wxPython is close enough to the C++ version that the majority of
703 the wxPython documentation is actually just notes attached to the C++
704 documents that describe the places where wxPython is different. There
705 is also a series of sample programs included, and a series of
706 documentation pages that assist the programmer in getting started
712 #----------------------------------------------------------------------------
713 #----------------------------------------------------------------------------
715 if __name__
== '__main__':
718 #----------------------------------------------------------------------------