Unhandled exception

Sam23 wrote:

<<Is the problem that the ApptGrid window is not filling the notebook
page? >>
The ApptGrid actually seems to be overflowing the notebook page!
(further details below). The problem seems to be that the AuiNotebook
is not expanding to fill available space in the panel that contains it
(OuterPanel aka self.op). The AuiNotebook expands fine, if it doesn't
contain a CalendarPanel object. Once CalendarPanel is added to its
pages, AuiNotebook collapses to a tiny size of (96, 76).

<< If so then it's just because it's given a specific size of
(300,300) and that the parent
CalendarPanel does not have a sizer to manage the position and size of
its child so it stays at (0,0) (300,300).>>

[...]

This seems to expand it correctly when there is no AuiNotebook
involved; i.e. it is directly added to OuterPanel (wx.Panel) without
AuiNotebook as its parent. I tried changing the default size setting
to (-1, -1) instead of (300, 300), but it didn't seem to make any
difference.

<< (Set the CalendarPanel's bg color to something else to verify that,
or use the WIT's Highlight tool.)>>

I set CalendarPanel bg colour to Yellow, and yellow fills the
AuiNotebook, which is tiny. The blue still fills most of the
containing panel.

That is not what I'm seeing, maybe I didn't reenable the right lines in Werner's version of the files. (This is why I always ask for a *small* standalone sample, so confusions like this don't happen.)

Looking at the code and the hierarchy I just described, I suspect that
I may have messed up the sizers/parenting of these windows within
CalendarPanel. Ouch. I will take a closer look again.

Try ripping out everything that is not essential to make this crash happen. (Or start from scratch and make a new app that has the same problem.) That will help to isolate the cause of the problem and may even enable you to figure out what the problem is yourself.

One thing that I noticed is that the organization of your code and the objects is fairly messy. For example the ApptGrid uses a sizer but it is entirely managed outside of the ApptGrid class. Some widgets add themselves to this sizer, others are added to it from the CalendarPanel when it creates the widgets, etc. Using proper OOP encapsulation you should make the ApptGrid own and manage its own sizer, and probably also manage the adding of child widgets to itself.

If you reorganize the code to be more compliant to OO principles then you'll be less likely to get lost and make mistakes.

<< The problems may be related. For example, if you have a loop in
the
sizer containment then something may be being destroyed twice, which
would cause a crash like you're seeing. >>

Is this sizer containment Destroy() loop something inside my python
code or is this c++ code? Should I be looking for Destroy() in my
python code?

It's in C++. When a window is destroyed then it will destroy its sizer, which will destroy its nested sizers, etc.

If a loop always incorrectly destroys an item twice, should this
always cause a crash, or could it be intermittent? The exception is
intermittent even with the exact same sequence and data.

It could be intermittent.

···

--
Robin Dunn
Software Craftsman

After I wrote the reply to Robin’s mail I had this feeling that I got the OuterFrame parenting wrong. I hunted for this and guess what - I found that one line of code caused the tiny AuiNotebook size problem! Unfortunately, the intermittent “Unhandled Exception” problem is still there.

I attach the new set of code with this mail. The line of code changed is in vAps.py:
class CalendarPanel(wx.Panel):

def adjustScrollbars(self):
    self.mainSizer.Layout()
    op = self.parent  # this is the Outer Panel
    op.SetSize(op.GetBestSize())  # set the size of the OuterPanel which does not automatically adjust to best size

I changed line 819:
op = self.parent # this is the Outer Panel

to
op = self.GetParent().GetParent() # this is the Outer Panel

Initially, I didn’t have AuiNotebook. The CalendarPanel was directly under OuterPanel, and there was only 1 CalendarPanel. At that time, there was a problem when the frame was manually resized (using mouse) - OuterPanel didn’t adjust correctly to the new frame size. The op.SetSize(op.GetBestSize()) fixed the problem - I don’t know why, but it did.

Later I added AuiNotebook as a child of OuterPanel, and CalendarPanel became a child of AuiNotebook instead of OuterPanel. I also added another CalendarPanel. So OuterPanel became CalendarPanel’s GrandParent instead of parent. But line 819, still tried to get OuterPanel by getting CalendarPanel’s parent. Changing this to the GrandParent solved the tiny size problem for AuiNotebook.

So now, the parenting and sizing problem of AuiNotebook has been fixed.

But the “Unhandled Exception” is still there…

caps.zip (12.9 KB)

Werner,
<< Attached is a version of vAps.py which sizes fine for me.Robin's
tip on fixed sizes helped - basically got rid of all the hard coded
sizing stuff I came across.>>
Thanks. I will incorporate this into the code to remove hard coding.
Some of the hardcoding of sizes may have come about as I was trying to
figure out how to make the layout appear as I wanted it.

<< Now the crash is pretty predictable, it happens about every second
or
third move of the item "Giant Step" in the group 2.>>
That's better than my 'latest' fixed version, which usually happen on
the first shift of 'Giant Step'.

<< I think it is in "ResetCalPanel" but I can't figure it out and I
can't
catch it with an try/except either. >>
OK, I will have a close look at this.

<< Maybe instead of destroying/rebuilding all these things when you
shift
an entry it would be better to figure out a way to just move the
existing item, i.e. remove it from the grid and reinsert it.>>
The reason I did this was 'historical'. I started with the Add, and
the Delete of appointments. Both of these resulted in windows being
deleted and added, so to keep the sizers from getting confused, I
simply deleted and recreated everything. I think I started with trying
to keep windows and shifting, but if I recall correctly, the sizer
didn't like it. Actually with shift, there is also creation and
deletion of windows, at least 2 windows get deleted and at least 2
windows get created.

<< By the way the id's of ApptWindow instances are all "-n" - could it
be a problem that they are not positive numbers? >>
I used ID=-1

···

On Aug 6, 2:12 am, werner <wbru...@free.fr> wrote:

Sam,

Attached is a version of vAps.py which sizes fine for me.

Robin's tip on fixed sizes helped - basically got rid of all the hard
coded sizing stuff I came across.

Now the crash is pretty predictable, it happens about every second or
third move of the item "Giant Step" in the group 2.

I think it is in "ResetCalPanel" but I can't figure it out and I can't
catch it with an try/except either.

Maybe instead of destroying/rebuilding all these things when you shift
an entry it would be better to figure out a way to just move the
existing item, i.e. remove it from the grid and reinsert it.

By the way the id's of ApptWindow instances are all "-n" - could it be a
problem that they are not positive numbers?

Werner

vAps.py
30KViewDownload

<< By the way the id's of ApptWindow instances are all "-n" - could it
be a
problem that they are not positive numbers? >>
I used ID=-1, which means that the ID are automatically assigned by
wx.

···

On Aug 6, 2:12 am, werner <wbru...@free.fr> wrote:

Robin,

This is why I always ask for a *small*
standalone sample, so confusions like this don't happen.)

Ouch, sorry. I did try to create a minimalist version, but had some
difficulty with getting it to work after spending hours. So I tried
cutting down a 'working' version but as can be seen, still had a lot
of code.

Try ripping out everything that is not essential to make this crash
happen. (Or start from scratch and make a new app that has the same
problem.) That will help to isolate the cause of the problem and may
even enable you to figure out what the problem is yourself.

OK, will give it another go.

One thing that I noticed is that the organization of your code and the
objects is fairly messy. For example the ApptGrid uses a sizer but it
is entirely managed outside of the ApptGrid class. Some widgets add
themselves to this sizer, others are added to it from the CalendarPanel
when it creates the widgets, etc.

Thanks. Points noted. Will look at code structure.

Using proper OOP encapsulation you
should make the ApptGrid own and manage its own sizer, and probably also
manage the adding of child widgets to itself.

If you reorganize the code to be more compliant to OO principles then
you'll be less likely to get lost and make mistakes.

Thanks for the OO coding tips. Will relook at my code with this
perspective. The CalendarPanel was my first wx coding; actually first
Python project. This screen wasn't the easiest first wx coding for a
newbie to be attempting; and I got lost someway along the way...
Actually, I am from a mostly VB6/ASP background, so it is my first
'major' attempt at OO style coding too.

> It's in C++. When a window is destroyed then it will destroy its sizer,
which will destroy its nested sizers, etc.

That helps. I will look out for Destroy() of windows with sizers in
the code.

Robin, Werner
Thanks for all the useful tips and findings. Will rework the code
again. If there are any further info or ideas that can help, including
pointing out 'bad practices', please let me know.

Thanks.
Sam

···

On Aug 6, 2:30 am, Robin Dunn <ro...@alldunn.com> wrote:

Sam,

werner wrote:

Sam,

Attached is a version of vAps.py which sizes fine for me.

Robin's tip on fixed sizes helped - basically got rid of all the hard coded sizing stuff I came across.

Now the crash is pretty predictable, it happens about every second or third move of the item "Giant Step" in the group 2.
  

It happens on the second move if one moves it to the left most column.

I think it is in "ResetCalPanel" but I can't figure it out and I can't catch it with an try/except either.
  

Not that sure about this anymore, it is just that the debug print statements pointed to it, but on a crash/unhandeled exception these are not that reliable.

Still think it has to do with the apptSizer. I expected it to be empty after ResetCalPanel has removed the windows, however it still has over 200 children.

I can only see tracking of the "bookable" and the "callevents", but when adding to the sizer you have "tw", "iw", "pw", "aw", "bo" and "spacer" type windows. I can't see code which ensures that the newly shifted one does not overlap with an item already in the sizer.

Werner

I think I have found the cause of the ‘Unhandled Exception’ error. I attach the new set of files that don’t seem to have this error. I can’t really be sure that it is gone since there is something erratic about the problem - it had done a disappearing and reappearing trick several times before. But this is the first time the change looks like it is related to the problem.

The change I made was to comment out evt.Skip() in line 367 in vAps.py.

i.e.
def shiftStage2(self, evt):

if eventObject == self.destinationSlot:
# evt.Skip() # qqq This is the cause of the Unhandled Exception

I don’t know why this caused the intermittent ‘Unhandled Exception’. One possibility is that calling the Skip() too early was causing the program to enter into an endless event processing loop - Skip() threw it back up to App and then App threw it back here, ad infinitum. But if so, it would seem that it should be persistently crashing instead of intermittently.

The funny thing is that I distinctly remember that I deliberately sprinkled the code relating to this problematic ‘shift’ function with evt.Skip() in based on a worry that the ‘Unhandled Exception’ was caused by some system required event processing that had not been done. I had this unfounded idea that I could ‘empty out’ the event queue this way. I did not call Skip() in the event handling chain when I first wrote the code.

When Skip’ping everywhere didn’t help, I removed the Skip()'s that I had added, but there was apparently this one still left, and it seems to be the cause of the problem.

Any ideas regarding this?

cAps.zip (12.8 KB)

Werner,
Again really appreciate your help and Robin's help on these 2
problems. Over these 2 days, I have made significant progress on the
problem. The problem may have been solved (see my post just 2 minutes
after yours). As an added bonus, I have some good directions on how
to restructure and clean up the code.

In reply to the issues you raised below:

Sam,
Still think it has to do with the apptSizer. I expected it to be empty
after ResetCalPanel has removed the windows, however it still has over
200 children.

This has to do my 'hack' for displaying appointments up to 5 minutes
accuracy, even though the grid appears to have a resolution of only 30
minutes. To the right of the first column (time column) there is a
small grey column. It is not just a spacer but is actually composed of
close to 200 small windows..

These are the IntervalWindow panels.. Each represents 5 minutes -
there are 6 of them for every 30 minutes or 12 for every hour.
IntervalWindow, aka 'iw' is actually the basis of the schedule.. The
height of all the objects i.e. the period objects (the 30 minute
windows) and the appointments windows are 'determined' by 'iw', which
is the only object that has a specified size.

So, when I destroyed all the appointments, the IntervalWindows, the
period windows and the first row windows are what is left... The 200+
objects are mostly the IntervalWindow objects.. 16 hours has 16*12
i.e. 192 of the IntervalWindows.

I can only see tracking of the "bookable" and the "callevents", but when
adding to the sizer you have "tw", "iw", "pw", "aw", "bo" and "spacer"
type windows.

bookable are empty time slots available for booking.
calevents are calendar events i.e. already booked time slots.

I only 'track' these 2 during shift because the rest are 'fixed' e.g.
tw is for the first row (the column titles: e.g. 1 Token, 2 Ring, 3
Indie), iw is IntervalWindow (this is the real time axis - the first
column is just a cosmetic display for user to look at).

I can't see code which ensures that the newly shifted one

does not overlap with an item already in the sizer.

There are 3 stages:
(a) Before shift: The system only allows shifts to available (empty
time slots). This has been pre-calculated based on booked timeslots.
(A really complex looking computation)

(b) Shift: The appointment time is updated

(c) After shift: All the empty slots are recalculated based on the
updated appointment times (including those by other users). Hence
there will never be an overlap unless this recalculation of empty
slots is wrong. (which has happened before - ouch)

Cheers
Sam

···

On Aug 6, 2:51 pm, werner <wbru...@free.fr> wrote:

Sam23 wrote:

I think I have found the cause of the 'Unhandled Exception' error. I attach the new set of files that don't seem to have this error. I can't really be sure that it is gone since there is something erratic about the problem - it had done a disappearing and reappearing trick several times before. But this is the first time the change looks like it is related to the problem.

The change I made was to comment out evt.Skip() in line 367 in vAps.py.

i.e.
    def shiftStage2(self, evt):
....
        if eventObject == self.destinationSlot:
            # evt.Skip() # qqq This is the cause of the Unhandled Exception

I looks like you got it, at least I can't crash it anymore with the moves which previously crashed it.

So, shiftStage2 is not really an event handler, and you already have an evt.Skip in the calling event handler, so maybe change things to:

In onLeftUp:

    self.doShiftStage2(evt.GetEventObject)

And then change shiftStage to:
    def doShiftStage2(self, eventObject):
....
        if eventObject == self.destinationSlot:

Hopefully Robin or someone else can explain why the skip caused a problem. evt.Skip in my understanding, says I am not done go on to the next handler to finish the job.

Werner

Sam,

Sam23 wrote:

Werner,
Again really appreciate your help and Robin's help on these 2
problems.

You are welcome.

  Over these 2 days, I have made significant progress on the
problem. The problem may have been solved (see my post just 2 minutes
after yours). As an added bonus, I have some good directions on how
to restructure and clean up the code.

In reply to the issues you raised below:

Sam,
Still think it has to do with the apptSizer. I expected it to be empty
after ResetCalPanel has removed the windows, however it still has over
200 children.

This has to do my 'hack' for displaying appointments up to 5 minutes
accuracy, even though the grid appears to have a resolution of only 30
minutes. To the right of the first column (time column) there is a
small grey column. It is not just a spacer but is actually composed of
close to 200 small windows..
  

Why are you keeping this in the sizer?

Wouldn't it be better to just track the appoints etc in your database with a 5 minute accuracy and use the sizer/display just to show actual appoints and free slots?

Werner

···

On Aug 6, 2:51 pm, werner <wbru...@free.fr> wrote:

at least I can't crash it anymore with the
moves which previously crashed it.

I really hope so. The 'unhandled exception' spooked me a great deal.
Not used to not having a informative error message and having the
program crash, not midway through code, but after everything (in my
code) has ended.

So, shiftStage2 is not really an event handler,

I am not sure whether these are just semantics.. The event handler is
not processed within a single method but a method with calls to a
chain of other methods, some in other classes (part of my MVC
wanderings). The way the event handling chain goes is as follows:

Event handler for the clicks in the ApptGrid are not specified at the
windows level and bubbles up to the Application level where they are
handled. This is because I didn't want to code an event handler for
each of the many panels (for 2 types of classes). At the App level,
the onLeftUp event handler checks if it is a click inside the
ApptGrid. If so, it passes the handling of the event over to vAps's
onLeftUp(). There are different types of clicks - clicks to add new
appointment, clicks to view appointments, clicks to shift
appointments, clicks to confirm appointment shifts. vAps' onLeft up
decides what the click means and calls the appropriate method in the
model. In this case, the click is a 'confirmation of shift' click and
vAps' onLeftUp calls the shiftStage2 method... etc.

Hopefully Robin or someone else can explain why the skip caused a
problem. evt.Skip in my understanding, says I am not done go on to the
next handler to finish the job.

Yup, that's what I understand of it too. Not sure why it would crash
the program in such a manner. I think it is maybe something clear to
Robin and the other developers at wxPython.

Cheers
Sam

···

On Aug 6, 3:48 pm, werner <wbru...@free.fr> wrote:

Sam,

Sam23 wrote:

···

On Aug 6, 3:48 pm, werner <wbru...@free.fr> wrote:
  

at least I can't crash it anymore with the
moves which previously crashed it.

I really hope so. The 'unhandled exception' spooked me a great deal.
Not used to not having a informative error message and having the
program crash, not midway through code, but after everything (in my
code) has ended.

So, shiftStage2 is not really an event handler,

I am not sure whether these are just semantics..

Agree, I just think if the method signature does not look like one for an event handler you will not be tempted to add and "evt.Skip()" call to that method :wink:

Werner

You are right on both the storage and display. The explanation is as
follows:

The appointment will be kept as records in a database with start and
end times as datetime type. So, their resolution capability is
actually far better than 5 minutes.

The 5 minute resolution refers to the display resolution capability
i.e. the system is able to display with a resolution of up to 5
minutes e.g. the display of appointments that start at 9:15 or 9:20
will have a visible difference to the user onscreen, even though the
'visible' period intervals are 30 minutes.

5 minutes is probably more than enough display accuracy for the users
- but 30 minutes is too coarse.

So, the sizer isn't being used to keep the appointment timing, merely
to display it. The appointment details are to be read from a database
and then displayed in the table. The BagGridSizer is used to align the
appointment vertically (with the IntervalWindows timescale) and
horizontally with the column labels. It has the added 'benefit'
crashing of there is bug in the system that allows overlapping
appointments.

If you look at the code closely, you will see these 2 aspects - the
storage of the appointment (mostly in the model) and the display
(mostly in the view).. but as I said, the code organisation got messed
up, when I ran out of time and gave up the MVC, and simply tried to
get something visibly 'working'.

···

On Aug 6, 4:28 pm, werner <wbru...@free.fr> wrote:

> This has to do my 'hack' for displaying appointments up to 5 minutes
> accuracy, even though the grid appears to have a resolution of only 30

Why are you keeping this in the sizer?

Wouldn't it be better to just track the appoints etc in your database
with a 5 minute accuracy and use the sizer/display just to show actual
appoints and free slots?

Werner,

Agree, I just think if the method signature does not look like one for
an event handler you will not be tempted to add and "evt.Skip()" call to
that method :wink:

After this unnerving experience, I doubt I will be tempted to add Skip
() to anything for a long, long time :stuck_out_tongue:

But yes, I agree, there should be some means to be clear on where the
method stands in terms of whether it should Skip(). I will look at
this further. I did feel that the event handling calls went too far
in that it was all over the place (classes). Thanks for pointing this
out and clarifying it.

···

On Aug 6, 10:09 pm, werner <wbru...@free.fr> wrote:

Sam23 wrote:

I think I have found the cause of the 'Unhandled Exception' error. I attach the new set of files that don't seem to have this error. I can't really be sure that it is gone since there is something erratic about the problem - it had done a disappearing and reappearing trick several times before. But this is the first time the change looks like it is related to the problem.

The change I made was to comment out evt.Skip() in line 367 in vAps.py.

i.e.
    def shiftStage2(self, evt):
....
        if eventObject == self.destinationSlot:
            # evt.Skip() # qqq This is the cause of the Unhandled Exception

I don't know why this caused the intermittent 'Unhandled Exception'. One possibility is that calling the Skip() too early was causing the program to enter into an endless event processing loop - Skip() threw it back up to App and then App threw it back here, ad infinitum. But if so, it would seem that it should be persistently crashing instead of intermittently.

Skip does not cause the base event handlers to be called from within the Skip call. It just sets a flag that is checked after the current event handler returns that tells the system to continue processing the event as if it had not been handled yet and keep looking for a handler. If you don't call Skip then that tells the system to stop processing this event.

···

--
Robin Dunn
Software Craftsman

I was worried that there didn’t seem to be a good reason for Skip() to be causing the ‘Unhandled Exception’ error. I looked into the code further, and did more commenting and uncommenting testing.

I have finally found out the ‘real’ cause of the ‘unhandled exception’. I then went to clean up the code to show this clearly. I attach the cleaned up code, which shows the problem. It now only requires 1 file: vAps.py, and is only about 100 lines long.

The problem seems to be that the window from which an event originates cannot be destroyed in the event handler for the event. This is a concern for me since my design involves the destruction the of the window in which the event originates.

It looks like I can circumvent this limitation by not calling Skip() in the event handler. My question is:
*** Is this OK? *** Or is there some rule against destroying a windows in the event handler for an event that originates in that window? If yes, I will need to redesign the code.

I provide some explanation for the demonstration of the ‘unhandled exception’ here:
Run vAps.py
A blue window with 2 yellow panels are shown. The first yellow panel is labeled ‘000’ and THE second, ‘111’.

The onLeftUp event handler will destroy both of the yellow panels. i.e. a click anywhere in the window, either in the blue portion or the yellow panels will result in the 2 yellow panels being destroyed.

If the click is on either of the 2 yellow panels, the ‘Unhandled Exception’ error will occur. This is after both yellow panels are destroyed. If you click on ‘Ignore’, the program appears to continue, none the worse.

If the click is outside the 2 yellow panels, i.e. in the blue area, no errors will occur. This is because the event did not originate from within the either of the 2 yellow panels. The 2 yellow panels will be destroyed.

If you comment out evt.Skip() in Line 73 (which is in the onLeftUp event handler), no ‘Unhandled exception’ will occur even if the click is in one of the yellow panels.

You can also try commenting out line 55 and uncommenting line 56:

55 window.Destroy()
56 # if window != eventObject: window.Destroy()

This prevents the Destroy() of the window from which the click originates. With this, ‘Unhandled Exception’ will not occur either, even with the Skip() statement. Only one yellow window will be destroyed (the one which was not clicked).

I also tried handling the event from inside EmptySlot (the class for the YellowPanels) instead of from inside App, but the result is the same: ‘Unhandled Exception’ when the window from which the event originates is destroyed.

vAps.py (3.28 KB)

···

2009/8/7 Robin Dunn robin@alldunn.com

Skip … just sets a flag that is checked after the current event

handler returns that tells the system to continue processing the event

as if it had not been handled yet and keep looking for a handler.

Sam,

Sam23 wrote:

2009/8/7 Robin Dunn <robin@alldunn.com <mailto:robin@alldunn.com>>

    Skip ... just sets a flag that is checked after the current event
    handler returns that tells the system to continue processing the event
    as if it had not been handled yet and keep looking for a handler.

I was worried that there didn't seem to be a good reason for Skip() to be causing the 'Unhandled Exception' error. I looked into the code further, and did more commenting and uncommenting testing.

I have finally found out the 'real' cause of the 'unhandled exception'. I then went to clean up the code to show this clearly. I attach the cleaned up code, which shows the problem. It now only requires 1 file: vAps.py, and is only about 100 lines long.

The problem seems to be that the window from which an event originates cannot be destroyed in the event handler for the event. This is a concern for me since my design involves the destruction the of the window in which the event originates.

It looks like I can circumvent this limitation by not calling Skip() in the event handler.

Or you can leave the event.Skip() in the onLeftUp and change the call from:
    self.ResetCalPanels(eventObject)
to:
     wx.CallAfter(self.ResetCalPanels, eventObject)

Werner

Werner,
That's a really neat trick. I didn't realise that I could so easily
schedule a method call to run after an event handler had completed. I
was actually contemplating setting up timer to run code after the
event handler completed... but it seemed overly complicated and I was
afraid it might not be robust - timing concerns. This is much better.

I tested it and found that it works. Interestingly, I tried passing
the event itself (evt) instead of the eventObject, and it still worked
- i.e. the event was still available after event handling had ended.
Hopefully, this won't be a trip point somewhere else along the way!

Thanks for this new tip.

Cheers
Sam

···

On Aug 8, 12:18 am, werner <wbru...@free.fr> wrote:

Sam,

Sam23 wrote:
> 2009/8/7 Robin Dunn <ro...@alldunn.com <mailto:ro…@alldunn.com>>

> Skip ... just sets a flag that is checked after the current event
> handler returns that tells the system to continue processing the event
> as if it had not been handled yet and keep looking for a handler.

> I was worried that there didn't seem to be a good reason for Skip() to
> be causing the 'Unhandled Exception' error. I looked into the code
> further, and did more commenting and uncommenting testing.

> I have finally found out the 'real' cause of the 'unhandled
> exception'. I then went to clean up the code to show this clearly. I
> attach the cleaned up code, which shows the problem. It now only
> requires 1 file: vAps.py, and is only about 100 lines long.

> The problem seems to be that the window from which an event originates
> cannot be destroyed in the event handler for the event. This is a
> concern for me since my design involves the destruction the of the
> window in which the event originates.

> It looks like I can circumvent this limitation by not calling Skip()
> in the event handler.

Or you can leave the event.Skip() in the onLeftUp and change the call from:
self.ResetCalPanels(eventObject)
to:
wx.CallAfter(self.ResetCalPanels, eventObject)

Werner

Sam23 wrote:

Werner,
That's a really neat trick. I didn't realise that I could so easily
schedule a method call to run after an event handler had completed. I
was actually contemplating setting up timer

then you could use wx.CallLater :slight_smile:

to run code after the
event handler completed... but it seemed overly complicated and I was
afraid it might not be robust - timing concerns. This is much better.

I tested it and found that it works. Interestingly, I tried passing
the event itself (evt) instead of the eventObject, and it still worked
- i.e. the event was still available after event handling had ended.
  

I would still use the eventObject - just a gut feel, but hopefully Robin can give you a better guideline when to use which.

Hopefully, this won't be a trip point somewhere else along the way!

Thanks for this new tip.
  

You are welcome, but the thanks should go to Robin for providing all these little goodies.
Werner

I would still use the eventObject - just a gut feel,

Yes, I also feel a bit worried about using an event after its event
handler has completed. Could be living dangerously on the edge...

but hopefully Robin can give you a better guideline
when to use which.

Yes, I think this problem raises a fundamental question that could do
with clarification i.e. when can Destroy() be safely called - and/or
how to safely call Destroy()? It may also help others avoid this
problem. I looked this up further and have these findings:

----- According to the wxWidgets reference:
-- wxWindow::Destroy
Destroys the window ** safely **. Use this function instead of the
delete operator, since different window classes can be destroyed
differently. *** Frames and dialogs *** are ** not destroyed **
immediately *** when this function is called -- they are added to a
list of windows to be deleted on idle time, when all the window's
events have been processed. This prevents problems with events being
sent to non-existent windows.

So it looks like Frames and dialogs can be destroyed safely, but
panels are not listed.. It was the Destroy() of a wx.Panel that cause
my application to crash.

In my Googling for this problem, I found at least one other victim of
the wx.Panel crash: Alexander Fischer in Oct 2008. Interestingly, he
also said that "I wish i could give you an example of this, but I'm
not able to write a less complex application, that reproduces this
behaviour, so i can't show you." i.e. exactly the same difficulty I
faced at first! My application was working fine for a long time and
when it started crashing, I had no idea which part was breaking. I
did debug prints every where right till the program ended - without
any findings. I didn't know how to proceed. One lesson for me is that
this type of problem requires different debug techniques from what I
was familiar with before (in VB and ASP).

Here is an excerpt of Fisher's post and Robin's reply

···

On Aug 8, 1:10 am, werner <wbru...@free.fr> wrote:
---------------------------------------------------------
Datum: Tue, 07 Oct 2008 16:37h
Von: Robin Dunn <robin@...>
An: wxpython-users@...
Betreff: Re: [wxpython-users] Crash while calling Destroy()

Alexander Fischer wrote:

I'm writing an application with a wx.treectrl on the left and a *** panel *** on the right. Every item selection destroys a panel on the right and adds a new one. Until wxPython 2.8.8.1 all was fine, but with the new 2.8.9.1 version, my application crashes without any feedback while calling the panels Destroy() method.
I wish i could give you an example of this, but I'm not able to write a less complex application, that reproduces this behaviour, so i can't show you.

Has anybody an idea of what I'm doing wrong?

    def OnSelChanged(self, event = None):
        item = event.GetItem()
        if not item.IsOk():
            return
        #Delete old panel
        for i in self.parent.propertiesPanel.GetChildren():
            if i.GetName() == "propertyPanel":
                i.Destroy()

... [show rest of quote]

In addition to Tim's suggestions I would suggest trying to delay the
destroy until you are sure that there are no pending events for the
panel. You can do that with something like this:

        i.Hide()
        wx.CallAfter(i.Destroy)

--
Robin Dunn
Software Craftsman

-----------------------------------------

You are welcome, but the thanks should go to Robin
for providing all these little goodies.

Yes, definitely. Thanks to Robin for creating wxPython, and his strong
support for the wxPython community. Also for the other major wxPython
players, yourself and other volunteers contributing actively in this
forum. At least I don't feel lost alone :stuck_out_tongue: