There seems to be more that I don't understand ; -) AssignImageList ...

hello,

I've a fairly large program,
that uses a lot of icon sized images.
So I use the following construct:
- all images are placed in one subdirectory
- on start of the program, I read all images, scale them and place then in a global Global_ImageList (with a trick to maintain the order).
- now when I need icons, e.g. for treectrl, notebook, or whatever, I use AssignImageList ( Global_ImageList )

until now it seemed to work ok,
but ...
in the following case it goes wrong:

- the program starts with a tree and I assign the Global_ImageList to it.
- dynamically I create a notebook (on another form) and assign the same Global_ImageList to it
- now I dynamically destroy the form with the notebook

and then my Global_ImageList seems to be destroyed too.
Why ?
Isn't this a allowed / good method of handling many imagelists ?

The effect is that my main program's tree doesn't have an imagelist anymore,
tries to refresh and crashes.

thanks,
Stef

Hello,

hello,

I've a fairly large program,
that uses a lot of icon sized images.
So I use the following construct:
- all images are placed in one subdirectory
- on start of the program, I read all images, scale them and place then in a global Global_ImageList (with a trick to maintain the order).
- now when I need icons, e.g. for treectrl, notebook, or whatever, I use AssignImageList ( Global_ImageList )

until now it seemed to work ok,
but ...
in the following case it goes wrong:

- the program starts with a tree and I assign the Global_ImageList to it.
- dynamically I create a notebook (on another form) and assign the same Global_ImageList to it
- now I dynamically destroy the form with the notebook

and then my Global_ImageList seems to be destroyed too.
Why ?
Isn't this a allowed / good method of handling many imagelists ?

The effect is that my main program's tree doesn't have an imagelist anymore,
tries to refresh and crashes.

I believe that when you assign an image list to a window it take ownership of the memory for that object (remember this is c++ code down below). So when it is destroyed it deletes its members during cleanup, leaving your reference as a pointer to a deleted object.

The same affect can be seen in reverse if you create an image list, assign it to a window, then let it go out of scope. When python cleans up the image list you created it will create a bad reference that when the window tries to access now deleted object will cause a crash.

i.e

def __init__()
     imglst = wx.ImageList(...)
     imgst.Add(...)
     tree = wx.TreeCtrl(...)
     tree.SetImageList(imglst)

When this method goes out of scope python will cleanup the imglst variable which will cause the list to be deleted so when the TreeCtrl tries to access it it has a pointer to a null object which will cause a crash. Thats why you need to keep reference to it by assigning it to an attribute of the class 'self.imglst' so that it doesn't get deleted until the object it belongs to does.

So if you are using ImageList you will need to make copies for each window that uses it before using SetImageList and keep reference to that copy within the object itself.

Cody

···

On Dec 20, 2008, at 2:39 PM, Stef Mientki wrote:

thanks Cody,

but it think it's somewhat more complex ...

Cody Precord wrote:

Hello,

hello,

I've a fairly large program,
that uses a lot of icon sized images.
So I use the following construct:
- all images are placed in one subdirectory
- on start of the program, I read all images, scale them and place then in a global Global_ImageList (with a trick to maintain the order).
- now when I need icons, e.g. for treectrl, notebook, or whatever, I use AssignImageList ( Global_ImageList )

until now it seemed to work ok,
but ...
in the following case it goes wrong:

- the program starts with a tree and I assign the Global_ImageList to it.
- dynamically I create a notebook (on another form) and assign the same Global_ImageList to it
- now I dynamically destroy the form with the notebook

and then my Global_ImageList seems to be destroyed too.
Why ?
Isn't this a allowed / good method of handling many imagelists ?

The effect is that my main program's tree doesn't have an imagelist anymore,
tries to refresh and crashes.

I believe that when you assign an image list to a window it take ownership of the memory for that object (remember this is c++ code down below). So when it is destroyed it deletes its members during cleanup, leaving your reference as a pointer to a deleted object.

The same affect can be seen in reverse if you create an image list, assign it to a window, then let it go out of scope. When python cleans up the image list you created it will create a bad reference that when the window tries to access now deleted object will cause a crash.

i.e

def __init__()
    imglst = wx.ImageList(...)
    imgst.Add(...)
    tree = wx.TreeCtrl(...)
    tree.SetImageList(imglst)

When this method goes out of scope python will cleanup the imglst variable which will cause the list to be deleted so when the TreeCtrl tries to access it it has a pointer to a null object which will cause a crash. Thats why you need to keep reference to it by assigning it to an attribute of the class 'self.imglst' so that it doesn't get deleted until the object it belongs to does.

So if you are using ImageList you will need to make copies for each window that uses it before using SetImageList and keep reference to that copy within the object itself.

I create the ImageList in the main form created first and which remains the whole session
    self.Image_List = Get_Image_List ()
but the program still crashes if another form with a notebook (assigned to the same global image list) closes.
I also tried copy.copy but doesn't have any positive effect.
I also tried copy.deepcopy, but that produces a huge error message

Traceback (most recent call last):
  File "D:\Data_Python_25\PyLab_Works\control_output_viewer.py", line 312, in __init__
    self.image_list = copy.deepcopy ( Get_Image_List () )
  File "P:\Python\lib\copy.py", line 189, in deepcopy
    y = _reconstruct(x, rv, 1, memo)
  File "P:\Python\lib\copy.py", line 337, in _reconstruct
    state = deepcopy(state, memo)
  File "P:\Python\lib\copy.py", line 162, in deepcopy
    y = copier(x, memo)
  File "P:\Python\lib\copy.py", line 254, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "P:\Python\lib\copy.py", line 189, in deepcopy
    y = _reconstruct(x, rv, 1, memo)
  File "P:\Python\lib\copy.py", line 322, in _reconstruct
    y = callable(*args)
  File "P:\Python\Lib\copy_reg.py", line 92, in __newobj__
    return cls.__new__(cls, *args)
TypeError: object.__new__(PySwigObject) is not safe, use PySwigObject.__new__()

So for the moment I just create a new imagelist every time I need one.
Will think about another/better solution.

cheers,
Stef

···

On Dec 20, 2008, at 2:39 PM, Stef Mientki wrote:

Hello,

thanks Cody,

but it think it's somewhat more complex ...

Not really :wink:

I believe that when you assign an image list to a window it take ownership of the memory for that object (remember this is c++ code down below). So when it is destroyed it deletes its members during cleanup, leaving your reference as a pointer to a deleted object.

The same affect can be seen in reverse if you create an image list, assign it to a window, then let it go out of scope. When python cleans up the image list you created it will create a bad reference that when the window tries to access now deleted object will cause a crash.

i.e

def __init__()
   imglst = wx.ImageList(...)
   imgst.Add(...)
   tree = wx.TreeCtrl(...)
   tree.SetImageList(imglst)

When this method goes out of scope python will cleanup the imglst variable which will cause the list to be deleted so when the TreeCtrl tries to access it it has a pointer to a null object which will cause a crash. Thats why you need to keep reference to it by assigning it to an attribute of the class 'self.imglst' so that it doesn't get deleted until the object it belongs to does.

So if you are using ImageList you will need to make copies for each window that uses it before using SetImageList and keep reference to that copy within the object itself.

I create the ImageList in the main form created first and which remains the whole session
  self.Image_List = Get_Image_List ()
but the program still crashes if another form with a notebook (assigned to the same global image list) closes.

This is just as I explained above since you have one reference / one instance to the list object and then assign it to a window. At the point you assign it to a window that window gets a pointer to the object. When that window is destroyed it cleans up its members (the pointer to your list is one of them) when it cleans up it will delete the object that pointer is pointing to. Thus at that point your 'self.Image_List' is a reference to a deleted object, and any other window you assigned it to will also now have a reference to a deleted object. Which is why it will crash the next time any of them try to access the bad memory that that reference points to.

I also tried copy.copy but doesn't have any positive effect.
I also tried copy.deepcopy, but that produces a huge error message

Traceback (most recent call last):
File "D:\Data_Python_25\PyLab_Works\control_output_viewer.py", line 312, in __init__
  self.image_list = copy.deepcopy ( Get_Image_List () )
File "P:\Python\lib\copy.py", line 189, in deepcopy
  y = _reconstruct(x, rv, 1, memo)
File "P:\Python\lib\copy.py", line 337, in _reconstruct
  state = deepcopy(state, memo)
File "P:\Python\lib\copy.py", line 162, in deepcopy
  y = copier(x, memo)
File "P:\Python\lib\copy.py", line 254, in _deepcopy_dict
  y[deepcopy(key, memo)] = deepcopy(value, memo)
File "P:\Python\lib\copy.py", line 189, in deepcopy
  y = _reconstruct(x, rv, 1, memo)
File "P:\Python\lib\copy.py", line 322, in _reconstruct
  y = callable(*args)
File "P:\Python\Lib\copy_reg.py", line 92, in __newobj__
  return cls.__new__(cls, *args)
TypeError: object.__new__(PySwigObject) is not safe, use PySwigObject.__new__()

So for the moment I just create a new imagelist every time I need one.
Will think about another/better solution.

Creating a copy is the same thing as making a new list with the same values in it. It just means that there is a new object with its own memory. So each Window can own its own and won't be able to delete the memory used by one of the other windows.

Cody

···

On Dec 20, 2008, at 4:09 PM, Stef Mientki wrote:

Stef Mientki wrote:

hello,

I've a fairly large program,
that uses a lot of icon sized images.
So I use the following construct:
- all images are placed in one subdirectory
- on start of the program, I read all images, scale them and place then in a global Global_ImageList (with a trick to maintain the order).
- now when I need icons, e.g. for treectrl, notebook, or whatever, I use AssignImageList ( Global_ImageList )

until now it seemed to work ok,
but ...
in the following case it goes wrong:

- the program starts with a tree and I assign the Global_ImageList to it.
- dynamically I create a notebook (on another form) and assign the same Global_ImageList to it
- now I dynamically destroy the form with the notebook

and then my Global_ImageList seems to be destroyed too.
Why ?

AssignImageList "assigns" ownership of the image list to the control, SetImageList does not. So if you are going to want to share the image list then you need to use SetImageList and maintain a Python reference to the image list to prevent it from being garbage collected.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!