简体   繁体   中英

Proper way to access items in FlexGridSizer in wxPython?

I have a FlexGridSizer called self.grid with five columns, each row having two TextCtrl's a pair of RadioButton's and a CheckBox. What is the best way to retrieve the data associated with these objects? Currently I am successfully using

# get flat list of all items in flexgridsizer, self.grid
children = list(self.grid.GetChildren())

# change list into list of rows (5 items each)
table = [children[i:i+5] for i in range(0, len(children), 5)]

# parse list of 'sizeritems' to extract content
for x in range(len(table)):
    for y in range(len(table[x])):
        widget = table[x][y].GetWindow()
        if isinstance(widget, wx.TextCtrl):
            text = ""
            for num in range(widget.GetNumberOfLines()):
                text += widget.GetLineText(num)
            table[x][y] = text
        if isinstance(widget, wx.RadioButton):
            table[x][y] = widget.GetValue()
        if isinstance(widget, wx.CheckBox):
            table[x][y] = (widget.GetLabel(), widget.GetValue())

This leaves me with table , a list of rows with five elements each, each item being relevant data: text for TextCtrl, bool for RadioButton, and (label, bool) for CheckBox. This seems to get the job done, but it doesn't feel right.

Is there a better way to recover data from a FlexGridSizer? Alternatively, should I be using a different sizer/control for this layout? (I tried UltimateListCtrl, but it was buggy/didn't actually do what I needed).

you shouldnt really be doing that .. instead you should create references to them when created

self.widgetTable = []
for row in dataSet:
   self.widgetTable.append([wx.TextCtrl(self,-1,value) for value in row])

then access them through that

self.widgetTable[0][0].GetValue()

Since you have working code, and seem to be asking about coding style, you may have some luck asking on Code Review.

That being said, what you have here isn't too terrible. I think isinstance() is pretty ugly, so when I did something like this, I went by order of the widgets since I knew every 5th widget was what I wanted. Maybe you could use a similar approach? Or use a try...except structure to avoid isinstance .

So there are two approaches here, the first based on the order of your widgets, and the second just guesses how you retrieve info.

Method 1: So if your widgets have regular order, you can do something like this: (horrendous variable names for demonstration only)

list_of_one_type_of_widget = map(lambda x: x.GetWindow(), self.grid.GetChildren())[::k]
list_of_values_for_first_type = map(lambda x: x.GetValue(), list_of_one_type_of_widget)

list_of_another_type_of_widget = map(lambda x: x.GetWindow(), self.grid.GetChildren())[1::k]
list_of_values_for_first_type = map(lambda x: (x.GetLabel(), x.GetValue()), list_of_another_type_of_widget)

Where k is the number of widget types you have. This is how I tackled the problem when I came up against it, and I think its pretty nifty and very concise. You're left with a list for each type of widget you have, so that makes processing easy if it depends on the widget. You could also pretty easily build this back into a table. Be sure to note how the second one is sliced with [1::k] rather than [::k] . Each subsequent widget type will need to be one greater than the previous.

Method 2: If you don't have a regular order, you can do something like this:

list_of_values = []
for widget in map(lambda x: x.GetWindow(), self.grid.GetChildren()):
    try:
        list_of_values.append(widget.GetValue())
    except:
        #Same as above, but with the appropriate Get function.  If there multiple alternatives, just keep nesting try...except blocks in decrease order of commonness

You could make the case that the second method is more "pythonic", but that's up for debate. Additionally, without some clever tricks, you're left with one list in the end, which may not be ideal for you.

Some notes on your solution:

  • self.grid.GetChildren() is iterable, so you don't need to convert it to a list before using it as an iterable
  • You could change your sequential if statements to a if...elif...(else) construct, but its really not that big of a deal in this case since you don't expect any widget to more than one test

Hope this helps

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM