autocomplete

walterigo at yahoo.com walterigo at yahoo.com
Sat Jun 10 22:39:47 CEST 2006


hello.
    I have been working all too hard trying to figure out how to get
TextCtrlAutoComplete.py  to start another word after it finishes the
last word. I want it to start the autocomplete process all over again
after it finishes the autocomplete process. I have striped down the
program to a smaller version than the orginal. it now works in a
multiline wx.textctrl box. belive that the program only needs one or
two lines to complete the taks and start all over again.

here is a copy of the code


'''

wxPython Custom Widget Collection 20060207
Written By: Edward Flick ()
            Michele Petrazzo (michele -=dot=- petrazzo -=at=- unipex
-=dot=- it)
            Will Sadkin (wsadkin-=at=- nameconnector -=dot=- com)
Copyright 2006 (c) CDF Inc. ( http://www.cdf-imaging.com )
Contributed to the wxPython project under the wxPython project's
license.

'''



import wx
import sys

import  wx.lib.mixins.listctrl  as  listmix


class myListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin):
    def __init__(self,
                parent,
                ID=-1,
                pos=wx.DefaultPosition,
                size=wx.DefaultSize,
                style=0):
        wx.ListCtrl.__init__(self, parent, ID, pos, size, style)
        listmix.ListCtrlAutoWidthMixin.__init__(self)

class TextCtrlAutoComplete (wx.TextCtrl, listmix.ColumnSorterMixin ):

    def __init__ ( self, parent, choices = None,
                showHead=False, dropDownClick=True,
                colFetch=-1, colSearch=0, hideOnNoMatch=True,
                selectCallback=None, entryCallback=None,
matchFunction=None,
                **therest) :
        '''
        Constructor works just like wx.TextCtrl except you can pass in
a
        list of choices.  You can also change the choice list at any
time
        by calling setChoices.
        '''

        if therest.has_key('style'):
            therest['style']=wx.TE_PROCESS_ENTER | therest['style']
        else:
            therest['style']=wx.TE_PROCESS_ENTER


wx.TextCtrl.__init__(self,parent,-1,'',size=(500,500),style=wx.TE_MULTILINE)
        #wx.TextCtrl.__init__(self, parent, **therest )
        self._hideOnNoMatch = hideOnNoMatch
        self._selectCallback = selectCallback
        self._matchFunction = matchFunction
        self._screenheight = wx.SystemSettings.GetMetric(
wx.SYS_SCREEN_Y )

        #sort variable needed by listmix
        self.itemDataMap = dict()

        #widgets
        self.dropdown = wx.PopupWindow( self )

        #Control the style
        flags = wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_SORT_ASCENDING
        if not (showHead) :
            flags = flags | wx.LC_NO_HEADER

        #Create the list and bind the events
        self.dropdownlistbox = myListCtrl( self.dropdown, style=flags,
                                 pos=wx.Point( 0, 0) )
        gp = self
        while ( gp != None ) :
           gp = gp.GetParent()
        self.Bind( wx.EVT_TEXT , self.onEnteredText, self )
        self.Bind( wx.EVT_KEY_DOWN , self.onKeyDown, self )
        self.dropdownlistbox.Bind(wx.EVT_LEFT_DCLICK,
self.onListDClick)

    def onListDClick(self, evt):
        self._setValueFromSelected()

    def onEnteredText(self, event):
        text = event.GetString()
        #print('onEnterdText text: ',text)
        if self._entryCallback:
            self._entryCallback()


        if not text:
            # control is empty; hide dropdown if shown:
            if self.dropdown.IsShown():
                self._showDropDown(False)
            event.Skip()
            return
        found = False
        choices = self._choices

        for numCh, choice in enumerate(choices):
            if self._matchFunction and self._matchFunction(text,
choice):
                found = True
            elif choice.lower().startswith(text.lower()) :
                found = True
            if found:
                self._showDropDown(True)
                item = self.dropdownlistbox.GetItem(numCh)
                toSel = item.GetId()
                self.dropdownlistbox.Select(toSel)
                break

        if not found:

self.dropdownlistbox.Select(self.dropdownlistbox.GetFirstSelected(),
False)
            if self._hideOnNoMatch:
                self._showDropDown(False)

        self._listItemVisible()

        event.Skip ()

    def onKeyDown ( self, event ) :
        """ Do some work when the user press on the keys:
            up and down: move the cursor
            left and right: move the search
        """
        skip = True

        sel = self.dropdownlistbox.GetFirstSelected()
        visible = self.dropdown.IsShown()

        KC = event.GetKeyCode()
        if KC == wx.WXK_DOWN :
            if sel < (self.dropdownlistbox.GetItemCount () - 1) :
                self.dropdownlistbox.Select ( sel+1 )
                self._listItemVisible()
            self._showDropDown ()
            skip = False
        elif KC == wx.WXK_UP :
            if sel > 0 :
                self.dropdownlistbox.Select ( sel - 1 )
                self._listItemVisible()
            self._showDropDown ()
            skip = False

        if visible :
            if event.GetKeyCode() == wx.WXK_RETURN :
                self._setValueFromSelected()
                skip = False
            if event.GetKeyCode() == wx.WXK_ESCAPE :
                self._showDropDown( False )
                skip = False
        if skip :
            event.Skip()

    def onListItemSelected (self, event):
        self._setValueFromSelected()
        event.Skip()

    def onClickToggleDown(self, event):
        self._lastinsertionpoint = self.GetInsertionPoint()
        event.Skip ()

    def onClickToggleUp ( self, event ) :
        if ( self.GetInsertionPoint() == self._lastinsertionpoint ) :
            self._showDropDown ( not self.dropdown.IsShown() )
        event.Skip ()


    # -- Interfaces methods



    def SetChoices(self, choices):

        #Sets the choices available in the popup wx.ListBox.
        #The items will be sorted case insensitively.
        self._choices = choices
        flags = wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_SORT_ASCENDING
| wx.LC_NO_HEADER
        self._updateDataList(self._choices)
        self.dropdownlistbox.InsertColumn(0, "")
        for num, colVal in enumerate(self._choices):
            index =
self.dropdownlistbox.InsertImageStringItem(sys.maxint, colVal, -1)
            self.dropdownlistbox.SetStringItem(index, 0, colVal)
            self.dropdownlistbox.SetItemData(index, num)

        self._setListSize()

        # there is only one choice for both search and fetch if setting
a single column:
        self._colSearch = 0
        self._colFetch = -1
    def SetSelectCallback(self, cb=None):
        self._selectCallback = cb

    def SetEntryCallback(self, cb=None):
        self._entryCallback = cb

    #-- Internal methods
    def _setValueFromSelected( self ) :
         '''
         Sets the wx.TextCtrl value from the selected wx.ListCtrl item.
         Will do nothing if no item is selected in the wx.ListCtrl.
         '''
         sel = self.dropdownlistbox.GetFirstSelected()
         if sel > -1:
            if self._colFetch != -1: col = self._colFetch
            else: col = self._colSearch
            itemtext = self.dropdownlistbox.GetItem(sel, col).GetText()

            if self._selectCallback:
                dd = self.dropdownlistbox
                values = [dd.GetItem(sel, x).GetText()
                    for x in xrange(dd.GetColumnCount())]
                self._selectCallback( values )


            self.SetValue (itemtext)
            self.SetInsertionPointEnd ()
            self.SetSelection ( -1, -1 )
            self._showDropDown ( False )



    def _showDropDown ( self, show = True ) :
        '''
        Either display the drop down list (show = True) or hide it
(show = False).
        '''

        if show :
            size = self.dropdown.GetSize()
            width, height = self . GetSizeTuple()
            x, y = self . ClientToScreenXY ( wx.CentreX+6, wx.CentreY+6
)
            if size.GetWidth() != width :
                size.SetWidth(width)
                self.dropdown.SetSize(size)

self.dropdownlistbox.SetSize(self.dropdown.GetClientSize())
            if (y + size.GetHeight()) < self._screenheight :
                self.dropdown . SetPosition ( wx.Point(x, y) )
            else:
                self.dropdown . SetPosition ( wx.Point(x, y - height -
size.GetHeight()) )
        self.dropdown.Show ( show )

    def _listItemVisible( self ) :
        '''
        Moves the selected item to the top of the list ensuring it is
always visible.
        '''
        toSel =  self.dropdownlistbox.GetFirstSelected ()
        if toSel == -1: return
        self.dropdownlistbox.EnsureVisible( toSel )

    def _updateDataList(self, choices):
        #delete, if need, all the previous data
        if self.dropdownlistbox.GetColumnCount() != 0:
            self.dropdownlistbox.DeleteAllColumns()
            self.dropdownlistbox.DeleteAllItems()

        #and update the dict
        if choices:
            for numVal, data in enumerate(choices):
                self.itemDataMap[numVal] = data
                #print("data is %s",data)
        else:
            numVal = 0
        self.SetColumnCount(numVal)

    def _setListSize(self):
        choices = self._choices
        longest = 0
        for choice in choices :
            longest = max(len(choice), longest)

        #longest += 3
        itemcount = min( len( choices ) , 7 ) + .5
        charheight = self.dropdownlistbox.GetCharHeight()
        charwidth = self.dropdownlistbox.GetCharWidth()
        self.popupsize = wx.Size( charwidth*longest,
charheight*itemcount )
        self.dropdownlistbox.SetSize ( self.popupsize )
        self.dropdown.SetClientSize( self.popupsize )





class test:
    def __init__(self):
        args = dict()
        args["selectCallback"] = self.selectCallback

        self.dynamic_choices = [
                        'hello world', 'abandon', 'acorn', 'acute',
'adore',
                        'aegis', 'ascertain', 'asteroid',
                        'beautiful', 'bold', 'classic',
                        'daring', 'dazzling', 'debonair', 'definitive',
                        'effective', 'elegant',
                        'http://python.org', 'http://www.google.com',
                        'fabulous', 'fantastic', 'friendly',
'forgiving', 'feature',
                        'sage', 'scarlet', 'scenic', 'seaside',
'showpiece', 'spiffy',
                        'www.wxPython.org', 'www.osafoundation.org'
                        ]


        app = wx.PySimpleApp()
        frm = wx.Frame(None,-1,"Test",
        style=wx.CLEAR
        |wx.DEFAULT_FRAME_STYLE
        )
        panel = wx.Panel(frm)
        self._ctrl = TextCtrlAutoComplete(panel, **args)
        self.onBtDynamicChoices(self.onBtDynamicChoices)

        frm.Show()
        app.MainLoop()


    def onBtDynamicChoices(self, event):
        self._ctrl.SetChoices(self.dynamic_choices)
        self._ctrl.SetEntryCallback(self.setDynamicChoices)


    def match(self, text, choice):
        t = text.lower()
        c = choice.lower()
        #print('The Value is %S',choice)
        return c.startswith(t)

    def setDynamicChoices(self):
        if wx.EVT_KEY_DOWN == ' ': print "Space bar pressed"
        text = self._ctrl.GetValue().lower()
        choices = [choice for choice in self.dynamic_choices if
self.match(text, choice)]
        self._ctrl.SetChoices(choices)
        #print('The Value is %S',text)

    def selectCallback(self, values):
        """ Simply function that receive the row values when the
            user select an item
        """
        print "Select Callback called...:",  values
        self.wordCheck(values)

    def wordCheck(self,values):
        pass #print"Word to check:",values

    
if __name__ == "__main__":
    test()




More information about the Python-list mailing list