wx.GridSimple: Controlling Size and Data Entry

64 views
Skip to first unread message

Rich Shepard

unread,
May 22, 2015, 1:49:34 PM5/22/15
to wxpytho...@googlegroups.com
Seeking advice on sizing a wx.Grid and individiual column widths and
restricting cell contents of specific columns to a choice of terms. Should I
be using a GridSizer, GridBagSizer, or GridFlexBagSizer?

The current view is attached as a .png file (if the maillist allows
attachments). The code follows (with blank lines removed to save space):

class pwAir(wx.Panel):
def __init__(self, *args, **kwds):
wx.Panel.__init__(self, *args, **kwds)

topBox = wx.BoxSizer(wx.VERTICAL)
commentBox = wx.BoxSizer(wx.HORIZONTAL)

# Define grid widget
airGrid = gridlib.Grid(self)
self.nRows = 25
self.nCols = 9
self.flag = 0
self.colLabels = ['Emitter', 'Date', 'Time', 'Collector', 'PM', 'PM10', \
'PM2.5', 'Opacity', 'Comment']
airGrid.CreateGrid(self.nRows, self.nCols)
# simple cell formatting
airGrid.SetColSize(0,800)
airGrid.SetColSize(1,500)
airGrid.SetColSize(2,500)
airGrid.SetColSize(3,800)
airGrid.SetColSize(4,100)
airGrid.SetColSize(5,100)
airGrid.SetColSize(6,100)
airGrid.SetColSize(7,80)
airGrid.SetColSize(8,2000)
airGrid.SetColLabelValue(0, "Emission Unit")
airGrid.SetColLabelValue(1, "Date")
airGrid.SetColLabelValue(2, "Time")
airGrid.SetColLabelValue(3, "Collector")
airGrid.SetColLabelValue(4, "PM")
airGrid.SetColLabelValue(5, "PM10")
airGrid.SetColLabelValue(6, "PM2.5")
airGrid.SetColLabelValue(7, "Opacity")
airGrid.SetColLabelValue(8, "Data Explanation")
airGrid.SetColLabelAlignment(wx.ALIGN_CENTER, wx.ALIGN_BOTTOM)
airGrid.AutoSizeColumns(setAsMin = True)
airGrid.attr = wx.grid.GridCellAttr()
airGrid.attr.SetTextColour(wx.BLACK)
airGrid.attr.SetBackgroundColour(wx.RED)
airGrid.attr.SetFont(wx.Font(10, wx.ROMAN, wx.NORMAL, wx.BOLD))
airGrid.SetColLabelAlignment(wx.ALIGN_CENTER, wx.ALIGN_BOTTOM)
airGrid.SetLabelBackgroundColour('DARKOLIVEGREEN')
airGrid.SetLabelFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD))
airGrid.SetLabelTextColour('WHEAT')
airGrid.SetDefaultCellOverflow(False)
r = gridlib.GridCellAutoWrapStringRenderer()
airGrid.SetCellRenderer(9, 1, r)
editor = gridlib.GridCellTextEditor()
editor.SetParameters('10')
airGrid.SetCellEditor(0, 4, editor)
airGrid.moveTo = None
airGrid.Bind(wx.EVT_IDLE, self.OnIdle)
# Comments
lab = wx.StaticText(self, -1, "Comments: ")
self.comment = wx.TextCtrl(self, -1, size = (500, 50),
style = wx.TAB_TRAVERSAL|wx.TE_PROCESS_ENTER|wx.RAISED_BORDER|
wx.TE_MULTILINE|wx.TE_BESTWRAP)
commentBox.Add(lab, 0, wx.ALL, 5)
commentBox.Add(self.comment, 0, wx.ALL, 5)
# Define buttons
self.AddButton = wx.Button(self, wx.ID_ADD)
self.EditButton = wx.Button(self, wx.ID_EDIT)
self.CancelButton = wx.Button(self, wx.ID_CANCEL)
btn1Sizer = wx.StdDialogButtonSizer()
btn1Sizer.Add(self.AddButton, 0, wx.ALL, 0)
btn1Sizer.Add(self.EditButton, 0, wx.ALL, 0)
btn1Sizer.Add(self.CancelButton)


self.Bind(wx.EVT_BUTTON, self.OnAdd, self.AddButton)
self.Bind(wx.EVT_BUTTON, self.OnEdit, self.EditButton)
self.Bind(wx.EVT_BUTTON, self.OnCancel, self.CancelButton)
btn1Sizer.Realize()

topBox.Add(airGrid, 0, wx.ALIGN_CENTER|wx.ALL, 5)
topBox.Add(commentBox, 0, wx.ALIGN_CENTER|wx.ALL, 5)
topBox.Add(btn1Sizer, 0, wx.ALIGN_CENTER|wx.ALL, 5)

self.SetSizer(topBox)
topBox.Fit(self)

I've looked at the wx.Widgets on-line docs page without learning just how
to tune this code.

Besides sizing, I'd like the number of rows to increase as needed and
limit data entry (in the last column in this grid) to a list of possible
values.

Suggestions, recommendations, and other advice needed.

Thanks in advance,

Rich
grid-widget.png

Rich Shepard

unread,
May 22, 2015, 4:58:49 PM5/22/15
to wxpytho...@googlegroups.com
On Fri, 22 May 2015, Rich Shepard wrote:

> Seeking advice on sizing a wx.Grid and individiual column widths and
> restricting cell contents of specific columns to a choice of terms.

Sizing has been resolved. However, limiting cell content in a specific
column to a list of strings is still open. Pointers to docs will help.

Rich

Torsten

unread,
May 23, 2015, 2:35:14 AM5/23/15
to wxpytho...@googlegroups.com
Hello Rich,

you could use an own CellEditor with a ChoiceCtrl and set it as default editor for the column. I've attached a simple test app.

class GridCellChoiceEditor(wx.grid.PyGridCellEditor):
    def __init__(self):
        wx.grid.PyGridCellEditor.__init__(self)
        
    def Create(self, parent, id, evtHandler):
        choicesList = ['edit me', 'to select', 'between choices']
        self._choiceCtrl = wx.Choice(parent, id, choices=choicesList)
        self.SetControl(self._choiceCtrl)
        if evtHandler:
            self._choiceCtrl.PushEventHandler(evtHandler)

    def SetSize(self, rect):
        self._choiceCtrl.SetDimensions(rect.x, rect.y,
            rect.width+2, rect.height+2, wx.SIZE_AUTO)
    
    def BeginEdit(self, row, col, grid):
        self._startValue = grid.GetTable().GetValue(row, col)
        self._choiceCtrl.SetStringSelection(self._startValue)
        self._choiceCtrl.SetFocus()
        
    def EndEdit(self, row, col, grid, oldVal):
        val = self._choiceCtrl.GetStringSelection()
        if val != self._startValue:
            return val
        else:
            return None
    
    def ApplyEdit(self, row, col, grid):
        val = self._choiceCtrl.GetStringSelection()
        grid.GetTable().SetValue(row, col, val)
        
    def Reset(self):
        self._choiceCtrl.SetStringSelection(self._startValue)
        
    def Clone(self):
        return GridCellChoiceEditor()

class TestFrame(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, id=wx.ID_ANY)
        
        self.testGrid = wx.grid.Grid(self)
        self.testGrid.CreateGrid(5, 5)
        self.testGrid.SetSelectionMode(0)

        self.testGrid.SetCellValue(0, 0, 'edit me')
        self.testGrid.SetCellValue(1, 0, 'to select')
        self.testGrid.SetCellValue(2, 0, 'between choices')

        cellAttr = wx.grid.GridCellAttr()
        cellAttr.SetEditor(GridCellChoiceEditor())
        self.testGrid.SetColAttr(0, cellAttr)
        
        szr = wx.BoxSizer(wx.VERTICAL)
        szr.Add(self.testGrid, 1, wx.EXPAND)
        
        self.SetSize((300, 200))
        self.SetSizer(szr)
        self.Layout()        
        self.Centre(wx.BOTH)


grid_choice_editor.py

Rich Shepard

unread,
May 23, 2015, 8:44:25 AM5/23/15
to wxpytho...@googlegroups.com
On Fri, 22 May 2015, Torsten wrote:

> you could use an own CellEditor with a ChoiceCtrl and set it as default
> editor for the column. I've attached a simple test app.

Torsten,

This looks like the perfect solution. With my current knowledge of
wxPython I could not have come up with this.

Thank you very much,

Rich

Rich Shepard

unread,
May 28, 2015, 10:32:33 AM5/28/15
to wxpytho...@googlegroups.com
On Fri, 22 May 2015, Torsten wrote:

Torsten,

Replying to the list so the thread is archived forever.

> def Create(self, parent, id, evtHandler):
> choicesList = ['edit me', 'to select', 'between choices']
> self._choiceCtrl = wx.Choice(parent, id, choices=choicesList)
> self.SetControl(self._choiceCtrl)
> if evtHandler:
> self._choiceCtrl.PushEventHandler(evtHandler)

I'll need to provide a different choicesList[] for each grid column. Would
best practices mean inserting this class's code in the code for each panel?
Or, can I import the class while calling Create() for each column needing
data entry limited to the specified choices?

> class TestFrame(wx.Frame):
...

> self.testGrid.SetCellValue(0, 0, 'edit me')
> self.testGrid.SetCellValue(1, 0, 'to select')
> self.testGrid.SetCellValue(2, 0, 'between choices')

How do I provide the same set of choices (by referencing the choiceList[]
rather than a defined string) for all rows and a specified column? Can I
write
self.testGrid.SetCellValue(, 1, choiceList)?

Thanks,

Rich

Torsten

unread,
May 28, 2015, 11:21:49 AM5/28/15
to wxpytho...@googlegroups.com
Hello Rich,


Am Donnerstag, 28. Mai 2015 16:32:33 UTC+2 schrieb fuzzydoc:
I'll need to provide a different choicesList[] for each grid column.
To have different choices for different columns you could add a parameter to the editor class to
provide a list of choices. Then for each column create a new GridCellAttr and set the editor with
the needed choice list. See attached code.
 

   How do I provide the same set of choices (by referencing the choiceList[]
rather than a defined string) for all rows and a specified column? Can I

Sorry, i don't  understand what do you want here. Can you explain in other words?



Torsten 
grid_choice_editor.py

Rich Shepard

unread,
May 28, 2015, 11:33:30 AM5/28/15
to wxpytho...@googlegroups.com
On Thu, 28 May 2015, Torsten wrote:

> To have different choices for different columns you could add a parameter
> to the editor class to provide a list of choices. Then for each column
> create a new GridCellAttr and set the editor with the needed choice list.
> See attached code.

Hi, Torsten,

That's what I thought.

>> How do I provide the same set of choices (by referencing the
>> choiceList[] rather than a defined string) for all rows and a specified
>> column? Can I
>
> Sorry, i don't understand what do you want here. Can you explain in other
> words?

When I look at the docs for wx.grid and at your example code I see the
method to SetColLableValue() to title the columns. I have not found the
wxWidgets docs for wx.Grid to learn if there is a SetColValue() method.

Your example code puts the choice box in each individual cell. Rather than
calling .SetCellValue(row, column, "choice") I need to call
.SetColValue(col, "choice").

Is this more clear?

Thanks again,

Rich


Message has been deleted

Torsten

unread,
May 28, 2015, 12:13:27 PM5/28/15
to wxpytho...@googlegroups.com
If i understand you right, you want with one call set the value for all rows in a column. I don't
know of such a method. So my solution would be to define an own method:

class MyGrid(wx.grid.Grid):
   
def __init__(self, *args, **kwargs):
       
super(MyGrid, self).__init__(*args, **kwargs)
       
   
def SetColValue(self, col, value):
       
for row in range(self.GetNumberRows()):
           
self.SetCellValue(row, col, value)


Regards, Torsten

Rich Shepard

unread,
May 28, 2015, 12:32:27 PM5/28/15
to wxpytho...@googlegroups.com
On Thu, 28 May 2015, Torsten wrote:

> If i understand you right, you want with one call set the value for all
> rows in a column. I don't
> know of such a method. So my solution would be to define an own method:
>
> class MyGrid(wx.grid.Grid):
> def __init__(self, *args, **kwargs):
> super(MyGrid, self).__init__(*args, **kwargs)
>
> def SetColValue(self, col, value):
> for row in range(self.GetNumberCols()):
> self.SetCellValue(row, col, value)

Torsten,

That works.

Much appreciated,

Rich
Reply all
Reply to author
Forward
0 new messages