Reputation: 322
I would want to have a ComboBox with autocomplete as I have a list of more than 1000 items and would like to be able to select one element without having to go through the whole list, by only having part of the item string in the ComboBox.
I have been looking around and the question has been answered multiple times and I even checked the following link from a previous question here:
and this other link:
However, when I try to run the example codes I always get the error: "module 'wx' has no attribute 'SimpleHtmlListBox'/'HtmlListBox' ".
What might be the reason for the error? And are there maybe other ways to achieve an autocomplete ComboBox?
Upvotes: 0
Views: 2054
Reputation: 332
I have converted the code in the first link you gave to make it work in python 3, wxPython Phoenix. Some changes has been added to make the combo box work better. The first comboBox has been tested it in Mac OSX. But when I tested it Linux gtk+, it doesn't work as expected so I created a work around in second line with a TextCtrl as a filter for comboBox.
import wx
class PromptingComboBox(wx.ComboBox) :
def __init__(self, parent, choices=[], style=0, **par):
wx.ComboBox.__init__(self, parent, wx.ID_ANY, style=style|wx.CB_DROPDOWN, choices=choices, **par)
self.choices = choices
self.Bind(wx.EVT_TEXT, self.OnText)
self.Bind(wx.EVT_KEY_DOWN, self.OnPress)
self.ignoreEvtText = False
self.deleteKey = False
def OnPress(self, event):
if event.GetKeyCode() == 8:
self.deleteKey = True
event.Skip()
def OnText(self, event):
currentText = event.GetString()
if self.ignoreEvtText:
self.ignoreEvtText = False
return
if self.deleteKey:
self.deleteKey = False
if self.preFound:
currentText = currentText[:-1]
self.preFound = False
for choice in self.choices :
if choice.startswith(currentText):
self.ignoreEvtText = True
self.SetValue(choice)
self.SetInsertionPoint(len(currentText))
self.SetTextSelection(len(currentText), len(choice))
self.preFound = True
break
class TrialPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, wx.ID_ANY)
choices = ['grandmother', 'grandfather', 'cousin', 'aunt', 'uncle', 'grandson', 'granddaughter']
for relative in ['mother', 'father', 'sister', 'brother', 'daughter', 'son']:
choices.extend(self.derivedRelatives(relative))
self.choices = choices = sorted(choices)
mainSizer = wx.FlexGridSizer(2, 2, 5, 10)
self.SetSizer(mainSizer)
mainSizer.Add(wx.StaticText(
self, -1, "Worked in Mac - python 3 - wx phoenix"))
cb1 = PromptingComboBox(self, choices=choices)
mainSizer.Add(cb1)
mainSizer.Add(wx.StaticText(self, -1, "Work arround in Linux-gtk"))
sizer2 = wx.BoxSizer(wx.HORIZONTAL)
mainSizer.Add(sizer2)
filterCtrl = wx.TextCtrl(self, -1, size=(150, -1))
filterCtrl.Bind(wx.EVT_TEXT, self.OnFilter)
sizer2.Add(filterCtrl)
self.cb2 = wx.ComboBox(self, -1, size=(150, -1), choices=choices)
sizer2.Add(self.cb2)
def derivedRelatives(self, relative):
return [relative, 'step' + relative, relative + '-in-law']
def OnFilter(self, event):
currentText = event.GetString().upper()
tmpChoices = [c for c in self.choices if c.startswith(currentText)]
if tmpChoices != []:
self.cb2.SetItems(tmpChoices)
self.cb2.SetValue(tmpChoices[0])
else:
self.cb2.SetValue('')
self.cb2.SetItems([])
if __name__ == '__main__':
app = wx.App(False)
frame = wx.Frame (None, -1, 'Demo PromptingComboBox Control and Work around',
size=(700, 400))
TrialPanel(frame)
frame.Show()
app.MainLoop()
Upvotes: 1