Search code examples
pythonwxpythonobjectlistview-python

How to change value of existing item's string in wxPython ObjectListView list_ctrl


I know I can use list_ctrl.GetStringValueAt() like so to get the value for a particular object in the ObjectListView:

class myOLV(ObjectListView):
    ... code to handle specific events

class myPanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)

        self.list_ctrl = myOLV(self, wx.ID_ANY, style=wx.LC_REPORT)
        self.setColumns()

        # . . .

        self.submit_button = wx.Button(self, label="Submit")
        # ... add to sizer here, skipping tedious stuff in this example
        self.submit_button.Bind(wx.EVT_BUTTON, self.onSubmit)

    def setColumns(self):
        self.list_ctrl.SetColumns([
            ColumnDefn("Column 1", "left", 128, "col1"),
            ColumnDefn("Column 2", "left", 128, "col2"),
            ColumnDefn("Column 3", "left", 128, "col3")
        )]

    def onSubmit(self, event):
        objects = self.list_ctrl.GetObjects()
        for obj in objects:
            col1 = self.list_ctrl.GetStringValueAt(obj, 1)
            # how could I change the above value here?
            col2 = self.list_ctrl.GetStringValueAt(obj, 2)
            col3 = self.list_ctrl.GetStringValueAt(obj, 3)

But what if I want to change the value of a string given the obj in this current loop and column index? The documentation doesn't seem to have a method that takes the current object and a column index as a parameter, so how could I do this (without removing and repopulating the element)?

I see from the docs that there is a SetValue(modelObjects, preserveSelection=False) method but it sets the list of modelObjects to be displayed by the control, which is not what I'm trying to do.

Is there a SetStringValueAt(modelObject, columnIndex) method or workaround to do the same thing in this context?


Solution

  • You can turn on cell "editability" by setting your ObjectListView instance's cellEditMode. Something like this would work:

    self.list_ctrl.cellEditMode = ObjectListView.CELLEDIT_SINGLECLICK
    

    The ObjectListView documentation talks about this here:

    I also mention it in the following tutorial:

    UPDATE: Iterating over objects and changing them programmatically is a bit trickier. Fortunately, ObjectListView provides RefreshObject, which allows us to change a specific object and then refresh it. Here's an example script:

    # OLVcheckboxes.py
    
    import wx
    from ObjectListView import ObjectListView, ColumnDefn
    
    ########################################################################
    class Results(object):
        """"""
    
        #----------------------------------------------------------------------
        def __init__(self, tin, zip_code, plus4, name, address):
            """Constructor"""
            self.tin = tin
            self.zip_code = zip_code
            self.plus4 = plus4
            self.name = name
            self.address = address
    
    
    ########################################################################
    class ProvPanel(wx.Panel):
        """"""
    
        #----------------------------------------------------------------------
        def __init__(self, parent):
            """Constructor"""
            wx.Panel.__init__(self, parent=parent)
    
            mainSizer = wx.BoxSizer(wx.VERTICAL)
    
            self.columns = {0: 'tin',
                            1: 'zip_code',
                            2: 'plus4',
                            3: 'name',
                            4: 'address'}
    
            self.test_data = [Results("123456789", "50158", "0065", "Patti Jones",
                                      "111 Centennial Drive"),
                              Results("978561236", "90056", "7890", "Brian Wilson",
                                      "555 Torque Maui"),
                              Results("456897852", "70014", "6545", "Mike Love",
                                      "304 Cali Bvld")
                              ]
            self.resultsOlv = ObjectListView(self, style=wx.LC_REPORT|wx.SUNKEN_BORDER)
            self.resultsOlv.cellEditMode = ObjectListView.CELLEDIT_SINGLECLICK
    
            self.setResults()
    
            self.column_cbo = wx.ComboBox(self, value='tin',
                                          choices=self.columns.values())
            modify_btn = wx.Button(self, label='Modify Column 1 Cells')
            modify_btn.Bind(wx.EVT_BUTTON, self.onModify)
    
            mainSizer.Add(self.resultsOlv, 1, wx.EXPAND|wx.ALL, 5)
            mainSizer.Add(self.column_cbo, 0, wx.CENTER|wx.ALL, 5)
            mainSizer.Add(modify_btn, 0, wx.CENTER|wx.ALL, 5)
            self.SetSizer(mainSizer)
    
        #----------------------------------------------------------------------
        def onModify(self, event):
            """
            Modify cells
            """
            objects = self.resultsOlv.GetObjects()
            column = self.column_cbo.GetValue()
            for obj in objects:
                value = 'Row #%s' % self.resultsOlv.GetIndexOf(obj)
                setattr(obj, column, value)
                self.resultsOlv.RefreshObject(obj)
    
        #----------------------------------------------------------------------
        def setResults(self):
            """"""
            self.resultsOlv.SetColumns([
                ColumnDefn("TIN", "left", 100, "tin"),
                ColumnDefn("Zip", "left", 75, "zip_code"),
                ColumnDefn("+4", "left", 50, "plus4"),
                ColumnDefn("Name", "left", 150, "name"),
                ColumnDefn("Address", "left", 200, "address")
            ])
            self.resultsOlv.CreateCheckStateColumn()
            self.resultsOlv.SetObjects(self.test_data)
    
    
    ########################################################################
    class ProvFrame(wx.Frame):
        """"""
    
        #----------------------------------------------------------------------
        def __init__(self):
            """Constructor"""
            title = "OLV Checkbox Tutorial"
            wx.Frame.__init__(self, parent=None, title=title, size=(1024, 768))
            panel = ProvPanel(self)
    
    
    #----------------------------------------------------------------------
    if __name__ == "__main__":
        app = wx.App(False)
        frame = ProvFrame()
        frame.Show()
        app.MainLoop()