📄 main.py
字号:
def OnSave(self, event):
if self.demoModules.Exists(modModified):
if self.demoModules.GetActiveID() == modOriginal:
overwriteMsg = "You are about to overwrite an already existing modified copy\n" + \
"Do you want to continue?"
dlg = wx.MessageDialog(self, overwriteMsg, "wxPython Demo",
wx.YES_NO | wx.NO_DEFAULT| wx.ICON_EXCLAMATION)
result = dlg.ShowModal()
if result == wx.ID_NO:
return
dlg.Destroy()
self.demoModules.SetActive(modModified)
modifiedFilename = GetModifiedFilename(self.demoModules.name)
# Create the demo directory if one doesn't already exist
if not os.path.exists(GetModifiedDirectory()):
try:
os.makedirs(GetModifiedDirectory())
if not os.path.exists(GetModifiedDirectory()):
wx.LogMessage("BUG: Created demo directory but it still doesn't exist")
raise AssertionError
except:
wx.LogMessage("Error creating demo directory: %s" % GetModifiedDirectory())
return
else:
wx.LogMessage("Created directory for modified demos: %s" % GetModifiedDirectory())
# Save
f = open(modifiedFilename, "wt")
source = self.editor.GetText()
try:
f.write(source)
finally:
f.close()
busy = wx.BusyInfo("Reloading demo module...")
self.demoModules.LoadFromFile(modModified, modifiedFilename)
self.ActiveModuleChanged()
self.mainFrame.SetTreeModified(True)
def OnRestore(self, event): # Handles the "Delete Modified" button
modifiedFilename = GetModifiedFilename(self.demoModules.name)
self.demoModules.Delete(modModified)
os.unlink(modifiedFilename) # Delete the modified copy
busy = wx.BusyInfo("Reloading demo module...")
self.ActiveModuleChanged()
self.mainFrame.SetTreeModified(False)
#---------------------------------------------------------------------------
def opj(path):
"""Convert paths to the platform-specific separator"""
st = apply(os.path.join, tuple(path.split('/')))
# HACK: on Linux, a leading / gets lost...
if path.startswith('/'):
st = '/' + st
return st
def GetDataDir():
"""
Return the standard location on this platform for application data
"""
sp = wx.StandardPaths.Get()
return sp.GetUserDataDir()
def GetModifiedDirectory():
"""
Returns the directory where modified versions of the demo files
are stored
"""
return os.path.join(GetDataDir(), "modified")
def GetModifiedFilename(name):
"""
Returns the filename of the modified version of the specified demo
"""
if not name.endswith(".py"):
name = name + ".py"
return os.path.join(GetModifiedDirectory(), name)
def GetOriginalFilename(name):
"""
Returns the filename of the original version of the specified demo
"""
if not name.endswith(".py"):
name = name + ".py"
return name
def DoesModifiedExist(name):
"""Returns whether the specified demo has a modified copy"""
if os.path.exists(GetModifiedFilename(name)):
return True
else:
return False
def GetConfig():
if not os.path.exists(GetDataDir()):
os.makedirs(GetDataDir())
config = wx.FileConfig(
localFilename=os.path.join(GetDataDir(), "options"))
return config
def SearchDemo(name, keyword):
""" Returns whether a demo contains the search keyword or not. """
fid = open(GetOriginalFilename(name), "rt")
fullText = fid.read()
fid.close()
if type(keyword) is unicode:
fullText = fullText.decode('iso8859-1')
if fullText.find(keyword) >= 0:
return True
return False
#---------------------------------------------------------------------------
class ModuleDictWrapper:
"""Emulates a module with a dynamically compiled __dict__"""
def __init__(self, dict):
self.dict = dict
def __getattr__(self, name):
if name in self.dict:
return self.dict[name]
else:
raise AttributeError
class DemoModules:
"""
Dynamically manages the original/modified versions of a demo
module
"""
def __init__(self, name):
self.modActive = -1
self.name = name
# (dict , source , filename , description , error information )
# ( 0 , 1 , 2 , 3 , 4 )
self.modules = [[None, "" , "" , "<original>" , None],
[None, "" , "" , "<modified>" , None]]
# load original module
self.LoadFromFile(modOriginal, GetOriginalFilename(name))
self.SetActive(modOriginal)
# load modified module (if one exists)
if DoesModifiedExist(name):
self.LoadFromFile(modModified, GetModifiedFilename(name))
def LoadFromFile(self, modID, filename):
self.modules[modID][2] = filename
file = open(filename, "rt")
self.LoadFromSource(modID, file.read())
file.close()
def LoadFromSource(self, modID, source):
self.modules[modID][1] = source
self.LoadDict(modID)
def LoadDict(self, modID):
if self.name != __name__:
source = self.modules[modID][1]
description = self.modules[modID][2]
description = description.encode(sys.getfilesystemencoding())
try:
self.modules[modID][0] = {}
code = compile(source, description, "exec")
exec code in self.modules[modID][0]
except:
self.modules[modID][4] = DemoError(sys.exc_info())
self.modules[modID][0] = None
else:
self.modules[modID][4] = None
def SetActive(self, modID):
if modID != modOriginal and modID != modModified:
raise LookupError
else:
self.modActive = modID
def GetActive(self):
dict = self.modules[self.modActive][0]
if dict is None:
return None
else:
return ModuleDictWrapper(dict)
def GetActiveID(self):
return self.modActive
def GetSource(self, modID = None):
if modID is None:
modID = self.modActive
return self.modules[modID][1]
def GetFilename(self, modID = None):
if modID is None:
modID = self.modActive
return self.modules[self.modActive][2]
def GetErrorInfo(self, modID = None):
if modID is None:
modID = self.modActive
return self.modules[self.modActive][4]
def Exists(self, modID):
return self.modules[modID][1] != ""
def UpdateFile(self, modID = None):
"""Updates the file from which a module was loaded
with (possibly updated) source"""
if modID is None:
modID = self.modActive
source = self.modules[modID][1]
filename = self.modules[modID][2]
try:
file = open(filename, "wt")
file.write(source)
finally:
file.close()
def Delete(self, modID):
if self.modActive == modID:
self.SetActive(0)
self.modules[modID][0] = None
self.modules[modID][1] = ""
self.modules[modID][2] = ""
#---------------------------------------------------------------------------
class DemoError:
"""Wraps and stores information about the current exception"""
def __init__(self, exc_info):
import copy
excType, excValue = exc_info[:2]
# traceback list entries: (filename, line number, function name, text)
self.traceback = traceback.extract_tb(exc_info[2])
# --Based on traceback.py::format_exception_only()--
if type(excType) == types.ClassType:
self.exception_type = excType.__name__
else:
self.exception_type = excType
# If it's a syntax error, extra information needs
# to be added to the traceback
if excType is SyntaxError:
try:
msg, (filename, lineno, self.offset, line) = excValue
except:
pass
else:
if not filename:
filename = "<string>"
line = line.strip()
self.traceback.append( (filename, lineno, "", line) )
excValue = msg
try:
self.exception_details = str(excValue)
except:
self.exception_details = "<unprintable %s object>" & type(excValue).__name__
del exc_info
def __str__(self):
ret = "Type %s \n \
Traceback: %s \n \
Details : %s" % ( str(self.exception_type), str(self.traceback), self.exception_details )
return ret
#---------------------------------------------------------------------------
class DemoErrorPanel(wx.Panel):
"""Panel put into the demo tab when the demo fails to run due to errors"""
def __init__(self, parent, codePanel, demoError, log):
wx.Panel.__init__(self, parent, -1)#, style=wx.NO_FULL_REPAINT_ON_RESIZE)
self.codePanel = codePanel
self.nb = parent
self.log = log
self.box = wx.BoxSizer(wx.VERTICAL)
# Main Label
self.box.Add(wx.StaticText(self, -1, "An error has occurred while trying to run the demo")
, 0, wx.ALIGN_CENTER | wx.TOP, 10)
# Exception Information
boxInfo = wx.StaticBox(self, -1, "Exception Info" )
boxInfoSizer = wx.StaticBoxSizer(boxInfo, wx.VERTICAL ) # Used to center the grid within the box
boxInfoGrid = wx.FlexGridSizer(0, 2, 0, 0)
textFlags = wx.ALIGN_RIGHT | wx.LEFT | wx.RIGHT | wx.TOP
boxInfoGrid.Add(wx.StaticText(self, -1, "Type: "), 0, textFlags, 5 )
boxInfoGrid.Add(wx.StaticText(self, -1, str(demoError.exception_type)) , 0, textFlags, 5 )
boxInfoGrid.Add(wx.StaticText(self, -1, "Details: ") , 0, textFlags, 5 )
boxInfoGrid.Add(wx.StaticText(self, -1, demoError.exception_details) , 0, textFlags, 5 )
boxInfoSizer.Add(boxInfoGrid, 0, wx.ALIGN_CENTRE | wx.ALL, 5 )
self.box.Add(boxInfoSizer, 0, wx.ALIGN_CENTER | wx.ALL, 5)
# Set up the traceback list
# This one automatically resizes last column to take up remaining space
from ListCtrl import TestListCtrl
self.list = TestListCtrl(self, -1, style=wx.LC_REPORT | wx.SUNKEN_BORDER)
self.list.Bind(wx.EVT_LEFT_DCLICK, self.OnDoubleClick)
self.list.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
self.list.InsertColumn(0, "Filename")
self.list.InsertColumn(1, "Line", wx.LIST_FORMAT_RIGHT)
self.list.InsertColumn(2, "Function")
self.list.InsertColumn(3, "Code")
self.InsertTraceback(self.list, demoError.traceback)
self.list.SetColumnWidth(0, wx.LIST_AUTOSIZE)
self.list.SetColumnWidth(2, wx.LIST_AUTOSIZE)
self.box.Add(wx.StaticText(self, -1, "Traceback:")
, 0, wx.ALIGN_CENTER | wx.TOP, 5)
self.box.Add(self.list, 1, wx.GROW | wx.ALIGN_CENTER | wx.ALL, 5)
self.box.Add(wx.StaticText(self, -1, "Entries from the demo module are shown in blue\n"
+ "Double-click on them to go to the offending line")
, 0, wx.ALIGN_CENTER | wx.BOTTOM, 5)
self.box.Fit(self)
self.SetSizer(self.box)
def InsertTraceback(self, list, traceback):
#Add the traceback data
for x in range(len(traceback)):
data = traceback[x]
list.InsertStringItem(x, os.path.basename(data[0])) # Filename
list.SetStringItem(x, 1, str(data[1])) # Line
list.SetStringItem(x, 2, str(data[2])) # Function
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -