Using ListCtrl for Keyboard and Programmatic Input, not working

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: