wxPython UltimateListCtrl Error After Deleting Row

删除回忆录丶 提交于 2021-01-29 07:14:17

问题


I have been working with wxPython and UltimateListCtrl to create a GUI for a project. For my GUI is have a few panels that have UltimateListCtrls and have I run into an issue I cant seem to fix. My GUI consists of a list of files with 5 columns: a CheckBox Column, a File Name Column, a File Extension Column, a File Size Column, and a ComboBox Column. Example GUI Below the list I have a button that, when clicked, will delete any row whose CheckBox is checked. My issue comes after I delete, for example, row 1 and click on either the CheckBox or the ComboBox for the last row. When I do I receive this error:

Traceback (most recent call last): File "C:\Users\Media_i5\PycharmProjects\PicThings\venv\lib\site-packages\wx\lib\agw\ultimatelistctrl.py", line 2260, in OnSetFocus select = listCtrl.GetItemState(self._itemId, ULC_STATE_SELECTED) File "C:\Users\Media_i5\PycharmProjects\PicThings\venv\lib\site-packages\wx\lib\agw\ultimatelistctrl.py", line 8944, in GetItemState raise Exception("invalid item index in GetItemState") Exception: invalid item index in GetItemState

When I trace back the calls I find that when I delete a row, the ID/Index for each following row is updated to match its new position on the list, but the ID/Index for the CheckBox, ComboBox is not. In the example code below, when the row at index 1 (row 2) is deleted, the row at index 2 becomes index 1, index 3 becomes index 2, etc... However the Checkbox/ComboBox on the row that moved to index 1 still has an ID/Index of 2. In this scenario, after row 1 is deleted, if you click on the CheckBox/ComboBox on the last row, the error above is flagged because the index for the Box is larger than the number of rows.

I hope this makes sense. Attached below is a small example code the illustrates the issue. Run the code, click the CheckBox for Picture 1, Click the Clear Button, then Click the CheckBox for Picture 7.

Can anyone help me figure out why the ID/Index for the Boxes are not updating automatically like the row?

import wx
from wx.lib.agw import ultimatelistctrl as ULC

class Mywin(wx.Frame):
    t_col1 = ['PICTURE 1', 'PICTURE 2', 'PICTURE 3', 'PICTURE 4', 'PICTURE 5', 'PICTURE 6', 'PICTURE 7']
    t_col4 = ['1', '1', '3', '5', '5', '1', '2']

    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent)
        box2 = wx.BoxSizer(wx.VERTICAL)
        title = wx.StaticText(self, wx.ID_ANY, label='Pictures On Frame:')
        box2.Add(title, 0, wx.ALL, 5)
        self.list = ULC.UltimateListCtrl(self, agwStyle = ULC.ULC_REPORT | ULC.ULC_HAS_VARIABLE_ROW_HEIGHT)
        colhead = ["", "File", "Ext", "Size", "Rating"]
        colwidth = [30, 300, 45, 45, 45]
        for x in range(0, len(colhead)):
            self.list.InsertColumn(x, colhead[x], width=colwidth[x])
        box2.Add(self.list, 1, wx.EXPAND)
        btnSizer2 = wx.BoxSizer(wx.HORIZONTAL)
        btnC = wx.Button(self, label="Clear")
        btnC.Bind(wx.EVT_BUTTON, self.on_clear)
        btnSizer2.Add(btnC, 0, wx.ALL | wx.CENTER, 5)
        box2.Add(btnSizer2, 1, wx.EXPAND)
        self.SetSizer(box2)
        self.SetTitle('Picture Frame Selector')
        self.Centre()
        self.Maximize()
        self.Show()
        rb_list = ["1", "2", "3", "4", "5"]
        for x in range(0 , len(self.t_col1)):
            self.list.InsertStringItem(x, '')
            cBox = wx.CheckBox(self.list)
            self.list.SetItemWindow(x, 0, cBox)
            self.list.SetStringItem(x, 1, self.t_col1[x])
            self.list.SetStringItem(x, 2, '.jpg')
            dBox = wx.ComboBox(self.list, value=self.t_col4[x], choices=rb_list, style=wx.CB_READONLY)
            self.list.SetItemWindow(x, 4, dBox, expand=True)

    def on_clear(self, event):
        t = 0
        for x in range(0, len(self.t_col1)):
            if self.list.GetItemWindow(t, 0).IsChecked():
                self.list.DeleteItem(t)
            else:
                t += 1
        event.Skip()

if __name__ == "__main__":
    ex = wx.App()
    Mywin(None, 'Row Delete Issue')
    ex.MainLoop()

回答1:


You can get around this issue by rebuilding the listctrl using the list t_col1.

import wx
from wx.lib.agw import ultimatelistctrl as ULC

class Mywin(wx.Frame):
    t_col1 = ['PICTURE 1', 'PICTURE 2', 'PICTURE 3', 'PICTURE 4', 'PICTURE 5', 'PICTURE 6', 'PICTURE 7']
    t_col4 = ['1', '1', '3', '5', '5', '1', '2']

    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent)
        box2 = wx.BoxSizer(wx.VERTICAL)
        title = wx.StaticText(self, wx.ID_ANY, label='Pictures On Frame:')
        box2.Add(title, 0, wx.ALL, 5)
        self.list = ULC.UltimateListCtrl(self, agwStyle = ULC.ULC_REPORT | ULC.ULC_HAS_VARIABLE_ROW_HEIGHT)
        colhead = ["", "File", "Ext", "Size", "Rating"]
        colwidth = [30, 300, 45, 45, 45]
        for x in range(0, len(colhead)):
            self.list.InsertColumn(x, colhead[x], width=colwidth[x])
        box2.Add(self.list, 1, wx.EXPAND)
        btnSizer2 = wx.BoxSizer(wx.HORIZONTAL)
        btnC = wx.Button(self, label="Clear")
        btnC.Bind(wx.EVT_BUTTON, self.on_clear)
        btnSizer2.Add(btnC, 0, wx.ALL | wx.CENTER, 5)
        box2.Add(btnSizer2, 1, wx.EXPAND)
        self.SetSizer(box2)
        self.SetTitle('Picture Frame Selector')
        self.Centre()
        self.Maximize()
        self.CreateList()
        self.Show()

    def CreateList(self):
        rb_list = ["1", "2", "3", "4", "5"]
        for x in range(0 , len(self.t_col1)):
            self.list.InsertStringItem(x, '')
            cBox = wx.CheckBox(self.list)
            self.list.SetItemWindow(x, 0, cBox)
            self.list.SetStringItem(x, 1, self.t_col1[x])
            self.list.SetStringItem(x, 2, '.jpg')
            dBox = wx.ComboBox(self.list, value=self.t_col4[x], choices=rb_list, style=wx.CB_READONLY)
            self.list.SetItemWindow(x, 4, dBox, expand=True)

    def on_clear(self, event):
        for x in range(len(self.t_col1) -1 , -1, -1):
            if self.list.GetItemWindow(x, 0).IsChecked():
                self.t_col1.pop(x)
        self.list.DeleteAllItems()
        self.CreateList()
        event.Skip()

if __name__ == "__main__":
    ex = wx.App()
    Mywin(None, 'Row Delete Issue')
    ex.MainLoop()

Note that items are removed from the list in reverse, for obvious reasons and I use list.pop() so that I can use its position from range rather than list.remove()
I have not allowed for saving changes made to choices under the Rating column.



来源:https://stackoverflow.com/questions/52286106/wxpython-ultimatelistctrl-error-after-deleting-row

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!