wx.GridSimple: Controlling Size and Data Entry

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

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

···

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.

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 (2.31 KB)

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

···

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,

   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

···

On Fri, 22 May 2015, Torsten wrote:

Hello Rich,

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 (2.7 KB)

···

Am Donnerstag, 28. Mai 2015 16:32:33 UTC+2 schrieb fuzzydoc:

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

···

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.GetNumberRows()):
        self.SetCellValue(row, col, value)

``

Regards, Torsten

Torsten,

   That works.

Much appreciated,

Rich

···

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)