[wxPython-users] Re: ComboBox: Incorrect usage?

Frank Millman frank at chagford.com
Thu Jul 26 22:44:11 PDT 2007


Steve Holden wrote: 
> Thanks, that's a win. I'll let the list know if I make any 
> progress on this - I suspect I may need to create something 
> like a pop-up pull-down list to do this properly.
> 

FYI, I had some success with a customised ComboCtrl, which I got to emulate
a wx.Choice but with some additional features. Maybe you could do something
similar. Attached is a program that shows what I did.

Frank
-------------- next part --------------
#!/usr/bin/env python
import sys
import wx
import wx.combo

class MyChoice(wx.combo.ComboCtrl):
    def __init__(self,parent,choices,selection,size,pos):
        wx.combo.ComboCtrl.__init__(self,parent,size=size,pos=pos)
        MyComboPopup(self,choices,selection)
        self.textCtrl = self.GetTextCtrl()
        self.textCtrl.Bind(wx.EVT_SET_FOCUS,self.onGotFocus)
        self.textCtrl.Bind(wx.EVT_KILL_FOCUS,self.onLostFocus)
        self.count = 0
        self.nav = False

    def onGotFocus(self,evt):
        self.count += 1
        print self.count,'got focus'
        if self.nav:
            self.nav = False
            wx.CallAfter(self.Navigate)
        evt.Skip()

    def onLostFocus(self,evt):
        print self.count,'lost focus'
        self.textCtrl.SetSelection(0,0)
        evt.Skip()

class MyComboPopup(wx.ListBox, wx.combo.ComboPopup):
    def __init__(self,comboCtrl,choices,selection):
        self.comboCtrl = comboCtrl
        self.choices = choices
        self.curitem = self.selection = selection
        wx.combo.ComboPopup.__init__(self)
        comboCtrl.SetPopupControl(self)
        comboCtrl.SetValue(choices[selection])

    def Create(self, parent):
        # Create the popup child control.  Return true for success.
        self.listBox = wx.ListBox(parent,choices=self.choices)
        self.listBox.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
        self.listBox.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
        return True

    def OnKeyDown(self, evt):
        if evt.KeyCode == wx.WXK_DOWN:
            if self.curitem < len(self.choices)-1:
                self.curitem += 1
                self.listBox.Select(self.curitem)
                return
        if evt.KeyCode == wx.WXK_UP:
            if self.curitem > 0:
                self.curitem -= 1
                self.listBox.Select(self.curitem)
                return
        if evt.KeyCode == wx.WXK_ESCAPE:
            self.Dismiss()
            return
        if evt.KeyCode in (wx.WXK_TAB,wx.WXK_SPACE,wx.WXK_RETURN,wx.WXK_NUMPAD_ENTER):
            self.selection = self.curitem
            self.comboCtrl.nav = True
            self.Dismiss()
            return

    def OnLeftDown(self, evt):
        item = self.listBox.HitTest(evt.GetPosition())
        if item > -1:
            self.selection = item
            self.Dismiss()

    def GetControl(self):
        # Return the widget that is to be used for the popup
        return self.listBox

    def GetStringValue(self):
        # Return a string representation of the current item.
        return self.choices[self.selection]

    def OnPopup(self):
        # Called immediately after the popup is shown
        print 'popup'
        self.curitem = self.selection
        self.listBox.Select(self.selection)
        wx.combo.ComboPopup.OnPopup(self)

    def OnDismiss(self):
        # Called when popup is dismissed
        print 'dismiss'
        wx.combo.ComboPopup.OnDismiss(self)

    def OnComboKeyEvent(self, evt):
        # Receives key events from the parent ComboCtrl.  Events not
        # handled should be skipped, as usual.
        if evt.KeyCode == wx.WXK_SPACE:
            self.comboCtrl.ShowPopup()
        elif evt.KeyCode == wx.WXK_DOWN:
            if self.selection < len(self.choices)-1:
                self.selection += 1
                self.comboCtrl.SetValue(self.choices[self.selection])
                self.comboCtrl.GetTextCtrl().SetSelection(-1,-1)
        elif evt.KeyCode == wx.WXK_UP:
            if self.selection > 0:
                self.selection -= 1
                self.comboCtrl.SetValue(self.choices[self.selection])
                self.comboCtrl.GetTextCtrl().SetSelection(-1,-1)

    def GetAdjustedSize(self, minWidth, prefHeight, maxHeight):
        # Return final size of popup. Called on every popup, just prior to OnPopup.
        # minWidth = preferred minimum width for window
        # prefHeight = preferred height. Only applies if > 0,
        # maxHeight = max height for window, as limited by screen size
        #   and should only be rounded down, if necessary.
        if sys.platform == 'win32':
            prefHeight = 15 * len(self.choices)
        else:
            prefHeight = 26 * len(self.choices)
        return wx.combo.ComboPopup.GetAdjustedSize(self, minWidth, prefHeight, maxHeight)

class MyPanel(wx.Panel):
    def __init__(self,parent):
        wx.Panel.__init__(self,parent,-1)

        choices = ['Category 1','Category 2','Category 3']
        selection = 1

        wx.StaticText(self,-1,'Field1',pos=(50,30))
        wx.TextCtrl(self,-1,'',size=(180,-1),pos=(150,30))

        wx.StaticText(self,-1,'Field2',pos=(50,80))
        MyChoice(self,choices,selection,size=(180,-1),pos=(150,80))

        wx.StaticText(self,-1,'Field3',pos=(50,130))
        wx.TextCtrl(self,-1,'',size=(180,-1),pos=(150,130))

        self.SetFocus()

class MyFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self,None,-1,"Custom ComboCtrl test",size=(400,200))
        panel = MyPanel(self)
        self.CentreOnScreen()

class MyApp(wx.App):
    def OnInit(self):
        frame = MyFrame()
        frame.Show(1)
        return 1

app = MyApp(0)
app.MainLoop()


More information about the wxpython-users mailing list