天天看點

使用wxStyledTextCtrl實作代碼提示

       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()