wxStyledTextCtrl是wxPython對流行的Scintilla的包裝,Scintilla的網站(http://www.scintilla.org/),
wxStyledTextCtrl的文檔位置(https://docs.wxpython.org/wx.stc.StyledTextCtrl.html#wx.stc.StyledTextCtrl),不過不要期望太高,這些文檔最多算聊勝于無。(看來國外的程式員也不愛寫文檔,天下烏鴉一般黑:))。
wxStyledTextCtrl是一個功能強大的富文本編輯控件,常見的編輯器功能都能找到,包括代碼高亮,搜尋替換,拷貝粘貼,回退等,後續我将逐漸提供說明和例子代碼,以供大家參考。今天先說代碼提示。
建立Frame
首先建立Frame,這個Frame由工具條和wxStyledTextCtrl組成。
class myFrame(wx.Frame):
def __init__(self,parent,title):
wx.Frame.__init__(self,parent,title=title,size=(800,600))
#建立工具條
tb=wx.Frame.CreateToolBar(self,style=wx.TB_FLAT|wx.TB_HORIZONTAL)
tb.AddTool(201,u"回退",wx.Bitmap("./icos/undo.bmp"))
tb.AddTool(202,u"重做",wx.Bitmap("icos/redo.bmp"))
tb.AddSeparator()
tb.AddTool(101,u"拷貝",wx.Bitmap("icos/copy.bmp"))
tb.AddTool(102,u"粘貼",wx.Bitmap("icos/paste.bmp"))
tb.AddTool(103,u"剪貼",wx.Bitmap("icos/cut.bmp"))
tb.AddTool(104,u"搜尋",wx.Bitmap("icos/search.bmp"))
tb.Realize()
#在工具條下方建立StyledTextCtrl編輯控件
self.control=stc.StyledTextCtrl(self,style=0)
#建立一個用于代碼提示的AutoComplete對象
self._autocomplete=AutoComplete()
#綁定工具條事件和處理函數
tb.Bind(wx.EVT_TOOL,self.OnToolSelected)
#綁定按鍵事件
self.control.Bind(wx.EVT_KEY_DOWN,self.OnKeyPressed)
self.control.Bind(wx.EVT_CHAR,self.OnChar)
self.Show(True)
因為代碼提示是在鍵入的過程中發生的,是以需要跟蹤鍵盤事件,是以把按鍵事件與處理函數做了綁定。
AutoComplete類
在代碼提示過程中需要動态根據使用者輸入提供建議,是以建立了一個_autocomplete對象,它的類代碼:
class AutoComplete:
def __init__(self):
self.suggests=keyword.kwlist
self.prefix=""
self.key=""
def append(self,char):
self.prefix+=char
def back(self):
if len(self.prefix)>1:
self.prefix=self.prefix[:-1]
else:
self.prefix=""
def clear(self):
self.prefix=""
@property
def length(self):
return len(self.prefix)
def getsugs(self):
return [word for word in self.suggests if word.startswith(self.prefix)]
這個類維護一個使用者目前已輸入的字元串,使用者每輸入一個字元都附加在字元串後面,每次輸入倒退鍵,字元串删掉最後的字元。getsugs()函數根據字元串在關鍵字清單中查找比對的候選關鍵字,并傳回一個推薦清單。
跟蹤鍵盤事件
def OnKeyPressed(self,evt):
key=evt.GetKeyCode()
control=evt.ControlDown()
alt=evt.AltDown()
shift=evt.ShiftDown()
if key in self.AutoCompStopwords and not control and not alt and not shift:
if self.control.AutoCompActive():
self.control.AutoCompComplete()
self._autocomplete.clear()
elif key==wx.WXK_BACK and not control and not alt and not shift:
self._autocomplete.back()
self.code_complete()
evt.Skip()
def OnChar(self,evt):
control = evt.ControlDown()
alt = evt.AltDown()
shift = evt.ShiftDown()
try:
char = chr(evt.GetUnicodeKey())
if char.isprintable() and char!=" ":
self._autocomplete.append(char)
except ValueError:
#self._autocomplete.clear()
if self.control.AutoCompActive():
self.control.AutoCompCancel()
if not control and not alt and not shift:
self.code_complete()
evt.Skip()
我們提供了兩個跟蹤鍵盤事件的函數,它們之間還是有些差別的。主要目的是區分可列印字元與功能鍵。AutoCompStopwords就是指定遇到什麼樣的按鍵代碼提示結束,常見的包括回車、空格、分号、點号等。代碼提示結束有兩種情況,一種是使用者在清單中選擇其中一項,填入到編輯器中,另一種是使用者輸入的内容比對不到任何關鍵字。
每個處理函數後面都加上了evt.Skip()目的是不要打破系統的消息處理機制,使得系統有時間處理必要的消息。有點像以前VB時代的DoEvents。
在遇到AutoCompStopwords後,需要把_autocomplete中的字元串清空,等待下一個詞的編輯。這兩個事件處理代碼中都調用了code_complete()函數,其代碼:
def code_complete(self):
choices=self._autocomplete.getsugs()
if choices and self._autocomplete.length>=1:
choices.sort()
self.control.AutoCompShow(self._autocomplete.length-1," ".join(choices))
else:
if self.control.AutoCompActive():
self.control.AutoCompCancel()
就是擷取推薦清單,并顯示在編輯器中。AutoCompShow(nlength,suggents),其中第一個參數nlength是指比對多少個字元開始顯示,suggents是一個分隔符隔開的推薦清單字元串,分隔符可以設定,不過一般保持預設就可以了,預設是空格。
建立主程式
建立一個主程式的入口,并建立消息循環機制。這些都是wxPython的規定動作。
if __name__=="__main__":
app=wx.App(False)
frame=myFrame(None,'Simple Editor')
app.MainLoop()