Introduction
This recipe offers a wxComboBox subclass that will display the first entire item from its dropdown list whose initial characters match those that the user has typed, with untyped characters selected.
What Objects are Involved
Only wx.ComboBox itself.
Process Overview
When the user keys a 'c', for instance, we want the code to identify the first combobox choice that begins with 'c', and to display it in the combobox with the characters following 'c' "selected". One does this in response to the wx.EVT_TEXT event. When one changes the content of the combobox, however, this ellicits another wx.EVT_TEXT event and this leads to infinite recursion.
To prevent this we arrange to ignore the second wx.EVT_TEXT that is ellicited.
Similar code is used to make it possible for the control to respond properly to backspaces, and when the user selects a choice from the dropdown list.
Special Concerns
The code in the loop in the wx.EVT_TEXT handler might well be changed so that the combobox would accept plugins providing different suggestion options; for example, the most frequently selected option could be offered.
Code Sample
1 import wx
2
3 class PromptingComboBox(wx.ComboBox) :
4 def __init__(self, parent, value, choices=[], style=0, **par):
5 wx.ComboBox.__init__(self, parent, wx.ID_ANY, value, style=style|wx.CB_DROPDOWN, choices=choices, **par)
6 self.choices = choices
7 self.Bind(wx.EVT_TEXT, self.EvtText)
8 self.Bind(wx.EVT_CHAR, self.EvtChar)
9 self.Bind(wx.EVT_COMBOBOX, self.EvtCombobox)
10 self.ignoreEvtText = False
11
12 def EvtCombobox(self, event):
13 self.ignoreEvtText = True
14 event.Skip()
15
16 def EvtChar(self, event):
17 if event.GetKeyCode() == 8:
18 self.ignoreEvtText = True
19 event.Skip()
20
21 def EvtText(self, event):
22 if self.ignoreEvtText:
23 self.ignoreEvtText = False
24 return
25 currentText = event.GetString()
26 found = False
27 for choice in self.choices :
28 if choice.startswith(currentText):
29 self.ignoreEvtText = True
30 self.SetValue(choice)
31 self.SetInsertionPoint(len(currentText))
32 self.SetMark(len(currentText), len(choice))
33 found = True
34 break
35 if not found:
36 event.Skip()
37
38 class TrialPanel(wx.Panel):
39 def __init__(self, parent):
40 wx.Panel.__init__(self, parent, wx.ID_ANY)
41
42 choices = ['grandmother', 'grandfather', 'cousin', 'aunt', 'uncle', 'grandson', 'granddaughter']
43 for relative in ['mother', 'father', 'sister', 'brother', 'daughter', 'son']:
44 choices.extend(self.derivedRelatives(relative))
45
46 cb = PromptingComboBox(self, "default value", choices, style=wx.CB_SORT)
47
48 def derivedRelatives(self, relative):
49 return [relative, 'step' + relative, relative + '-in-law']
50
51
52 if __name__ == '__main__':
53 app = wx.App()
54 frame = wx.Frame (None, -1, 'Demo PromptingComboBox Control', size=(400, 50))
55 TrialPanel(frame)
56 frame.Show()
57 app.MainLoop()
Comments
Any comments or suggestions, to Bill Bell, please.