[wxPython-users] ComboBox: Incorrect usage?

Frank Millman frank at chagford.com
Thu Jul 26 06:49:26 PDT 2007


Steve Holden wrote: 
> 
> I was hoping to be able to code wxComboBox to allow me to 
> enter text and look up possible selections in a database - a 
> little like the AJAX-style pulldowns you see all over the web 
> nowadays.
> 
> This is my best effort so far, but clearing the control 
> appears to leave the text empty, and if I put a value in the 
> text the insertion point is set at the start of the text. 
> Setting the insertion point by removing the comment marker 
> from the last line seems to lead to a loop, repeatedly 
> printing out the single entered character until the program 
> eventually terminates with no further output.
> 
>      def OnCompanyChar(self, event):
>          """Set combo dropdown to companies whose names match 
> the combo text."""
>          combo = self.FindWindowById(cmbCompany)
>          txt = combo.GetValue()
>          sql = "SELECT orgName, orgID from organization WHERE
> lower(orgName) LIKE %s ORDER BY orgName"
>          self.curs.execute(sql, (txt + "%", ))
>          vals = self.curs.fetchall()
>          combo.Clear()
>          combo.AppendItems([v[0] for v in vals])
>          #combo.SetSelection(wx.NOT_FOUND)
>          print txt
>          combo.SetValue(txt)
>          #combo.SetInsertionPoint(len(txt)-1)
> 
> Attempts to debug the code with Wing tells me that an 
> uncaught Win32 exception is being raised. I suspect I am 
> doing something obviously wrong, but it isn't shrieking at me.
> 

Hi Steve

I don't have a full answer, but I played around a bit and found a clue.

I assume you are using MSW, as the problem does not seem to arise with GTK2.

I found that calling combo.SetInsertionPoint(n) on MSW generates an EVT_TEXT
event - heaven only knows why. I assume your entire method is driven by
catching this event, therefore you end up in a loop.

You will see from the attached program that I work around it by setting a
flag, and skipping the event the second time if the flag is set. This is
totally non-portable, as with GTK2 this means that you skip every second
character, but it does explain what is happening.

The attached program is just doodling - it does not do much. If you get a
full working solution, please post a working example here - I would find it
interesting. In particular, how do you get the box to display its drop-down
as you type, so you can see which items are available. Every time I type a
character, the drop-down closes.

A small point - I found that instead of
    combo.Clear()
    combo.AppendItems([...])

you can just say
    combo.SetItems([...])

It seems to do the same thing.

HTH

Frank Millman
-------------- next part --------------
#!/usr/bin/env python
import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(360,240))
        MyPanel(self)

class MyPanel(wx.Panel):
    def __init__(self,frame):
        wx.Panel.__init__(self,frame,-1)
        data = ['Apples','Oranges','Pears','Bananas','Peaches']
        combo = wx.ComboBox(self,-1,'',pos=(10,10),choices=data)
        combo.Bind(wx.EVT_COMBOBOX,self.onComboBox)
        combo.Bind(wx.EVT_TEXT,self.onComboText)
        combo.Bind(wx.EVT_TEXT_ENTER,self.onComboEnter)
        combo.Bind(wx.EVT_KILL_FOCUS,self.onComboLostFocus)
        button = wx.Button(self,-1,'Change list',pos=(10,60))
        button.Bind(wx.EVT_BUTTON,self.onButton)
        combo.SetFocus()
        self.combo = combo
        self.data = data
        self.inserted = False

    def onComboBox(self,evt):
        print evt.EventObject.Value

    def onComboText(self,evt):
        if self.inserted:
            print 'INSERTED'
            self.inserted = False
            return
        print evt.EventObject.Value
        txt = evt.EventObject.Value
        lng = len(txt)
        data = [x[:-lng] for x in self.data]
        self.combo.SetItems(data)
        self.combo.Value = txt
        self.inserted = True
        self.combo.SetInsertionPoint(len(txt))

    def onComboEnter(self,evt):
        print evt.EventObject.Value

    def onComboLostFocus(self,evt):
        print evt.EventObject.Value

    def onButton(self,evt):
#       self.combo.SetSelection(wx.NOT_FOUND)
        self.combo.Value = ''
        data = ['Peas','Beans','Carrots','Tomatoes','Cauliflower']
        self.combo.SetItems(data)

class MyApp(wx.App):
    def OnInit(self):
        frame = MyFrame(None, -1, "Test ComboBox")
        frame.CentreOnScreen()
        frame.Show(True)
        self.SetTopWindow(frame)
        return True

app = MyApp(0)     # Create an instance of the application class
app.MainLoop()     # Tell it to start processing events


More information about the wxpython-users mailing list