#!/bin/env python #---------------------------------------------------------------------------- # Name: Main.py # Purpose: Testing lots of stuff, controls, window types, etc. # # Author: Robin Dunn # # Created: A long time ago, in a galaxy far, far away... # Copyright: (c) 1999-2020 by Total Control Software # Licence: wxWindows license # Tags: phoenix-port, py3-port #---------------------------------------------------------------------------- # FIXME List: # * Problems with flickering related to ERASE_BACKGROUND # and the splitters. Might be a problem with this 2.5 beta...? # UPDATE: can't see on 2.5.2 GTK - maybe just a faster machine :) # * Demo Code menu? # * Annoying switching between tabs and resulting flicker # how to replace a page in the notebook without deleting/adding? # Where is SetPage!? tried freeze...tried reparent of dummy panel.... # AG: It looks like this issue is fixed by Freeze()ing and Thaw()ing the # main frame and not the notebook # TODO List: # * UI design more professional (is the new version more professional?) # * save file positions (new field in demoModules) (@ LoadDemoSource) # * Update main overview # * Why don't we move _treeList into a separate module # ===================== # = EXTERNAL Packages = # ===================== # In order to let a package (like AGW) be included in the wxPython demo, # the package owner should create a sub-directory of the wxPython demo folder # in which all the package's demos should live. In addition, the sub-folder # should contain a Python file called __demo__.py which, when imported, should # contain the following methods: # # * GetDemoBitmap: returns the bitmap to be used in the wxPython demo tree control # in a PyEmbeddedImage format; # * GetRecentAdditions: returns a list of demos which will be displayed under the # "Recent Additions/Updates" tree item. This list should be a subset (or the full # set) of the package's demos; # * GetDemos: returns a tuple. The first item of the tuple is the package's name # as will be displayed in the wxPython demo tree, right after the "Custom Controls" # item. The second element of the tuple is the list of demos for the external package. # * GetOverview: returns a wx.html-ready representation of the package's documentation. # # Please see the __demo__.py file in the demo/agw/ folder for an example. # Last updated: Andrea Gavana, 20 Oct 2008, 18.00 GMT import sys, os, time, traceback import pickle import re import shutil import urllib.error import urllib.request from io import BytesIO from threading import Thread import wx import wx.adv import wx.lib.agw.aui as aui import wx.html from wx.lib.msgpanel import MessagePanel from wx.adv import TaskBarIcon as TaskBarIcon from wx.adv import SplashScreen as SplashScreen import wx.lib.mixins.inspection import version # We won't import the images module yet, but we'll assign it to this # global when we do. images = None # For debugging ##wx.Trap(); ##print("wx.VERSION_STRING = %s (%s)" % (wx.VERSION_STRING, wx.USE_UNICODE and 'unicode' or 'ansi')) ##print("pid:", os.getpid()) ##raw_input("Press Enter...") #--------------------------------------------------------------------------- USE_CUSTOMTREECTRL = False DEFAULT_PERSPECTIVE = "Default Perspective" #--------------------------------------------------------------------------- # get images and demo list from demodata import _demoPngs, _treeList #--------------------------------------------------------------------------- _styleTable = '
This class supports the following window %s:\n' \ '
Checking for documentation on the wxWidgets website, please stand by...
"
lead = text[:6]
if lead != '' and lead != '':
text = '
'.join(text.split('\n'))
self.ovr.SetPage(text)
self.downloadTimer.Start(100)
self.downloadGauge.Show()
self.Reposition()
self.downloading = True
self.internetThread = InternetThread(self, itemText)
#---------------------------------------------
def StopDownload(self, error=None):
self.downloadTimer.Stop()
if not self.downloading:
return
if error:
if self.sendDownloadError:
self.log.AppendText("Warning: problems in downloading documentation from the wxWidgets website.\n")
self.log.AppendText("Error message from the documentation downloader was:\n")
self.log.AppendText("\n".join(error))
self.sendDownloadError = False
self.nb.SetPageImage(0, 0)
self.internetThread.keepRunning = False
self.internetThread = None
self.downloading = False
self.downloadGauge.Hide()
self.Reposition()
text = self.curOverview
lead = text[:6]
if lead != '' and lead != '':
text = '
'.join(text.split('\n'))
self.ovr.SetPage(text)
#---------------------------------------------
def LoadDocumentation(self, data):
text = self.curOverview
addHtml = False
if '' not in text and '' not in text:
text = '
'.join(text.split('\n'))
styles, events, extra, appearance = data
if appearance:
text += FormatImages(appearance)
for names, values in zip(["Styles", "Extra Styles", "Events"], [styles, extra, events]):
if not values:
continue
headers = (names == "Events" and [2] or [3])[0]
text += "
" + FormatDocs(names, values, headers) item = self.tree.GetSelection() itemText = self.tree.GetItemText(item) self.pickledData[itemText] = data self.StopDownload() self.ovr.SetPage(text) #print("load time: ", time.time() - start) # Menu methods def OnFileExit(self, *event): self.Close() def OnToggleRedirect(self, event): app = wx.GetApp() if event.IsChecked(): app.RedirectStdio() print("Print statements and other standard output will now be directed to this window.") else: app.RestoreStdio() print("Print statements and other standard output will now be sent to the usual location.") def OnAllowDownload(self, event): self.allowDocs = event.IsChecked() if self.allowDocs: self.StartDownload() else: self.StopDownload() def OnDeleteDocs(self, event): deleteMsg = "You are about to delete the downloaded documentation.\n" + \ "Do you want to continue?" dlg = wx.MessageDialog(self, deleteMsg, "wxPython Demo", wx.YES_NO | wx.NO_DEFAULT| wx.ICON_QUESTION) result = dlg.ShowModal() if result == wx.ID_NO: dlg.Destroy() return dlg.Destroy() busy = wx.BusyInfo("Deleting downloaded data...") wx.SafeYield() pickledFile = GetDocFile() docDir = os.path.split(pickledFile)[0] if os.path.exists(docDir): shutil.rmtree(docDir, ignore_errors=True) self.pickledData = {} del busy self.sendDownloadError = True def OnAllowAuiFloating(self, event): self.allowAuiFloating = event.IsChecked() for pane in self.mgr.GetAllPanes(): if pane.name != "Notebook": pane.Floatable(self.allowAuiFloating) self.EnableAUIMenu() self.mgr.Update() def EnableAUIMenu(self): menuItems = self.options_menu.GetMenuItems() for indx in range(4, len(menuItems)-1): item = menuItems[indx] item.Enable(self.allowAuiFloating) def OnAUIPerspectives(self, event): perspective = self.perspectives_menu.GetLabel(event.GetId()) self.mgr.LoadPerspective(self.auiConfigurations[perspective]) self.mgr.Update() def OnSavePerspective(self, event): dlg = wx.TextEntryDialog(self, "Enter a name for the new perspective:", "AUI Configuration") dlg.SetValue(("Perspective %d")%(len(self.auiConfigurations)+1)) if dlg.ShowModal() != wx.ID_OK: return perspectiveName = dlg.GetValue() menuItems = self.perspectives_menu.GetMenuItems() for item in menuItems: if item.GetLabel() == perspectiveName: wx.MessageBox("The selected perspective name:\n\n%s\n\nAlready exists."%perspectiveName, "Error", style=wx.ICON_ERROR) return item = wx.MenuItem(self.perspectives_menu, -1, dlg.GetValue(), "Load user perspective %d"%(len(self.auiConfigurations)+1), wx.ITEM_RADIO) self.Bind(wx.EVT_MENU, self.OnAUIPerspectives, item) self.perspectives_menu.Append(item) item.Check(True) self.auiConfigurations.update({dlg.GetValue(): self.mgr.SavePerspective()}) def OnDeletePerspective(self, event): menuItems = self.perspectives_menu.GetMenuItems() lst = [] loadDefault = False for indx, item in enumerate(menuItems): if indx > 0: lst.append(item.GetLabel()) dlg = wx.MultiChoiceDialog(self, "Please select the perspectives\nyou would like to delete:", "Delete AUI Perspectives", lst) if dlg.ShowModal() == wx.ID_OK: selections = dlg.GetSelections() strings = [lst[x] for x in selections] for sel in strings: self.auiConfigurations.pop(sel) item = menuItems[lst.index(sel)+1] if item.IsChecked(): loadDefault = True self.perspectives_menu.GetMenuItems()[0].Check(True) self.perspectives_menu.DeleteItem(item) lst.remove(sel) if loadDefault: self.mgr.LoadPerspective(self.auiConfigurations[DEFAULT_PERSPECTIVE]) self.mgr.Update() def OnTreeExpansion(self, event): self.tree.SetExpansionState(self.expansionState) def OnHelpAbout(self, event): from About import MyAboutBox about = MyAboutBox(self) about.ShowModal() about.Destroy() def OnHelpFind(self, event): if self.finddlg is not None: return self.nb.SetSelection(1) self.finddlg = wx.FindReplaceDialog(self, self.finddata, "Find", wx.FR_NOMATCHCASE | wx.FR_NOWHOLEWORD) self.finddlg.Show(True) def OnUpdateFindItems(self, evt): evt.Enable(self.finddlg is None) def OnFind(self, event): editor = self.codePage.editor self.nb.SetSelection(1) end = editor.GetLastPosition() textstring = editor.GetRange(0, end).lower() findstring = self.finddata.GetFindString().lower() backward = not (self.finddata.GetFlags() & wx.FR_DOWN) if backward: start = editor.GetSelection()[0] loc = textstring.rfind(findstring, 0, start) else: start = editor.GetSelection()[1] loc = textstring.find(findstring, start) if loc == -1 and start != 0: # string not found, start at beginning if backward: start = end loc = textstring.rfind(findstring, 0, start) else: start = 0 loc = textstring.find(findstring, start) if loc == -1: dlg = wx.MessageDialog(self, 'Find String Not Found', 'Find String Not Found in Demo File', wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() if self.finddlg: if loc == -1: self.finddlg.SetFocus() return else: self.finddlg.Destroy() self.finddlg = None editor.ShowPosition(loc) editor.SetSelection(loc, loc + len(findstring)) def OnFindNext(self, event): if self.finddata.GetFindString(): self.OnFind(event) else: self.OnHelpFind(event) def OnFindClose(self, event): event.GetDialog().Destroy() self.finddlg = None def OnOpenShellWindow(self, evt): if self.shell: # if it already exists then just make sure it's visible s = self.shell if s.IsIconized(): s.Iconize(False) s.Raise() else: # Make a PyShell window from wx import py namespace = { 'wx' : wx, 'app' : wx.GetApp(), 'frame' : self, } self.shell = py.shell.ShellFrame(None, locals=namespace) self.shell.SetSize((640,480)) self.shell.Show() # Hook the close event of the main frame window so that we # close the shell at the same time if it still exists def CloseShell(evt): if self.shell: self.shell.Close() evt.Skip() self.Bind(wx.EVT_CLOSE, CloseShell) def OnOpenWidgetInspector(self, evt): # Activate the widget inspection tool, giving it a widget to preselect # in the tree. Use either the one under the cursor, if any, or this # frame. from wx.lib.inspection import InspectionTool wnd = wx.FindWindowAtPointer() if not wnd: wnd = self InspectionTool().Show(wnd, True) #--------------------------------------------- def OnCloseWindow(self, event): self.mgr.UnInit() self.dying = True self.demoPage = None self.codePage = None self.mainmenu = None self.StopDownload() if self.tbicon is not None: self.tbicon.Destroy() config = GetConfig() config.Write('ExpansionState', str(self.tree.GetExpansionState())) config.Write('AUIPerspectives', str(self.auiConfigurations)) config.Write('AllowDownloads', str(self.allowDocs)) config.Write('AllowAUIFloating', str(self.allowAuiFloating)) config.Flush() MakeDocDirs() pickledFile = GetDocFile() with open(pickledFile, "wb") as fid: pickle.dump(self.pickledData, fid, pickle.HIGHEST_PROTOCOL) self.Destroy() #--------------------------------------------- def OnIdle(self, event): if self.otherWin: self.otherWin.Raise() self.demoPage = self.otherWin self.otherWin = None #--------------------------------------------- def OnDownloadTimer(self, event): self.downloadGauge.Pulse() self.downloadImage += 1 if self.downloadImage > 9: self.downloadImage = 3 self.nb.SetPageImage(0, self.downloadImage) ## wx.SafeYield() #--------------------------------------------- def ShowTip(self): config = GetConfig() showTipText = config.Read("tips") if showTipText: showTip, index = eval(showTipText) else: showTip, index = (1, 0) # if showTip: # tp = wx.CreateFileTipProvider(opj("data/tips.txt"), index) # showTip = wx.ShowTip(self, tp) # index = tp.GetCurrentTip() # config.Write("tips", str( (showTip, index) )) # config.Flush() #--------------------------------------------- def OnDemoMenu(self, event): try: selectedDemo = self.treeMap[self.mainmenu.GetLabel(event.GetId())] except: selectedDemo = None if selectedDemo: self.tree.SelectItem(selectedDemo) self.tree.EnsureVisible(selectedDemo) #--------------------------------------------- def OnIconfiy(self, evt): wx.LogMessage("OnIconfiy: %s" % evt.IsIconized()) evt.Skip() #--------------------------------------------- def OnMaximize(self, evt): wx.LogMessage("OnMaximize") evt.Skip() #--------------------------------------------- def OnActivate(self, evt): wx.LogMessage("OnActivate: %s" % evt.GetActive()) evt.Skip() #--------------------------------------------- def OnAppActivate(self, evt): wx.LogMessage("OnAppActivate: %s" % evt.GetActive()) evt.Skip() #--------------------------------------------------------------------------- #--------------------------------------------------------------------------- class MySplashScreen(SplashScreen): def __init__(self): bmp = wx.Image(opj("bitmaps/splash.png")).ConvertToBitmap() SplashScreen.__init__(self, bmp, wx.adv.SPLASH_CENTRE_ON_SCREEN | wx.adv.SPLASH_TIMEOUT, 5000, None, -1) self.Bind(wx.EVT_CLOSE, self.OnClose) self.fc = wx.CallLater(1000, self.ShowMain) def OnClose(self, evt): # Make sure the default handler runs too so this window gets # destroyed evt.Skip() self.Hide() # if the timer is still running then go ahead and show the # main frame now if self.fc.IsRunning(): self.fc.Stop() self.ShowMain() def ShowMain(self): frame = wxPythonDemo(None, "wxPython: (A Demonstration)") frame.Show() if self.fc.IsRunning(): self.Raise() wx.CallAfter(frame.ShowTip) #--------------------------------------------------------------------------- from wx.lib.mixins.treemixin import ExpansionState if USE_CUSTOMTREECTRL: import wx.lib.agw.customtreectrl as CT TreeBaseClass = CT.CustomTreeCtrl else: TreeBaseClass = wx.TreeCtrl class wxPythonDemoTree(ExpansionState, TreeBaseClass): def __init__(self, parent): TreeBaseClass.__init__(self, parent, style=wx.TR_DEFAULT_STYLE| wx.TR_HAS_VARIABLE_ROW_HEIGHT) self.BuildTreeImageList() if USE_CUSTOMTREECTRL: self.SetSpacing(10) self.SetWindowStyle(self.GetWindowStyle() & ~wx.TR_LINES_AT_ROOT) self.SetInitialSize((100,80)) def AppendItem(self, parent, text, image=-1, wnd=None): if USE_CUSTOMTREECTRL: item = TreeBaseClass.AppendItem(self, parent, text, image=image, wnd=wnd) else: item = TreeBaseClass.AppendItem(self, parent, text, image=image) return item def BuildTreeImageList(self): imgList = wx.ImageList(16, 16) for png in _demoPngs: imgList.Add(images.catalog[png].GetBitmap()) # add the image for modified demos. imgList.Add(images.catalog["custom"].GetBitmap()) self.AssignImageList(imgList) def GetItemIdentity(self, item): return self.GetItemData(item) #--------------------------------------------------------------------------- class MyApp(wx.App, wx.lib.mixins.inspection.InspectionMixin): def OnInit(self): # Check runtime version if version.VERSION_STRING != wx.VERSION_STRING: wx.MessageBox(caption="Warning", message="You're using version %s of wxPython, but this copy of the demo was written for version %s.\n" "There may be some version incompatibilities..." % (wx.VERSION_STRING, version.VERSION_STRING)) self.InitInspection() # for the InspectionMixin base class # Now that we've warned the user about possible problems, # lets import images import images as i global images images = i # For debugging #self.SetAssertMode(wx.APP_ASSERT_DIALOG|wx.APP_ASSERT_EXCEPTION) wx.SystemOptions.SetOption("mac.window-plain-transition", 1) self.SetAppName("wxPyDemo") # Create and show the splash screen. It will then create and # show the main frame when it is time to do so. Normally when # using a SplashScreen you would create it, show it and then # continue on with the application's initialization, finally # creating and showing the main application window(s). In # this case we have nothing else to do so we'll delay showing # the main frame until later (see ShowMain above) so the users # can see the SplashScreen effect. splash = MySplashScreen() splash.Show() return True def InitLocale(self): super().InitLocale() self._locale = wx.Locale(wx.LANGUAGE_ENGLISH) #--------------------------------------------------------------------------- def main(): try: demoPath = os.path.dirname(__file__) os.chdir(demoPath) except: pass app = MyApp(False) app.MainLoop() #--------------------------------------------------------------------------- mainOverview = """
wxPython is a GUI toolkit for the Python programming language. It allows Python programmers to create programs with a robust, highly functional graphical user interface, simply and easily. It is implemented as a Python extension module (native code) that wraps the popular wxWindows cross platform GUI library, which is written in C++.
Like Python and wxWindows, wxPython is Open Source which means that it is free for anyone to use and the source code is available for anyone to look at and modify. Or anyone can contribute fixes or enhancements to the project.
wxPython is a cross-platform toolkit. This means that the same program will run on multiple platforms without modification. Currently supported platforms are 32-bit Microsoft Windows, most Unix or unix-like systems, and Macintosh OS X. Since the language is Python, wxPython programs are simple, easy to write and easy to understand.
This demo is not only a collection of test cases for wxPython, but is also designed to help you learn about and how to use wxPython. Each sample is listed in the tree control on the left. When a sample is selected in the tree then a module is loaded and run (usually in a tab of this notebook,) and the source code of the module is loaded in another tab for you to browse and learn from. """ #---------------------------------------------------------------------------- #---------------------------------------------------------------------------- if __name__ == '__main__': __name__ = 'Main' main() #----------------------------------------------------------------------------