问题描述
我一直在使用 wxPython 和 UltimateListCtrl 为项目创建 GUI.对于我的 GUI,有几个面板具有 UltimateListCtrls,并且我遇到了一个我似乎无法解决的问题.我的 GUI 包含一个包含 5 列的文件列表:一个复选框列、一个文件名列、一个文件扩展名列、一个文件大小列和一个组合框列.GUI 示例在列表下方,我有一个按钮,单击该按钮将删除选中复选框的任何行.例如,在删除第 1 行并单击最后一行的 CheckBox 或 ComboBox 后,我的问题就出现了.当我这样做时,我收到此错误:
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 GUIBelow 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:
回溯(最近一次调用最后一次):OnSetFocus 中的文件C:\Users\Media_i5\PycharmProjects\PicThings\venv\lib\site-packages\wx\lib\agw\ultimatelistctrl.py",第 2260 行select = listCtrl.GetItemState(self._itemId, ULC_STATE_SELECTED)GetItemState 中的文件C:\Users\Media_i5\PycharmProjects\PicThings\venv\lib\site-packages\wx\lib\agw\ultimatelistctrl.py",第 8944 行引发异常(GetItemState 中的项目索引无效")异常:GetItemState 中的项目索引无效
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
当我回溯调用时,我发现当我删除一行时,后续每一行的 ID/索引都会更新以匹配其在列表中的新位置,但 CheckBox 的 ID/索引不是.在下面的示例代码中,当索引 1(第 2 行)处的行被删除时,索引 2 处的行变为索引 1,索引 3 变为索引 2,等等......但是移动到索引的行上的复选框/组合框1 的 ID/Index 仍为 2.在这种情况下,删除第 1 行后,如果单击最后一行的 CheckBox/ComboBox,则会标记上述错误,因为 Box 的索引大于行.
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.
我希望这是有道理的.下面附上一个小示例代码,它说明了这个问题.运行代码,单击图 1 的复选框,单击清除按钮,然后单击图 7 的复选框.
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.
谁能帮我弄清楚为什么盒子的 ID/索引没有像行一样自动更新?
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()
推荐答案
您可以通过使用 list
t_col1 重新构建 listctrl
来解决此问题.
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()
请注意,出于显而易见的原因,项目从列表中反向删除,我使用 list.pop()
以便我可以使用 range
中的位置而不是list.remove()
我不允许在 Rating
列下保存对 choices
所做的更改.
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.
这篇关于删除行后wxPython UltimateListCtrl错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!