CheckListCtrl with Images crashes on Linux

Hi,

I have a custom ListCtrl with images.
At some place, I want the user to be able to check some items,
but I don’t want to rewrite the whole ListCtrl.
So I mixed in the CheckListCtrlMixin. As this mixin creates its own image list
(btw, I think it would be nice, if one could pass an existing image list to the mixin that is extended),
I wrote some init code that
either extends this image list (for the checked case) or creates a new one (for the plain list):

class MyList(wx.ListCtrl):
def init(self):
super(MyList, self).init();
self.il = None;

def _GetImageList(self):
    if not self.il:
        self.il = wx.ImageList(16, 16);
    return self.il

def Init(self, res_manager):
    il = self._GetImageList();
    self.image_index = {}
    self.image_index['foo'] = il.Add(wx.Bitmap('some_image.png'),wx.BITMAP_TYPE_PNG));
    self.SetImageList(il, wx.IMAGE_LIST_SMALL); 

class MyCheckedList(MyList, listmix.CheckListCtrlMixin):

def __init__(self):
    MyList.__init__(self);
    listmix.CheckListCtrlMixin.__init__(self);
        
def _GetImageList(self):
    return self._CheckListCtrlMixin__imagelist_;

This works fine under Windows XP.
However, under xubuntu 12, I get a segfault in wxListMainWindow::SetImageList.
(both cases with wxpython 2.8)
Any idea what is going wrong on xubuntu?

I expect that since you are using SetImageList with the same wx.ImageList more than once then you are causing wx to use the same object after it has been deleted. Or something like that.

BTW, you should be able to use self.GetImageList(wx.IMAGE_LIST_SMALL) instead of digging in to the base class and using its attribute directly. It will return None if one hasn't been set yet.

···

On 5/12/12 1:29 AM, Patrick Ruoff wrote:

Hi,

I have a custom ListCtrl with images.
At some place, I want the user to be able to check some items,
but I don't want to rewrite the whole ListCtrl.
So I mixed in the CheckListCtrlMixin. As this mixin creates its own
image list
(btw, I think it would be nice, if one could pass an existing image list
to the mixin that is extended),
I wrote some init code that
either extends this image list (for the checked case) or creates a new
one (for the plain list):

class MyList(wx.ListCtrl):
def __init__(self):
super(MyList, self).__init__();
self.il = None;

def _GetImageList(self):
if not self.il:
self.il = wx.ImageList(16, 16);
return self.il

def Init(self, res_manager):
il = self._GetImageList();
self.image_index = {}
self.image_index['foo'] =
il.Add(wx.Bitmap('some_image.png'),wx.BITMAP_TYPE_PNG));
self.SetImageList(il, wx.IMAGE_LIST_SMALL);

class MyCheckedList(MyList, listmix.CheckListCtrlMixin):

def __init__(self):
MyList.__init__(self);
listmix.CheckListCtrlMixin.__init__(self);

def _GetImageList(self):
return self._CheckListCtrlMixin__imagelist_;

This works fine under Windows XP.
However, under xubuntu 12, I get a segfault in
wxListMainWindow::SetImageList.
(both cases with wxpython 2.8)
Any idea what is going wrong on xubuntu?

--
Robin Dunn
Software Craftsman

Hi Robin,
thank you for the answer!
After hours of debugging I found out that the error is somewhere else,
it is due to a late processing of the EVT_WINDOW_CREATE event.
If I create some XRC dialog, like this

import wx
import wx.xrc as xrc

app = wx.App(False)
frame = wx.Frame(None)
xrc_res = xrc.XmlResource(‘test.xrc’)

def Go(dlg):
print ‘Init Dialog’
dlg.ShowModal();

def OnButton(evt):
dlg = xrc_res.LoadDialog(frame, ‘MyDialog’);
wx.CallAfter(Go, dlg);

button = wx.Button(frame)
button.Bind(wx.EVT_BUTTON, OnButton)
frame.Show()
app.MainLoop()

and in the dialog, I have a custom widget

import wx

class MyListCtrl(wx.ListCtrl):
def init(self):
pre = wx.PreListCtrl()
self.PostCreate(pre)
self.Bind(wx.EVT_WINDOW_CREATE, self.OnCreate)

def OnCreate(self, event):
    print 'OnCreate'
    if self is event.GetEventObject():
        self.Unbind(wx.EVT_WINDOW_CREATE)

then the problem is that on WindowsXP, the ‘OnCreate’ is executed before ‘Init Dialog’
whereas on Xubuntu it is executed afterwards. (doesn’t even matter if I use wx.CallAfter or not)

Where should I initialize my dialog controls and when/where can I safely use them afterwards?