Question

I'm trying to autocompute the totals column after an event without making a button to compute. My loop for the defined function total is wrong and I've been stuck for a few hours figuring out what listctrl event to use thinking that the it should autocompute at edit of the label and at the data entry by adding lines. Please help! I'm still a noob. Thanks! :)

import wx
import wx.lib.mixins.listctrl  as  listmix

########################################################################
class EditableListCtrl(wx.ListCtrl, listmix.TextEditMixin):
    ''' TextEditMixin allows any column to be edited. '''

    #----------------------------------------------------------------------
    def __init__(self, parent, ID=wx.ID_ANY, pos=wx.DefaultPosition,
                 size=wx.DefaultSize, style=0):
        """Constructor"""
        wx.ListCtrl.__init__(self, parent, ID, pos, size, style)
        listmix.TextEditMixin.__init__(self)
        self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnBeginLabelEdit)

    def OnBeginLabelEdit(self, event):
        if event.m_col == 0:
            event.Veto()
        elif event.m_col == 4:
            event.Veto()
        else:
            event.Skip()

########################################################################
class MyPanel(wx.Panel):
    """"""

    #----------------------------------------------------------------------
    def __init__(self, parent):
        """Constructor"""
        wx.Panel.__init__(self, parent)
        self.text_ctrl = wx.TextCtrl(self)

        rows = [("Ford", "123", "1996", ""),
                ("Nissan", "432", "2010", ""),
                ("Porche", "911", "2009", "")
                ]
        self.list_ctrl = EditableListCtrl(self, style=wx.LC_REPORT)

        self.list_ctrl.InsertColumn(0, "Somethin")
        self.list_ctrl.InsertColumn(1, "Price")
        self.list_ctrl.InsertColumn(2, "Qty")
        self.list_ctrl.InsertColumn(3, "Total")
        self.listitems = set()
        self.index = 0
        index = 0
        for row in rows:
            self.list_ctrl.InsertStringItem(index, row[0])
            self.list_ctrl.SetStringItem(index, 1, row[1])
            self.list_ctrl.SetStringItem(index, 2, row[2])
            self.list_ctrl.SetStringItem(index, 3, row[3])
            index += 1
        btn = wx.Button(self, label="Add Line")
        btn.Bind(wx.EVT_BUTTON, self.add_line)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.text_ctrl,0,wx.ALL|wx.EXPAND,5)
        sizer.Add(self.list_ctrl, 0, wx.ALL|wx.EXPAND, 5)
        sizer.Add(btn, 0, wx.ALL|wx.CENTER, 5)
        self.SetSizer(sizer)
        self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.total)
    def add_line(self, event):
        textval = self.text_ctrl.GetValue()
        if textval not in self.listitems:
            line = "%s" % self.index
            self.list_ctrl.InsertStringItem(self.index, line)
            self.list_ctrl.SetStringItem(self.index, 1, self.text_ctrl.GetValue())
            self.index += 1
            self.listitems.add(textval)
        print "duplicate detected"

    def total(self,event):
        count = self.list_ctrl.GetItemCount()
        for row in range(count):
            itemprice = self.list_ctrl.GetItem(itemId=row, col=1)
            itemqty = self.list_ctrl.GetItem(itemId=row, col=2)
            itempriceval = itemprice.GetText()
            itemqtyval = itemqty.GetText()
            total = float(itempriceval)*float(itemqtyval)
            self.list_ctrl.SetStringItem(count-1, 5, "%.2f" % total)


########################################################################
class MyFrame(wx.Frame):
    """"""

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, None, wx.ID_ANY, "Editable List Control")
        panel = MyPanel(self)
        self.Show()

#----------------------------------------------------------------------
if __name__ == "__main__":
    app = wx.App(False)
    frame = MyFrame()
    app.MainLoop()
Was it helpful?

Solution

Alright, try this for your MyPanel class

class MyPanel(wx.Panel):
    """"""

    #----------------------------------------------------------------------
    def __init__(self, parent):
        """Constructor"""
        wx.Panel.__init__(self, parent)
        self.text_ctrl = wx.TextCtrl(self)

        rows = [("Ford", "123", "1996", ""),
                ("Nissan", "432", "2010", ""),
                ("Porche", "911", "2009", "")
                ]
        self.list_ctrl = EditableListCtrl(self, style=wx.LC_REPORT, size=(-1, 150))

        self.list_ctrl.InsertColumn(0, "Something")
        self.list_ctrl.InsertColumn(1, "Price")
        self.list_ctrl.InsertColumn(2, "Qty")
        self.list_ctrl.InsertColumn(3, "Total")
        self.listitems = set()
        self.index = 0
        index = 0
        for row in rows:
            self.list_ctrl.InsertStringItem(index, row[0])
            self.list_ctrl.SetStringItem(index, 1, row[1])
            self.list_ctrl.SetStringItem(index, 2, row[2])
            self.list_ctrl.SetStringItem(index, 3, row[3])
            index += 1
        btn = wx.Button(self, label="Add Line")
        btn.Bind(wx.EVT_BUTTON, self.add_line)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.text_ctrl,0,wx.ALL|wx.EXPAND,5)
        sizer.Add(self.list_ctrl, 0, wx.ALL|wx.EXPAND, 5)
        sizer.Add(btn, 0, wx.ALL|wx.CENTER, 5)
        self.SetSizer(sizer)
        self.Bind(wx.EVT_LIST_END_LABEL_EDIT, self.total)

    def add_line(self, event):
        textval = self.text_ctrl.GetValue()
        if textval not in self.listitems:
            line = str(self.index)
            self.list_ctrl.InsertStringItem(self.index, line)
            self.list_ctrl.SetStringItem(self.index, 0, self.text_ctrl.GetValue())
            self.index += 1
            self.listitems.add(textval)
        else:
            print "duplicate detected"

    def total(self,event):
        if not event.IsEditCancelled():
            count = self.list_ctrl.GetItemCount()
            totals = []
            try:
                for row in range(count):
                    itemprice = self.list_ctrl.GetItem(itemId=row, col=1)
                    itemqty = self.list_ctrl.GetItem(itemId=row, col=2)
                    itempriceval = itemprice.GetText()
                    itemqtyval = itemqty.GetText()
                    total = float(itempriceval)*float(itemqtyval)
                    totals.append(total)

                print totals

                for row, total in zip(range(count),totals):
                    self.list_ctrl.SetStringItem(row, 3, "%.2f" % total)
            except:
                return
        else:
            print "edit was cancelled"

Most of what I did was in total(), most notably, the try...except block. This keeps you from getting an error when not all the totals can be computed. I changed some things in other places too such as the bound event (now based off the end of an edit), and a bunch of indices were wrong as well (you were trying to write the total to index 5, should be 3)

Hope this helps,

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top