My program collects data and stores it in lists. I use a ListCtrl to get user input; after each char typed in, it looks in a list to find a match and offers a whole string to be accepted or ignored. Acceptance is to be via the Enter key.
The problem is that after offering the match in the list, it is highlighted grey and not blue, and cannot be accepted by the Enter key, only by doubleclick with the mouse.
If I substitute the user input with a wx.TextEntryDialog, it works properly with the offer highlighted blue and acceptable with Enter. I am sure there are standard ways to provide look-up for repeated user entries, but I haven’t managed to find one.
I have two scripts which demonstrate the problem, but as a total newbie I don’t know whether to include these opn this page or upload files - your help very much appreciated.
Hi,
Posting your scripts would help. If you want to paste the code in a post, please put 3 backtick characters (`) before the first line of code and 3 more backtick characters after the last line of code. That will prevent the forum software from formatting it as markup text and thus wrecking the indentation, etc.
In the example below I call the ListCtrl’s Focus()
method as well as its Select()
method. Pressing the Enter key then does trigger the event handler.
Tested using wxPython 4.2.1 + Python 3.10.12 + Linux Mint 21.3.
import wx
class MyFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent)
self.SetSize((400, 300))
self.SetTitle("Test ListCtrl Activate")
self.panel = wx.Panel(self, wx.ID_ANY)
sizer = wx.BoxSizer(wx.VERTICAL)
self.list_ctrl = wx.ListCtrl(self.panel, wx.ID_ANY, style=wx.LC_HRULES | wx.LC_REPORT | wx.LC_VRULES)
self.list_ctrl.AppendColumn("A", format=wx.LIST_FORMAT_LEFT, width=200)
sizer.Add(self.list_ctrl, 1, wx.EXPAND, 0)
self.panel.SetSizer(sizer)
self.Layout()
self.insertItems()
self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnActivated, self.list_ctrl)
self.list_ctrl.Focus(2)
self.list_ctrl.Select(2)
def insertItems(self):
for i in range(0, 8):
self.list_ctrl.InsertItem(i, f"Item {i+1}")
def OnActivated(self, event):
print(event.GetText())
if __name__ == "__main__":
app = wx.App(0)
frame = MyFrame(None)
frame.Show()
app.MainLoop()
Hi and thanks for your thoughts. Here is the non-working code
import wx
class MyForm(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "Illustrative script")
panel = wx.Panel(self, wx.ID_ANY)
self.list_ctrl = wx.ListCtrl(panel, size=(-1,100),
style=wx.LC_REPORT | wx.LC_SINGLE_SEL
|wx.BORDER_SUNKEN)
self.list_ctrl.InsertColumn(0, 'Artist', width=200)
self.list_ctrl.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.Enter)
self.cdartist = wx.TextCtrl(panel, wx.ID_ANY, "") #Artist input
self.cdartist.SetMinSize((180, 27))
self.Bind(wx.EVT_TEXT, self.art_input, self.cdartist) #fires each time entry changes
# add some artists
self.list_ctrl.Append(['Andras Schiff'])
self.list_ctrl.Append(['Bob Dylan'])
self.list_ctrl.Append(['Murray Perahia'])
self.list_ctrl.Append(['Kieth Jarret'])
self.flag1 = True #True denotes keyboard input, False program input
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.list_ctrl, 0, wx.ALL|wx.EXPAND, 5)
sizer.Add(self.cdartist, 0, wx.ALL, 3)
panel.SetSizer(sizer)
self.cdartist.SetFocus()
# get the first char of an artist in the list
def art_input(self, event): #Runs whenever text in cdartist changes
if self.flag1: #Input is from keyboard
typed = self.cdartist.GetValue()
self.Checkname(self.list_ctrl, typed.title())
self.flag1 = True
event.Skip
def Checkname(self, l, n): #finds str n in list l
i = l.FindItem(-1, n, True)
l.Select(i,1) #present possible choice
def Enter(self, event):
self.flag1 = False
chose = self.list_ctrl.GetItem(self.list_ctrl.GetFirstSelected()).Text
self.cdartist.SetValue(chose)
if __name__ == "__main__":
app = wx.App(False)
frame = MyForm()
frame.Show()
app.MainLoop()
Try this change:
def Checkname(self, l, n): # finds str n in list l
i = l.FindItem(-1, n, True)
l.Focus(i)
l.Select(i, 1) # present possible choice
l.SetFocus()
Also, in art_input()
you have the statement event.Skip
- this needs parentheses event.Skip()
if you intend to actually call the method.
Wonderful!Thanks. I thought I had tried every combination of Select() and Focus(). Also I scattered Skip() about the place and wasn’t concentrating. Thanks again.
I just checked page wx.ListCtrl — wxPython Phoenix 4.2.1 documentation and it doesn’t mention SetFocus() as a method. Are there classes of methods which apply generally to any widget?
Yes. The way to find them is to expand the class’s Inheritance diagram. You can then click on the various base classes in the diagram to quickly navigate to their document pages and see what methods the class you are interested in will inherit. In that way you should see that SetFocus()
is inherited from wx.Window
.
EDIT:
A useful feature of an IDE like PyCharm is that it will show you an object’s matching methods in a drop-down list, including which base class they come from: