changing choices list on a combobox

I am new to the list. I’m learning a lot of great stuff from you guys–wish I had looked into this a long time ago!

I have been working on a problem where I want to change the choices list on a combobox control after it has been created. I have two simple questions plus a general one:

  1. I am guessing that you are not able to change the choices list once the combobox has been added to the frame by Layout(). I can’t find a Set() method like with wx.ListBox. I think this is probably due to the potential that changing the list could change the basic layout of the control itself. Correct me if I am wrong. This would be the ideal solution but I am not hopeful.

  2. Is there a way to change the sequence of tab traversal through the widgets in a dialog? I explain below why I am asking if you want to invest the time to look.

  3. Is there a good workaround than what I have come up with? This requires you to look at my situation in more detail.

The details of my situation are this: I define a wx.Dialog. In init I define ‘myCbx’ as a wx.ComboBox with choices=oldlist and place it in a gridsizer which is nested within other sizers. The dialog is opened with ShowModal(). An event occurs (a button is clicked) which is handled by an eventhandler function. In this function oldlist is changed to newlist. Before leaving the function, I want to replace oldlist with newlist in myCbx. I have tried the following:

  1. Replace the control. I used this method:

gsizer.Detach(myCbx)

myCbx.Destroy()

myCbx = wx.ComboBox(self,id#,…choices=newlist…)

self.Bind(wx.EVT_COMBOBOX, …)

gsizer.Insert(index,myCbx)

self.Layout()

This is simple and works very well. The combobox has the required choices list and everything works as expected except that myCbx is now at the end of the tab traversal order. I thought that using the identical name and id# in the new widget would correct this, so I set arbitrary idnumbers for all the widgets in the gridsizer (in init) and then used the same id# for the new combobox as for the old, but it didn’t help. Does anyone know how to change the order of tab traversal?

  1. Redefine the topsizer. I thought maybe if I did a new layout for the entire dialog that the tab traversal would work right. So I did this, still within the event handler function:

myCbx.Destroy()

myCbx = wx.ComboBox(self,id#,…choices=newlist…)

self.Bind(wx.EVT_COMBOBOX, …)

topsizer.Destroy()

call a function (also used in init ) to:

…define subsizers and add widgets

…define the gridsizer and add widgets including the new myCbx

…define other subsizers and add widgets

…add all subsizers to topsizer

self.Layout()

This works as well as replacing the combobox, but doesn’t affect the tab traversal problem. [By the way, before I did this I tried just replacing the gridsizer–same result.]

  1. Redefine all the widgets. It seems that the tabs follow the order in which the widgets are created–the new myCbx always goes to the end of the traversal order. I haven’t tried this, but maybe I would have to do the following, still within the eventhandler function:

a) gather all the current data values for the widgets in the dialog–not too hard, but maybe harder than I think

b) define wlist = [list of all widgets except the button that binds to the eventhandler function which is now executing]

c) for w in wlist : w.Destroy()

d) pass the current data values (including the newlist for myCbx) for all the destroyed widgets to a function that defines all those widgets again (I could use this function in init as well)

e) then do the same as above–destroy the topsizer, define all the sizers again, do self.Layout()

I think this might work, but it ain’t pretty. The button that isn’t destroyed and redefined will probably still be out of taborder. One last idea is to close the dialog and pass the current data back to a new instance of the dialog. Can someone suggest a better way?

Thanks in advance for your help. Maybe sometime soon I will know enough to contribute.

Leon,

I am new to the list. I'm learning a lot of great stuff from you guys--wish I had looked into this a long time ago!
I have been working on a problem where I want to change the choices list on a combobox control after it has been created. I have two simple questions plus a general one:
1) I am guessing that you are not able to change the choices list once the combobox has been added to the frame by Layout(). I can't find a Set() method like with wx.ListBox. I think this is probably due to the potential that changing the list could change the basic layout of the control itself. Correct me if I am wrong. This would be the ideal solution but I am not hopeful.

When I want to change the contents of my combobox, I call its Clear() method and then I append each new item I want. So something like this:

<code>
myCombo.Clear()
myList = [1,2,3,4,5]
for item in myList:
    myCombo.Append(item)
</code>

Of course, you'll need to make sure you list is in the order that you want it...

2) Is there a way to change the sequence of tab traversal through the widgets in a dialog? I explain below why I am asking if you want to invest the time to look.

By default, the tab order is the order of the creation of the widgets that can accept focus. Robin added some new methods in 2.8 (I think) called MoveAfterInTabOrder and MoveBeforeInTabOrder. See wxPython API Documentation — wxPython Phoenix 4.2.2 documentation

[...snip...]

Hope that helps.

···

-------------------
Mike Driscoll

Blog: http://blog.pythonlibrary.org
Python Extension Building Network: http://www.pythonlibrary.org

Leon M Tolman MD wrote:

I am new to the list. I'm learning a lot of great stuff from you
guys--wish I had looked into this a long time ago!

I have been working on a problem where I want to change the choices
list on a combobox control after it has been created. I have two
simple questions plus a general one:

1) I am guessing that you are not able to change the choices list
once the combobox has been added to the frame by Layout(). I can't
find a Set() method like with wx.ListBox. I think this is probably
due to the potential that changing the list could change the basic
layout of the control itself. Correct me if I am wrong. This would
be the ideal solution but I am not hopeful.

Sure, it can be changed.

    cb.Clear()
    cb.Append( 'New Item 1' )
    cb.Append( 'New Item 2' )

2) Is there a way to change the sequence of tab traversal through the
widgets in a dialog? I explain below why I am asking if you want to
invest the time to look.

By replacing the list in place, you shouldn't need this. However, every
control has MoveAfterInTabOrder and MoveBeforeInTabOrder functions that
let you adjust this.

···

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

Leon M Tolman MD wrote:

1) I am guessing that you are not able to change the choices list once the combobox has been added to the frame by Layout(). I can't find a Set() method like with wx.ListBox. I think this is probably due to the potential that changing the list could change the basic layout of the control itself. Correct me if I am wrong. This would be the ideal solution but I am not hopeful.

What do you say to:

  self._box.Clear()
  for item in newlist:
      self._box.Append(item)

Perhaps you have oversight, that wx.ComboBox is a wxControlWithItems and that the item-operations are not listed in the wxComboBox documentation.

Great! Certainly simpler than what I was doing. Nice to know about the taborder methods, too.

Thanks,
Leon

···

Leon,

I am new to the list. I'm learning a lot of great stuff from you guys--wish I had looked into this a long time ago!
I have been working on a problem where I want to change the choices list on a combobox control after it has been created. I have two simple questions plus a general one:
1) I am guessing that you are not able to change the choices list once the combobox has been added to the frame by Layout(). I can't find a Set() method like with wx.ListBox. I think this is probably due to the potential that changing the list could change the basic layout of the control itself. Correct me if I am wrong. This would be the ideal solution but I am not hopeful.

When I want to change the contents of my combobox, I call its Clear() method and then I append each new item I want. So something like this:

<code>
myCombo.Clear()
myList = [1,2,3,4,5]
for item in myList:
   myCombo.Append(item)
</code>

Of course, you'll need to make sure you list is in the order that you want it...

2) Is there a way to change the sequence of tab traversal through the widgets in a dialog? I explain below why I am asking if you want to invest the time to look.

By default, the tab order is the order of the creation of the widgets that can accept focus. Robin added some new methods in 2.8 (I think) called MoveAfterInTabOrder and MoveBeforeInTabOrder. See wxPython API Documentation — wxPython Phoenix 4.2.2 documentation

[...snip...]

Hope that helps.

-------------------
Mike Driscoll

Blog: http://blog.pythonlibrary.org
Python Extension Building Network: http://www.pythonlibrary.org

_______________________________________________
wxpython-users mailing list
wxpython-users@lists.wxwidgets.org
http://lists.wxwidgets.org/mailman/listinfo/wxpython-users

Thanks for your help. Simple, I guess I overlooked these inherited methods. Leon

···

----- Original Message ----- From: "Tim Roberts" <timr@probo.com>
To: <wxpython-users@lists.wxwidgets.org>
Sent: Thursday, September 11, 2008 2:03 PM
Subject: Re: [wxpython-users] changing choices list on a combobox

Leon M Tolman MD wrote:

I am new to the list. I'm learning a lot of great stuff from you
guys--wish I had looked into this a long time ago!

I have been working on a problem where I want to change the choices
list on a combobox control after it has been created. I have two
simple questions plus a general one:

1) I am guessing that you are not able to change the choices list
once the combobox has been added to the frame by Layout(). I can't
find a Set() method like with wx.ListBox. I think this is probably
due to the potential that changing the list could change the basic
layout of the control itself. Correct me if I am wrong. This would
be the ideal solution but I am not hopeful.

Sure, it can be changed.

   cb.Clear()
   cb.Append( 'New Item 1' )
   cb.Append( 'New Item 2' )

2) Is there a way to change the sequence of tab traversal through the
widgets in a dialog? I explain below why I am asking if you want to
invest the time to look.

By replacing the list in place, you shouldn't need this. However, every
control has MoveAfterInTabOrder and MoveBeforeInTabOrder functions that
let you adjust this.

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

_______________________________________________
wxpython-users mailing list
wxpython-users@lists.wxwidgets.org
http://lists.wxwidgets.org/mailman/listinfo/wxpython-users

Hello,

FYI: ComboBox also has a SetItems method that takes a list of strings to set. No need to Clear or loop and append the items individually.

Cody

···

On Thu, Sep 11, 2008 at 1:16 PM, Leon M Tolman MD tolmanmd@alltel.net wrote:

Thanks for your help. Simple, I guess I overlooked these inherited methods. Leon

----- Original Message ----- From: “Tim Roberts” timr@probo.com

To: wxpython-users@lists.wxwidgets.org
Sent: Thursday, September 11, 2008 2:03 PM
Subject: Re: [wxpython-users] changing choices list on a combobox

Leon M Tolman MD wrote:

I am new to the list. I’m learning a lot of great stuff from you
guys–wish I had looked into this a long time ago!

I have been working on a problem where I want to change the choices
list on a combobox control after it has been created. I have two
simple questions plus a general one:

  1. I am guessing that you are not able to change the choices list

once the combobox has been added to the frame by Layout(). I can’t
find a Set() method like with wx.ListBox. I think this is probably
due to the potential that changing the list could change the basic
layout of the control itself. Correct me if I am wrong. This would

be the ideal solution but I am not hopeful.

Sure, it can be changed.

cb.Clear()
cb.Append( ‘New Item 1’ )
cb.Append( ‘New Item 2’ )

  1. Is there a way to change the sequence of tab traversal through the
    widgets in a dialog? I explain below why I am asking if you want to

invest the time to look.

By replacing the list in place, you shouldn’t need this. However, every
control has MoveAfterInTabOrder and MoveBeforeInTabOrder functions that
let you adjust this.


Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.


wxpython-users mailing list
wxpython-users@lists.wxwidgets.org

http://lists.wxwidgets.org/mailman/listinfo/wxpython-users


wxpython-users mailing list
wxpython-users@lists.wxwidgets.org
http://lists.wxwidgets.org/mailman/listinfo/wxpython-users

Cody,

Hello,
FYI: ComboBox also has a SetItems method that takes a list of strings to set. No need to Clear or loop and append the items individually.
Cody

I thought there was something like this, but back when I learned how to update the combobox, I was told the previous method. This cleans up some of my code quite nicely.

Thanks,

Mike

Mike Driscoll wrote:

Cody,

Hello,
FYI: ComboBox also has a SetItems method that takes a list of strings to set. No need to Clear or loop and append the items individually.
Cody

I thought there was something like this, but back when I learned how to update the combobox, I was told the previous method. This cleans up some of my code quite nicely.

Thanks,

Mike

But the SetItems method is only a wrapper for the clear and append loop. Here is the code from _core.py:

    def SetItems(self, items):
        """Clear and set the strings in the control from a list"""
        self.Clear()
        for i in items:
            self.Append(i)

So there will be no performance improvement by using this method, but it cleans up the code indeed.

Christian

Christian wrote:

But the SetItems method is only a wrapper for the clear and append loop. Here is the code from _core.py:

   def SetItems(self, items):
       """Clear and set the strings in the control from a list"""
       self.Clear()
       for i in items:
           self.Append(i) So there will be no performance improvement by using this method,

Hmm... That should probably be changed to use AppendItems instead of the loop...

but it cleans up the code indeed.

Note that the GetItems and SetItems are also made into a property, so you can even do this:

  combo.Items = myNewListOfItems

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Mike Driscoll-2 wrote:

When I want to change the contents of my combobox, I call its Clear()
method and then I append each new item I want. So something like this:

<code>
myCombo.Clear()
myList = [1,2,3,4,5]
for item in myList:
    myCombo.Append(item)
</code>

Of course, you'll need to make sure you list is in the order that you
want it...

Hi, I'm trying to do something similar but in my case I have 2 combo boxes.
The first one is a list of the drives C, D , E and so on and the next one
displays the different folders in the selected drives.

<code>

import wx
import os

class CBF(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1, 'Test', (50,50), (800,800))
        panel =wx.Panel(self, -1, )
        Drive = ['c','d']
  
        CBDrive = wx.ComboBox(panel,-1,"c",(15,30), wx.DefaultSize, Drive,
wx.CB_DROPDOWN)
        CBfolders = wx.ComboBox(panel,-1,"", (80,30), wx.DefaultSize, ,
wx.CB_DROPDOWN)
        
        self.Bind(wx.EVT_COMBOBOX, self.EvtComboBoxDrive, CBDrive)
    
    def EvtComboBoxDrive(self, event):
        Choosendrive = event.GetString()
        
        CBfolders.Clear()
        myList = os.listdir (Choosendrive + "://")
        for item in myList:
            CBproject.Append(item)
          
if __name__ == "__main__":
    app = wx.PySimpleApp()
    CBF().Show()
    app.MainLoop()

</code>

But when I choose the drive i get the error
"CBfolders.Clear()NameError: global name 'CBfolders' is not defined"
I think that this happened because 'CBfolders' is defined in def
__init__(self) but not in EvtComboBoxDrive. Is there anyway to work around
this?

Thanks in advance for any reply.

···

--
View this message in context: http://www.nabble.com/changing-choices-list-on-a-combobox-tp19440396p19489277.html
Sent from the wxPython-users mailing list archive at Nabble.com.

monotoner wrote:

I think that this happened because 'CBfolders' is defined in def
__init__(self) but not in EvtComboBoxDrive. Is there anyway to work around
this?
  

Hi,
you are right, CBfolders is a local variable of the constructor. If you want to reuse it later, you have to bind it to your object. Here is a little example:

class Person(object):
    def __init__(self, name):
        self.name = name
    def say_hello(self):
        print 'My name is %s.' % self.name

andy = Person('Andy')
andy.say_hello() # --> My name is Andy.

There are several types of variable visibilities, global / local / object bound / class bound. Here is some additional info:
http://www.galileocomputing.de/openbook/python/python_kapitel_12_001.htm#mja573271b00198256bf4fb374b9401db8

Christian

Hi,

Mike Driscoll-2 wrote:
  

When I want to change the contents of my combobox, I call its Clear() method and then I append each new item I want. So something like this:

<code>
myCombo.Clear()
myList = [1,2,3,4,5]
for item in myList:
    myCombo.Append(item)
</code>

Of course, you'll need to make sure you list is in the order that you want it...

Hi, I'm trying to do something similar but in my case I have 2 combo boxes.
The first one is a list of the drives C, D , E and so on and the next one
displays the different folders in the selected drives.

<code>

import wx
import os

class CBF(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1, 'Test', (50,50), (800,800))
        panel =wx.Panel(self, -1, )
        Drive = ['c','d']
          CBDrive = wx.ComboBox(panel,-1,"c",(15,30), wx.DefaultSize, Drive,
wx.CB_DROPDOWN)
        CBfolders = wx.ComboBox(panel,-1,"", (80,30), wx.DefaultSize, ,
wx.CB_DROPDOWN)
                self.Bind(wx.EVT_COMBOBOX, self.EvtComboBoxDrive, CBDrive)
        def EvtComboBoxDrive(self, event):
        Choosendrive = event.GetString()
                CBfolders.Clear()
        myList = os.listdir (Choosendrive + "://") for item in myList:
            CBproject.Append(item)
          
if __name__ == "__main__":
    app = wx.PySimpleApp()
    CBF().Show()
    app.MainLoop()

</code>

But when I choose the drive i get the error "CBfolders.Clear()NameError: global name 'CBfolders' is not defined"
I think that this happened because 'CBfolders' is defined in def
__init__(self) but not in EvtComboBoxDrive. Is there anyway to work around
this?

Thanks in advance for any reply.
  
The recommended way would be to add "self" to the beginning of your combobox instances. Then they become accessible throughout your application object. I think the technical term for doing that is "property".

So, instead of "CBfolders" make it "self.CBfolders" throughout and do the same to the other one if you need to access it from another function within your program. I would recommend reading up on classes. This is a good resource: OOP in Python: How to Create a Class, Inherit Properties and Methods

···

-------------------
Mike Driscoll

Blog: http://blog.pythonlibrary.org
Python Extension Building Network: http://www.pythonlibrary.org