python — Ошибка сегментации wxpython при удалении элемента из ListCtrl

Всякий раз, когда программа достигает self.DeleteItem сбой и печать Segmentation Fault (Core Dumped), После удаления self.DeleteItem он больше не падает, но мы теряем способность удалять строки. Я не уверен, что с этим не так, поскольку нарушена только одна строка. Можете ли вы помочь мне увидеть, если что-то не так?

Код

import wx
from wx.lib.mixins.listctrl import ListCtrlAutoWidthMixin
from scrapy.crawler import CrawlerProcess

from spider.spider import WIPOSpider
from settings import settings
from processor import process_xls

class MainFrame(wx.Frame):

TITLE = 'Neko'
FRAME_MIN_SIZE = (820, 220)
DEFAULT_BORDER_SIZE = 10

ADD_LABEL = 'Add'
REMOVE_LABEL = 'Remove'
START_LABEL = 'Start'

FILE_LABEL = 'File'
SIZE_LABEL = 'Size'
PERCENT_LABEL = 'Percent'
ETA_LABEL = 'ETA'
SPEED_LABEL = 'Speed'
STATUS_LABEL = 'Status'
STATUS_LIST = {
'filename': (0, FILE_LABEL, 300, False),
'size': (1, SIZE_LABEL, 80, False),
'percent': (2, PERCENT_LABEL, 80, False),
'eta': (3, ETA_LABEL, 80, False),
'speed': (4, SPEED_LABEL, 80, False),
'status': (5, STATUS_LABEL, 80, False),
}

def __init__(self, *args, **kwargs):
super(MainFrame, self).__init__(*args, **kwargs)

self.index = 0

self.SetTitle(self.TITLE)
self.SetSize(self.FRAME_MIN_SIZE)

self._panel = wx.Panel(self)
self._vertical_box = wx.BoxSizer(wx.VERTICAL)

# Status List
self._status_list = ListCtrl(self.STATUS_LIST,
parent=self._panel,
style=wx.LC_REPORT | wx.LEFT | wx.RIGHT)
self._horizontal_box_status_list = wx.BoxSizer(wx.HORIZONTAL)
self._horizontal_box_status_list.Add(self._status_list,
proportion=1, flag=wx.EXPAND)

status_list_buttons_data = {
('Add', self.ADD_LABEL, (-1, -1), self._on_add, wx.Button),
('remove', self.REMOVE_LABEL, (-1, -1), self._on_remove, wx.Button),
('start', self.START_LABEL, (-1, -1), self._on_start, wx.Button),
}

# Create buttons vertically
self._vertical_control_box = wx.BoxSizer(wx.VERTICAL)
for item in status_list_buttons_data:
name, label, size, evt_handler, parent = item

button = parent(self._panel, size=size)

if parent == wx.Button:
button.SetLabel(label)

if evt_handler is not None:
button.Bind(wx.EVT_BUTTON, evt_handler)

self._vertical_control_box.Add(button,
flag=wx.LEFT|wx.BOTTOM|wx.EXPAND,
proportion=1,
border=self.DEFAULT_BORDER_SIZE)

self._horizontal_box_status_list.Add(self._vertical_control_box)
self._vertical_box.Add(self._horizontal_box_status_list,
flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP,
border=self.DEFAULT_BORDER_SIZE)

# Set Sizer
self._panel.SetSizerAndFit(self._vertical_box)

def _on_add(self, event):
file_dialog = wx.FileDialog(self)
file_dialog.Show()

if file_dialog.ShowModal() == wx.ID_OK:
file_path = file_dialog.GetPath()
self._status_list.InsertItem(self.index, file_path)

self.index += 1

def _on_remove(self, event):
selected = self._status_list.get_selected()

if selected:
self._status_list.remove_row(selected)

def _on_start(self, event):
for item_count in range(0, self._status_list.GetItemCount()):
item = self._status_list.GetItem(item_count, col=0)
data = process_xls(item.GetText())

# Start spider
if data:
process = CrawlerProcess(settings['BOT_SETTINGS'])
process.crawl(WIPOSpider(data))
process.start()

# Copied from
# https://github.com/MrS0m30n3/youtube-dl-gui/blob/57eb51ccc8e2df4e8c766b31d677513adb5c86cb/youtube_dl_gui/mainframe.py#L1095
class ListCtrl(wx.ListCtrl, ListCtrlAutoWidthMixin):

"""Custom ListCtrl widget.
Args:
columns (dict): See MainFrame class STATUSLIST_COLUMNS attribute.
"""
def __init__(self, columns, *args, **kwargs):
super(ListCtrl, self).__init__(*args, **kwargs)
ListCtrlAutoWidthMixin.__init__(self)
self.columns = columns
self._list_index = 0
self._set_columns()

def remove_row(self, row_number):
self.DeleteItem(row_number)
self._list_index -= 1

def get_selected(self):
return self.GetNextItem(-1, wx.LIST_NEXT_ALL, wx.LIST_STATE_SELECTED)

def _set_columns(self):
"""Initializes ListCtrl columns.
See MainFrame STATUSLIST_COLUMNS attribute for more info. """for column_item in sorted(self.columns.values()):
self.InsertColumn(column_item[0], column_item[1], width=wx.LIST_AUTOSIZE_USEHEADER)

# If the column width obtained from wxLIST_AUTOSIZE_USEHEADER
# is smaller than the minimum allowed column width
# then set the column width to the minumum allowed size
if self.GetColumnWidth(column_item[0]) < column_item[2]:
self.SetColumnWidth(column_item[0], column_item[2])

# Set auto-resize if enabled
if column_item[3]:
self.setResizeColumn(column_item[0])

0

Решение

Очевидно, есть проблема с вашим подклассом ListCtrl или в ListCtrlAutoWidthMixin,
Если вы бросите свой подкласс и использовать стандарт ListCtrlкод работает.
то есть

self._status_list = wx.ListCtrl(self, -1,
style=wx.LC_REPORT)
for column_item in self.STATUS_LIST.values():
self._status_list.InsertColumn(column_item[0], column_item[1], width=column_item[2])

Тогда функция _on_remove будет выглядеть так:

def _on_remove(self, event):
selected = self._status_list.GetNextItem(-1, wx.LIST_NEXT_ALL, wx.LIST_STATE_SELECTED)
if selected >= 0:
self._status_list.DeleteItem(selected)

Примечание: вы в настоящее время определяете status_list_buttons_data как set, ваши кнопки будут отображаться более последовательно, если это list, Я считаю, что наборы не заказаны.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]