TextCtrlAutoComplete.py
changeset 268 66843376a982
child 295 bc6fc07c3153
equal deleted inserted replaced
267:e12fb29fe797 268:66843376a982
       
     1 
       
     2 '''
       
     3 
       
     4 wxPython Custom Widget Collection 20060207
       
     5 Written By: Edward Flick (eddy -=at=- cdf-imaging -=dot=- com)
       
     6             Michele Petrazzo (michele -=dot=- petrazzo -=at=- unipex -=dot=- it)
       
     7             Will Sadkin (wsadkin-=at=- nameconnector -=dot=- com)
       
     8 Copyright 2006 (c) CDF Inc. ( http://www.cdf-imaging.com )
       
     9 Contributed to the wxPython project under the wxPython project's license.
       
    10 
       
    11 '''
       
    12 
       
    13 import locale, wx, sys, cStringIO
       
    14 
       
    15 import  wx.lib.mixins.listctrl  as  listmix
       
    16 import cPickle
       
    17 from wx import ImageFromStream, BitmapFromImage
       
    18 #----------------------------------------------------------------------
       
    19 def getSmallUpArrowData():
       
    20     return \
       
    21 '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
       
    22 \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
       
    23 \x00\x00<IDAT8\x8dcddbf\xa0\x040Q\xa4{h\x18\xf0\xff\xdf\xdf\xffd\x1b\x00\xd3\
       
    24 \x8c\xcf\x10\x9c\x06\xa0k\xc2e\x08m\xc2\x00\x97m\xd8\xc41\x0c \x14h\xe8\xf2\
       
    25 \x8c\xa3)q\x10\x18\x00\x00R\xd8#\xec\xb2\xcd\xc1Y\x00\x00\x00\x00IEND\xaeB`\
       
    26 \x82'
       
    27 
       
    28 def getSmallUpArrowBitmap():
       
    29     return BitmapFromImage(getSmallUpArrowImage())
       
    30 
       
    31 def getSmallUpArrowImage():
       
    32     stream = cStringIO.StringIO(getSmallUpArrowData())
       
    33     return ImageFromStream(stream)
       
    34 
       
    35 
       
    36 def getSmallDnArrowData():
       
    37     return \
       
    38 "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
       
    39 \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
       
    40 \x00\x00HIDAT8\x8dcddbf\xa0\x040Q\xa4{\xd4\x00\x06\x06\x06\x06\x06\x16t\x81\
       
    41 \xff\xff\xfe\xfe'\xa4\x89\x91\x89\x99\x11\xa7\x0b\x90%\ti\xc6j\x00>C\xb0\x89\
       
    42 \xd3.\x10\xd1m\xc3\xe5*\xbc.\x80i\xc2\x17.\x8c\xa3y\x81\x01\x00\xa1\x0e\x04e\
       
    43 ?\x84B\xef\x00\x00\x00\x00IEND\xaeB`\x82"
       
    44 
       
    45 def getSmallDnArrowBitmap():
       
    46     return BitmapFromImage(getSmallDnArrowImage())
       
    47 
       
    48 def getSmallDnArrowImage():
       
    49     stream = cStringIO.StringIO(getSmallDnArrowData())
       
    50     return ImageFromStream(stream)
       
    51 #----------------------------------------------------------------------
       
    52 
       
    53 class myListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin):
       
    54     def __init__(self, parent, ID=-1, pos=wx.DefaultPosition,
       
    55                  size=wx.DefaultSize, style=0):
       
    56         wx.ListCtrl.__init__(self, parent, ID, pos, size, style)
       
    57         listmix.ListCtrlAutoWidthMixin.__init__(self)
       
    58 
       
    59 class TextCtrlAutoComplete (wx.TextCtrl, listmix.ColumnSorterMixin ):
       
    60 
       
    61     def __init__ ( self, parent, colNames=None, choices = None,
       
    62                   multiChoices=None, showHead=True, dropDownClick=True,
       
    63                   colFetch=-1, colSearch=0, hideOnNoMatch=True,
       
    64                   selectCallback=None, entryCallback=None, matchFunction=None,
       
    65                   element_path=None, **therest) :
       
    66         '''
       
    67         Constructor works just like wx.TextCtrl except you can pass in a
       
    68         list of choices.  You can also change the choice list at any time
       
    69         by calling setChoices.
       
    70         '''
       
    71 
       
    72         if therest.has_key('style'):
       
    73             therest['style']=wx.TE_PROCESS_ENTER | therest['style']
       
    74         else:
       
    75             therest['style']=wx.TE_PROCESS_ENTER
       
    76 
       
    77         wx.TextCtrl.__init__(self, parent, **therest )
       
    78 
       
    79         #Some variables
       
    80         self._dropDownClick = dropDownClick
       
    81         self._colNames = colNames
       
    82         self._multiChoices = multiChoices
       
    83         self._showHead = showHead
       
    84         self._choices = choices
       
    85         self._lastinsertionpoint = 0
       
    86         self._hideOnNoMatch = hideOnNoMatch
       
    87         self._selectCallback = selectCallback
       
    88         self._entryCallback = entryCallback
       
    89         self._matchFunction = matchFunction
       
    90 
       
    91         self._screenheight = wx.SystemSettings.GetMetric( wx.SYS_SCREEN_Y )
       
    92         self.element_path = element_path
       
    93         #sort variable needed by listmix
       
    94         self.itemDataMap = dict()
       
    95 
       
    96         #widgets
       
    97         self.dropdown = wx.PopupWindow( self )
       
    98 
       
    99         #Control the style
       
   100         flags = wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_SORT_ASCENDING
       
   101         if not (showHead and multiChoices) :
       
   102             flags = flags | wx.LC_NO_HEADER
       
   103 
       
   104         #Create the list and bind the events
       
   105         self.dropdownlistbox = myListCtrl( self.dropdown, style=flags,
       
   106                                  pos=wx.Point( 0, 0) )
       
   107 
       
   108         #initialize the parent
       
   109         if multiChoices: ln = len(multiChoices)
       
   110         else: ln = 1
       
   111         #else: ln = len(choices)
       
   112         listmix.ColumnSorterMixin.__init__(self, ln)
       
   113 
       
   114         #load the data
       
   115         if multiChoices: self.SetMultipleChoices (multiChoices, colSearch=colSearch, colFetch=colFetch)
       
   116         else: self.SetChoices ( choices )
       
   117 
       
   118         #gp = self
       
   119         #while ( gp != None ) :
       
   120         #    gp.Bind ( wx.EVT_MOVE , self.onControlChanged, gp )
       
   121         #    gp.Bind ( wx.EVT_SIZE , self.onControlChanged, gp )
       
   122         #    gp = gp.GetParent()
       
   123 
       
   124         self.Bind( wx.EVT_KILL_FOCUS, self.onControlChanged, self )
       
   125         self.Bind( wx.EVT_TEXT , self.onEnteredText, self )
       
   126         self.Bind( wx.EVT_KEY_DOWN , self.onKeyDown, self )
       
   127 
       
   128         #If need drop down on left click
       
   129         if dropDownClick:
       
   130             self.Bind ( wx.EVT_LEFT_DOWN , self.onClickToggleDown, self )
       
   131             self.Bind ( wx.EVT_LEFT_UP , self.onClickToggleUp, self )
       
   132 
       
   133         self.dropdown.Bind( wx.EVT_LISTBOX , self.onListItemSelected, self.dropdownlistbox )
       
   134         self.dropdownlistbox.Bind(wx.EVT_LEFT_DOWN, self.onListClick)
       
   135         self.dropdownlistbox.Bind(wx.EVT_LEFT_DCLICK, self.onListDClick)
       
   136         self.dropdownlistbox.Bind(wx.EVT_LIST_COL_CLICK, self.onListColClick)
       
   137 
       
   138         self.il = wx.ImageList(16, 16)
       
   139 
       
   140         self.sm_dn = self.il.Add(getSmallDnArrowBitmap())
       
   141         self.sm_up = self.il.Add(getSmallUpArrowBitmap())
       
   142 
       
   143         self.dropdownlistbox.SetImageList(self.il, wx.IMAGE_LIST_SMALL)
       
   144         self._ascending = True
       
   145 
       
   146 
       
   147     #-- methods called from mixin class
       
   148     def GetSortImages(self):
       
   149         return (self.sm_dn, self.sm_up)
       
   150 
       
   151     def GetListCtrl(self):
       
   152         return self.dropdownlistbox
       
   153 
       
   154     # -- event methods
       
   155     def onListClick(self, evt):
       
   156         toSel, flag = self.dropdownlistbox.HitTest( evt.GetPosition() )
       
   157         #no values on poition, return
       
   158         if toSel == -1: return
       
   159         self.dropdownlistbox.Select(toSel)
       
   160 
       
   161     def onListDClick(self, evt):
       
   162         self._setValueFromSelected()
       
   163 
       
   164     def onListColClick(self, evt):
       
   165         col = evt.GetColumn()
       
   166 
       
   167         #reverse the sort
       
   168         if col == self._colSearch:
       
   169             self._ascending = not self._ascending
       
   170 
       
   171         self.SortListItems( evt.GetColumn(), ascending=self._ascending )
       
   172         self._colSearch = evt.GetColumn()
       
   173         evt.Skip()
       
   174 
       
   175     def onEnteredText(self, event):
       
   176         text = event.GetString()
       
   177 
       
   178         if self._entryCallback:
       
   179             self._entryCallback()
       
   180 
       
   181         if not text:
       
   182             # control is empty; hide dropdown if shown:
       
   183             if self.dropdown.IsShown():
       
   184                 self._showDropDown(False)
       
   185             event.Skip()
       
   186             return
       
   187 
       
   188 
       
   189         found = False
       
   190         if self._multiChoices:
       
   191             #load the sorted data into the listbox
       
   192             dd = self.dropdownlistbox
       
   193             choices = [dd.GetItem(x, self._colSearch).GetText()
       
   194                 for x in xrange(dd.GetItemCount())]
       
   195         else:
       
   196             choices = self._choices
       
   197 
       
   198         for numCh, choice in enumerate(choices):
       
   199             if self._matchFunction and self._matchFunction(text, choice):
       
   200                 found = True
       
   201             elif choice.lower().startswith(text.lower()) :
       
   202                 found = True
       
   203             if found:
       
   204                 self._showDropDown(True)
       
   205                 item = self.dropdownlistbox.GetItem(numCh)
       
   206                 toSel = item.GetId()
       
   207                 self.dropdownlistbox.Select(toSel)
       
   208                 break
       
   209 
       
   210         if not found:
       
   211             self.dropdownlistbox.Select(self.dropdownlistbox.GetFirstSelected(), False)
       
   212             if self._hideOnNoMatch:
       
   213                 self._showDropDown(False)
       
   214 
       
   215         self._listItemVisible()
       
   216 
       
   217         event.Skip ()
       
   218 
       
   219     def onKeyDown ( self, event ) :
       
   220         """ Do some work when the user press on the keys:
       
   221             up and down: move the cursor
       
   222             left and right: move the search
       
   223         """
       
   224         skip = True
       
   225         sel = self.dropdownlistbox.GetFirstSelected()
       
   226         visible = self.dropdown.IsShown()
       
   227 
       
   228         KC = event.GetKeyCode()
       
   229         if KC == wx.WXK_DOWN :
       
   230             if sel < (self.dropdownlistbox.GetItemCount () - 1) :
       
   231                 self.dropdownlistbox.Select ( sel+1 )
       
   232                 self._listItemVisible()
       
   233             self._showDropDown ()
       
   234             skip = False
       
   235         elif KC == wx.WXK_UP :
       
   236             if sel > 0 :
       
   237                 self.dropdownlistbox.Select ( sel - 1 )
       
   238                 self._listItemVisible()
       
   239             self._showDropDown ()
       
   240             skip = False
       
   241         elif KC == wx.WXK_LEFT :
       
   242             if not self._multiChoices: return
       
   243             if self._colSearch > 0:
       
   244                 self._colSearch -=1
       
   245             self._showDropDown ()
       
   246         elif KC == wx.WXK_RIGHT:
       
   247             if not self._multiChoices: return
       
   248             if self._colSearch < self.dropdownlistbox.GetColumnCount() -1:
       
   249                 self._colSearch += 1
       
   250             self._showDropDown()
       
   251 
       
   252         if visible :
       
   253             if event.GetKeyCode() == wx.WXK_RETURN :
       
   254                 self._setValueFromSelected()
       
   255                 skip = False
       
   256             if event.GetKeyCode() == wx.WXK_ESCAPE :
       
   257                 self._showDropDown( False )
       
   258                 skip = False
       
   259         if skip :
       
   260             event.Skip()
       
   261 
       
   262     def onListItemSelected (self, event):
       
   263         self._setValueFromSelected()
       
   264         event.Skip()
       
   265 
       
   266     def onClickToggleDown(self, event):
       
   267         self._lastinsertionpoint = self.GetInsertionPoint()
       
   268         event.Skip ()
       
   269 
       
   270     def onClickToggleUp ( self, event ) :
       
   271         if ( self.GetInsertionPoint() == self._lastinsertionpoint ) :
       
   272             self._showDropDown ( not self.dropdown.IsShown() )
       
   273         event.Skip ()
       
   274 
       
   275     def onControlChanged(self, event):
       
   276         res = self.GetValue()
       
   277         config = wx.ConfigBase.Get()
       
   278         listentries = cPickle.loads(str(config.Read(self.element_path, cPickle.dumps([]))))
       
   279         if len(res) and res not in listentries:
       
   280             config.Write(self.element_path, cPickle.dumps((listentries + [res])[-10:]))
       
   281             config.Flush()
       
   282             self.SetChoices((listentries + [res])[-10:])
       
   283         self._showDropDown( False )
       
   284         event.Skip()
       
   285 
       
   286 
       
   287     # -- Interfaces methods
       
   288     def SetMultipleChoices(self, choices, colSearch=0, colFetch=-1):
       
   289         ''' Set multi-column choice
       
   290         '''
       
   291         self._multiChoices = choices
       
   292         self._choices = None
       
   293         if not isinstance(self._multiChoices, list):
       
   294             self._multiChoices = [ x for x in self._multiChoices]
       
   295 
       
   296         flags = wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_SORT_ASCENDING
       
   297         if not self._showHead:
       
   298             flags |= wx.LC_NO_HEADER
       
   299         self.dropdownlistbox.SetWindowStyleFlag(flags)
       
   300 
       
   301         #prevent errors on "old" systems
       
   302         if sys.version.startswith("2.3"):
       
   303             self._multiChoices.sort(lambda x, y: cmp(x[0].lower(), y[0].lower()))
       
   304         else:
       
   305             self._multiChoices.sort(key=lambda x: locale.strxfrm(x[0]).lower() )
       
   306 
       
   307         self._updateDataList(self._multiChoices)
       
   308 
       
   309         lChoices = len(choices)
       
   310         if lChoices < 2:
       
   311             raise ValueError, "You have to pass me a multi-dimension list"
       
   312 
       
   313         for numCol, rowValues in enumerate(choices[0]):
       
   314 
       
   315             if self._colNames: colName = self._colNames[numCol]
       
   316             else: colName = "Select %i" % numCol
       
   317 
       
   318             self.dropdownlistbox.InsertColumn(numCol, colName)
       
   319 
       
   320         for numRow, valRow in enumerate(choices):
       
   321 
       
   322             for numCol, colVal in enumerate(valRow):
       
   323                 if numCol == 0:
       
   324                     index = self.dropdownlistbox.InsertImageStringItem(sys.maxint, colVal, -1)
       
   325                 self.dropdownlistbox.SetStringItem(index, numCol, colVal)
       
   326                 self.dropdownlistbox.SetItemData(index, numRow)
       
   327 
       
   328         self._setListSize()
       
   329         self._colSearch = colSearch
       
   330         self._colFetch = colFetch
       
   331 
       
   332     def SetChoices(self, choices):
       
   333         '''
       
   334         Sets the choices available in the popup wx.ListBox.
       
   335         The items will be sorted case insensitively.
       
   336         '''
       
   337         self._choices = choices
       
   338         self._multiChoices = None
       
   339         flags = wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_SORT_ASCENDING | wx.LC_NO_HEADER
       
   340         self.dropdownlistbox.SetWindowStyleFlag(flags)
       
   341                 
       
   342         #if not isinstance(choices, list):
       
   343         #    self._choices = [ x for x in choices if len(x)]
       
   344         self._choices = [ x for x in choices if len(x)]
       
   345         #prevent errors on "old" systems
       
   346         if sys.version.startswith("2.3"):
       
   347             self._choices.sort(lambda x, y: cmp(x.lower(), y.lower()))
       
   348         else:
       
   349             self._choices.sort(key=lambda x: locale.strxfrm(x).lower())
       
   350 
       
   351         self._updateDataList(self._choices)
       
   352 
       
   353         self.dropdownlistbox.InsertColumn(0, "")
       
   354 
       
   355         for num, colVal in enumerate(self._choices):
       
   356             index = self.dropdownlistbox.InsertImageStringItem(sys.maxint, colVal, -1)
       
   357 
       
   358             self.dropdownlistbox.SetStringItem(index, 0, colVal)
       
   359             self.dropdownlistbox.SetItemData(index, num)
       
   360 
       
   361         self._setListSize()
       
   362 
       
   363         # there is only one choice for both search and fetch if setting a single column:
       
   364         self._colSearch = 0
       
   365         self._colFetch = -1
       
   366 
       
   367     def GetChoices(self):
       
   368         if self._choices:
       
   369             return self._choices
       
   370         else:
       
   371             return self._multiChoices
       
   372 
       
   373     def SetSelectCallback(self, cb=None):
       
   374         self._selectCallback = cb
       
   375 
       
   376     def SetEntryCallback(self, cb=None):
       
   377         self._entryCallback = cb
       
   378 
       
   379     def SetMatchFunction(self, mf=None):
       
   380         self._matchFunction = mf
       
   381 
       
   382 
       
   383     #-- Internal methods
       
   384     def _setValueFromSelected( self ) :
       
   385          '''
       
   386          Sets the wx.TextCtrl value from the selected wx.ListCtrl item.
       
   387          Will do nothing if no item is selected in the wx.ListCtrl.
       
   388          '''
       
   389          sel = self.dropdownlistbox.GetFirstSelected()
       
   390          if sel > -1:
       
   391             if self._colFetch != -1: col = self._colFetch
       
   392             else: col = self._colSearch
       
   393 
       
   394             itemtext = self.dropdownlistbox.GetItem(sel, col).GetText()
       
   395             if self._selectCallback:
       
   396                 dd = self.dropdownlistbox
       
   397                 values = [dd.GetItem(sel, x).GetText()
       
   398                     for x in xrange(dd.GetColumnCount())]
       
   399                 self._selectCallback( values )
       
   400 
       
   401             self.SetValue (itemtext)
       
   402             self.SetInsertionPointEnd ()
       
   403             self.SetSelection ( -1, -1 )
       
   404             self._showDropDown ( False )
       
   405 
       
   406 
       
   407     def _showDropDown ( self, show = True ) :
       
   408         '''
       
   409         Either display the drop down list (show = True) or hide it (show = False).
       
   410         '''
       
   411         if show :
       
   412             size = self.dropdown.GetSize()
       
   413             width, height = self . GetSizeTuple()
       
   414             x, y = self . ClientToScreenXY ( 0, height )
       
   415             if size.GetWidth() != width :
       
   416                 size.SetWidth(width)
       
   417                 self.dropdown.SetSize(size)
       
   418                 self.dropdownlistbox.SetSize(self.dropdown.GetClientSize())
       
   419             if (y + size.GetHeight()) < self._screenheight :
       
   420                 self.dropdown . SetPosition ( wx.Point(x, y) )
       
   421             else:
       
   422                 self.dropdown . SetPosition ( wx.Point(x, y - height - size.GetHeight()) )
       
   423         self.dropdown.Show ( show )
       
   424 
       
   425     def _listItemVisible( self ) :
       
   426         '''
       
   427         Moves the selected item to the top of the list ensuring it is always visible.
       
   428         '''
       
   429         toSel =  self.dropdownlistbox.GetFirstSelected ()
       
   430         if toSel == -1: return
       
   431         self.dropdownlistbox.EnsureVisible( toSel )
       
   432 
       
   433     def _updateDataList(self, choices):
       
   434         #delete, if need, all the previous data
       
   435         if self.dropdownlistbox.GetColumnCount() != 0:
       
   436             self.dropdownlistbox.DeleteAllColumns()
       
   437             self.dropdownlistbox.DeleteAllItems()
       
   438 
       
   439         #and update the dict
       
   440         if choices:
       
   441             for numVal, data in enumerate(choices):
       
   442                 self.itemDataMap[numVal] = data
       
   443         else:
       
   444             numVal = 0
       
   445         self.SetColumnCount(numVal)
       
   446 
       
   447     def _setListSize(self):
       
   448         if self._multiChoices:
       
   449             choices = self._multiChoices
       
   450         else:
       
   451             choices = self._choices
       
   452 
       
   453         longest = 0
       
   454         for choice in choices :
       
   455             longest = max(len(choice), longest)
       
   456 
       
   457         longest += 3
       
   458         itemcount = min( len( choices ) , 7 ) + 2
       
   459         charheight = self.dropdownlistbox.GetCharHeight()
       
   460         charwidth = self.dropdownlistbox.GetCharWidth()
       
   461         self.popupsize = wx.Size( charwidth*longest, charheight*itemcount )
       
   462         self.dropdownlistbox.SetSize ( self.popupsize )
       
   463         self.dropdown.SetClientSize( self.popupsize )
       
   464 
       
   465     
       
   466 
       
   467 
       
   468 class test:
       
   469     def __init__(self):
       
   470         args = dict()
       
   471         if 1:
       
   472             args["colNames"] = ("col1", "col2")
       
   473             args["multiChoices"] = [ ("Zoey","WOW"), ("Alpha", "wxPython"),
       
   474                                     ("Ceda","Is"), ("Beta", "fantastic"),
       
   475                                     ("zoebob", "!!")]
       
   476             args["colFetch"] = 1
       
   477         else:
       
   478             args["choices"] = ["123", "cs", "cds", "Bob","Marley","Alpha"]
       
   479 
       
   480         args["selectCallback"] = self.selectCallback
       
   481 
       
   482         self.dynamic_choices = [
       
   483                         'aardvark', 'abandon', 'acorn', 'acute', 'adore',
       
   484                         'aegis', 'ascertain', 'asteroid',
       
   485                         'beautiful', 'bold', 'classic',
       
   486                         'daring', 'dazzling', 'debonair', 'definitive',
       
   487                         'effective', 'elegant',
       
   488                         'http://python.org', 'http://www.google.com',
       
   489                         'fabulous', 'fantastic', 'friendly', 'forgiving', 'feature',
       
   490                         'sage', 'scarlet', 'scenic', 'seaside', 'showpiece', 'spiffy',
       
   491                         'www.wxPython.org', 'www.osafoundation.org'
       
   492                         ]
       
   493 
       
   494 
       
   495         app = wx.PySimpleApp()
       
   496         frm = wx.Frame(None,-1,"Test",style=wx.TAB_TRAVERSAL|wx.DEFAULT_FRAME_STYLE)
       
   497         panel = wx.Panel(frm)
       
   498         sizer = wx.BoxSizer(wx.VERTICAL)
       
   499 
       
   500         self._ctrl = TextCtrlAutoComplete(panel, **args)
       
   501         but = wx.Button(panel,label="Set other multi-choice")
       
   502         but.Bind(wx.EVT_BUTTON, self.onBtMultiChoice)
       
   503         but2 = wx.Button(panel,label="Set other one-colum choice")
       
   504         but2.Bind(wx.EVT_BUTTON, self.onBtChangeChoice)
       
   505         but3 = wx.Button(panel,label="Set the starting choices")
       
   506         but3.Bind(wx.EVT_BUTTON, self.onBtStartChoices)
       
   507         but4 = wx.Button(panel,label="Enable dynamic choices")
       
   508         but4.Bind(wx.EVT_BUTTON, self.onBtDynamicChoices)
       
   509 
       
   510         sizer.Add(but, 0, wx.ADJUST_MINSIZE, 0)
       
   511         sizer.Add(but2, 0, wx.ADJUST_MINSIZE, 0)
       
   512         sizer.Add(but3, 0, wx.ADJUST_MINSIZE, 0)
       
   513         sizer.Add(but4, 0, wx.ADJUST_MINSIZE, 0)
       
   514         sizer.Add(self._ctrl, 0, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
       
   515         panel.SetAutoLayout(True)
       
   516         panel.SetSizer(sizer)
       
   517         sizer.Fit(panel)
       
   518         sizer.SetSizeHints(panel)
       
   519         panel.Layout()
       
   520         app.SetTopWindow(frm)
       
   521         frm.Show()
       
   522         but.SetFocus()
       
   523         app.MainLoop()
       
   524 
       
   525     def onBtChangeChoice(self, event):
       
   526         #change the choices
       
   527         self._ctrl.SetChoices(["123", "cs", "cds", "Bob","Marley","Alpha"])
       
   528         self._ctrl.SetEntryCallback(None)
       
   529         self._ctrl.SetMatchFunction(None)
       
   530 
       
   531     def onBtMultiChoice(self, event):
       
   532         #change the choices
       
   533         self._ctrl.SetMultipleChoices( [ ("Test","Hello"), ("Other word","World"),
       
   534                                         ("Yes!","it work?") ], colFetch = 1 )
       
   535         self._ctrl.SetEntryCallback(None)
       
   536         self._ctrl.SetMatchFunction(None)
       
   537 
       
   538     def onBtStartChoices(self, event):
       
   539         #change the choices
       
   540         self._ctrl.SetMultipleChoices( [ ("Zoey","WOW"), ("Alpha", "wxPython"),
       
   541                                     ("Ceda","Is"), ("Beta", "fantastic"),
       
   542                                     ("zoebob", "!!")], colFetch = 1 )
       
   543         self._ctrl.SetEntryCallback(None)
       
   544         self._ctrl.SetMatchFunction(None)
       
   545 
       
   546     def onBtDynamicChoices(self, event):
       
   547         '''
       
   548         Demonstrate dynamic adjustment of the auto-complete list, based on what's
       
   549         been typed so far:
       
   550         '''
       
   551         self._ctrl.SetChoices(self.dynamic_choices)
       
   552         self._ctrl.SetEntryCallback(self.setDynamicChoices)
       
   553         self._ctrl.SetMatchFunction(self.match)
       
   554 
       
   555 
       
   556     def match(self, text, choice):
       
   557         '''
       
   558         Demonstrate "smart" matching feature, by ignoring http:// and www. when doing
       
   559         matches.
       
   560         '''
       
   561         t = text.lower()
       
   562         c = choice.lower()
       
   563         if c.startswith(t): return True
       
   564         if c.startswith(r'http://'): c = c[7:]
       
   565         if c.startswith(t): return True
       
   566         if c.startswith('www.'): c = c[4:]
       
   567         return c.startswith(t)
       
   568 
       
   569     def setDynamicChoices(self):
       
   570         ctrl = self._ctrl
       
   571         text = ctrl.GetValue().lower()
       
   572         current_choices = ctrl.GetChoices()
       
   573         choices = [choice for choice in self.dynamic_choices if self.match(text, choice)]
       
   574         if choices != current_choices:
       
   575             ctrl.SetChoices(choices)
       
   576 
       
   577     def selectCallback(self, values):
       
   578         """ Simply function that receive the row values when the
       
   579             user select an item
       
   580         """
       
   581         print "Select Callback called...:",  values
       
   582 
       
   583 
       
   584 if __name__ == "__main__":
       
   585     test()
       
   586