Whenever the program reach self.DeleteItem
it crashes and print Segmentation Fault (Core Dumped)
. After removing self.DeleteItem
it does not crash anymore but we lose the ability to remove a row. I am not sure what is wrong with this as it is only one line that is broken. Can you help me see if anything is wrong?
Code
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])
Clearly, there is an issue either with your sub-classing of ListCtrl
or in ListCtrlAutoWidthMixin
.
If you drop your sub-class and use a standard ListCtrl
, the code works.
i.e.
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])
Then the function _on_remove
becomes:
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)
Note: you are currently defining status_list_buttons_data
as a set
, your buttons would display more consistently if this was a list
. I believe that sets are un-ordered.