Ошибка wxPython UltimateListCtrl после удаления строки - PullRequest
0 голосов
/ 12 сентября 2018

Я работал с wxPython и UltimateListCtrl, чтобы создать графический интерфейс для проекта. Для моего GUI есть несколько панелей с UltimateListCtrls, и я столкнулся с проблемой, которую не могу исправить. Мой графический интерфейс состоит из списка файлов с 5 столбцами: столбец CheckBox, столбец с именем файла, столбец с расширением файла, столбец с размером файла и столбец ComboBox. Пример GUI Под списком у меня есть кнопка, которая при нажатии удалит любую строку, чей флажок отмечен. Моя проблема возникает после того, как я удаляю, например, строку 1 и нажимаю либо CheckBox, либо ComboBox для последней строки. Когда я получаю эту ошибку:

Traceback (последний вызов был последним): Файл "C: \ Users \ Media_i5 \ PycharmProjects \ PicThings \ venv \ lib \ site-packages \ wx \ lib \ agw \ ultimatelistctrl.py", строка 2260, в OnSetFocus select = listCtrl.GetItemState (self._itemId, ULC_STATE_SELECTED) Файл "C: \ Users \ Media_i5 \ PycharmProjects \ PicThings \ venv \ lib \ site-packages \ wx \ lib \ agw \ ultimatelistctrl.py", строка 8944, в GetItemState повысить исключение («недопустимый индекс элемента в GetItemState») Исключение: недопустимый индекс элемента в GetItemState

Когда я отслеживаю вызовы, я обнаруживаю, что при удалении строки идентификатор / индекс для каждой следующей строки обновляется, чтобы соответствовать ее новой позиции в списке, но идентификатор / индекс для CheckBox, ComboBox - нет. В приведенном ниже примере кода при удалении строки с индексом 1 (строка 2) строка с индексом 2 становится индексом 1, индекс 3 становится индексом 2 и т. Д. Однако флажок / ComboBox в строке, которая переместилась в индекс 1 по-прежнему имеет идентификатор / индекс 2. В этом сценарии после удаления строки 1, если щелкнуть CheckBox / ComboBox в последней строке, указанная выше ошибка помечается, поскольку индекс для Box больше, чем число строки.

Надеюсь, это имеет смысл. Ниже приведен небольшой пример кода, иллюстрирующий проблему. Запустите код, щелкните флажок для рисунка 1, нажмите кнопку «Очистить», затем щелкните флажок для рисунка 7.

Может кто-нибудь помочь мне выяснить, почему идентификатор / индекс для ящиков не обновляются автоматически, как строка?

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 Ответ

0 голосов
/ 12 сентября 2018

Вы можете обойти эту проблему, перестроив listctrl, используя 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()

Обратите внимание, что элементы удаляются из списка в обратном порядке по понятным причинам, и я использую list.pop() чтобы я мог использовать его положение с range вместо list.remove()
Я не разрешил сохранять изменения, сделанные в choices в столбце Rating.

...