(Note: this code does not currently run on Mac, since wxMAC does not yet support PopupWindow.) (Will Sadkin 8/05/2008: This may no longer be true-- see below.) (Daniel Levine 7/10/2010: This is still not supported on Macs as of wxPython 2.8.10.1) Michele Petrazzo modified the code for use '''wxList{{{}}}Ctrl''' instead of '''wxList{{{}}}Box''', so now TextCtrlAutoComplete can handle more than one column, has column sorting, can fetch the data on the column you want and at the end, can call a "callback" function when an item are select. Will Sadkin modified the code to allow dynamic generation of the select list based on what's typed, added an argument to hide the dropdown if no match, added an option to set a match function, and enhanced the demo to show how you can now do dynamic list updates based on what is typed. ------------------ Comments ----------------- == Comment by Franz Steinhaeusler == If I replace the init line of the textctrl, . wx.Text''''''Ctrl.__init__( self , parent , style = wx.TE_PROCESS_ENTER, **therest ) when the Enter Key seems to be processed accordingly. I see, your implementation to this is much better than mine. :) == Comment by Edward Flick == Thanks Franz I think we just about tied for the solution to that. I had just added the TE_PROCESS_ENTER dynamically in the init section. Either way :-). So do you have any idea on how to fix the Popup''''''Window issue? == Comment by Franz Steinhaeusler == No, sorry. I will ask in the wxPython mailing list. Michele Petrazzo posted a solution using a List''''''Ctrl instead of a List''''''Box. http://lists.wxwidgets.org/cgi-bin/ezmlm-cgi?11:mss:47543:200602:jjhfcaoagldbfbigklnf == Comment by Michele Petrazzo == New class uploaded == Comment by Michele Petrazzo == Add two interface methods: '''setMultiple{{{}}}Choices''' and '''set{{{}}}Choices''' that permit to modify the list after the initialization. == Comment by Edward Flick == Changed __init__ to support single column list of choices (was broken). Also, changed the sort function to locale specific sort (as is used in the mixin). Commented out the mixin sort called at the beginning, since its unnecessary. == Comment by Michele Petrazzo == Change the sort methods for prevent the old (python 2.3) sort method that not accepting arguments == Comment by Will Sadkin == Fixed bug in design that could leave fetch column set to a non-existent column if you switched from a multi-choice to a single choice list, causing the control not to autocomplete. Instead, '''.set{{{}}}Choices()''' now automatically sets colSearch and colFetch to 0 and -1, respectively, (as there's only one choice), and '''.setMultiple{{{}}}Choices()''' now takes ''colSearch'' and ''colFetch'' as arguments. (I also changed fetchCol to colFetch, to be consistent with colSearch and colNames.) I also made the behavior more consistent with the Firefox address bar behavior, so that when the control is empty(ied), the dropdown is hidden, and added a constructor argument, ''hideOn{{{}}}No{{{}}}Match'' (by default True), so that when a user is typing, if nothing in the choice list matches, the dropdown is hidden as well. (Finally, I fixed this wiki page to not put wiki links in where none were meant to be.) == Comment by Will Sadkin == * Fixed another bug with case-sensitive sorting in choice list, but case-insensitive sorting in '''List{{{}}}Ctrl''', causing incorrect selection from the list when auto-completing. * Changed single-column display to not show an empty header in the dropdown, to better match address bar look and feel, and to make the control look right when the choice list is empty. * Renamed existing callBack argument to selectCallback, added entryCallback, added matchFunction, and setters for each of these. * Changed the Mixed{{{}}}Case format of the control's public methods to match rest of wx.Python. * Changed '''Set{{{}}}Choices''' and '''Set{{{}}}Multiple{{{}}}Choices''' to not auto-clear the text control when the list changes, so you can do dynamic updates of the list based on what is typed. * Added button in demo to demonstrate both dynamic list generation and "smart" matching via match function-- Click the '''Enable dynamic choices''' button, and then try typing 'as' or 'www', and see what happens! * Attached a working copy of the source for easier extension by others, (so they don't have to cut & paste from the above and then remove the trailing whitespaces in the bitmaps.) == Comment by Marc Hedlund == This class looks great -- thanks to the people who have worked on it. As a note so that others are aware, the class depends on Popup``Window, which is not currently (Jan 2008) implemented on Mac. If you need something cross-platform, you'll have to look elsewhere... == Comment by Will Sadkin == According to http://trac.wxwidgets.org/ticket/9377, as of 6/27/2008, wxWidgets was updated to support Popup``Window... I don't know how long it will take for wxPython to incorporate this change, but someone who has access to a Mac should check this out and update this page if this restriction no longer applies.) == Comment by Marcelo Fernandez == This widget is great! And it also works passing a cursor.fetchall() (from a SQLite DB) to the !SetMultipleChoices() method. :-) I was looking at the custom widget !TextCtrl and implementing it in a little application I'm developing. The thing is, the widget works very well overall, but I added a new method which I needed: {{{#!python def GetSelectedItems(self): ''' Returns the complete listbox item selected as a list ''' dd = self.dropdownlistbox sel = dd.GetFirstSelected() if sel > -1: values = [dd.GetItem(sel, x).GetText() for x in xrange(dd.GetColumnCount())] return values else: return None }}} It borrows a lot of code from the internal "_setValueFromSelected()" method, but its intention is to return the selected listbox item as a list. I needed it because in the "Save Form" button I wanted to know not only the !TextCtrl value, but all the !ListCtrl values selected; and I didn't want to set a callback to _selectCallback() (which adds more code). IMHO, I think this approach to get all the !ListCtrl values stored there, in any time, is cleaner. == Comment by Matthijs Sypkens Smit == I believe to have discovered a bug in the current code (29-7-2009). In lines 101-105 ('gp = self' to 'gp = gp.GetParent()') bindings are created to catch movement and resize events for parents. However, these are never removed when the control is terminated. The problem came to light when I put the control on a custom dialog. After the dialog had been destroyed I got PyDeadObjectErrors: "wx._core.PyDeadObjectError: The C++ part of the TextCtrlAutoComplete object has been deleted, attribute access no longer allowed." The following code fixed it, at least for my case. I inserted them between line 105 and 106, but there might be {{{#!python def handler_close(evt): # unbinding... gp = self while ( gp != None ) : gp.Unbind( wx.EVT_MOVE , gp, -1, -1) gp.Unbind( wx.EVT_SIZE , gp, -1, -1) gp = gp.GetParent() self.Bind(wx.EVT_WINDOW_DESTROY, handler_close) }}} == Comment by Matthijs Sypkens Smit == This widget does not work perfectly when placed on a modal dialog. I suspect this is because the ListBox is on a separate popup window. Doubleclick on an item in the listbox or scrolling with the scrollbars does not work on a modal dialog. Scrolling with the keyboard does work. == Comment by James Hofmann == 16 October 2009: Clarified the exact usage of multiChoices(the test was incorrect before). == Comment by Daniel Levine == 10 July 2010: Checked with a friend who has wxPython on a Mac (wxPython 2.8.10.1) and got a non-implementation error. This still does not work for Macs.