[PEAK] Re: Trellis + wx

Sergey Schetinin maluke at gmail.com
Tue Jul 1 21:38:04 EDT 2008


I figured out a way to work around this. To make it work we need to
call Close only if we already decided that the frame should be closed.
So FrameComponent.close instead sets .closing to the
CancellableEvent() and schedules a check that will call wx.Frame.Close
if the event wasn't cancelled by the dependent rules. Also, the
EVT_CLOSE handler tests if current event originated from the check
mentioned above and if that's true it just calls evt.Skip() and
returns. Otherwise it vetoes the event and calls FrameComponent.close
instead which will give the chance to cancel the window closing.


On Wed, Jul 2, 2008 at 02:15, Sergey Schetinin <maluke at gmail.com> wrote:
> I was prototyping a library to use Trellis for various wx operations
> and came across an issue I don't know how to resolve.
>
> I tried to stick to Phillip's advice, so event handlers are
> implemented in such a way that they set some attribute (which has
> resetting_to=False) of a window component to an instance of some event
> class. So a rule to handle events can look like this:
>
>    @maintain
>    def on_close_click(self):
>        if self.button_close.clicked:
>            on_commit(self.close)
>
> It uses @maintain with on_commit instead of @perform because
> self.close calls wx.Frame.Close and that will in effect send a new
> event which will set more attributes and that is prohibited in
> @perform rules. Anyway, this isn't the issue. When the actual
> wx.Frame.Close is called that triggers another handler which sets
> .closing to an instance of CancellableEvent. That has a cancel method
> which simply sets .cancelled = True for that event. So, the event
> handler for EVT_CLOSE should decide before returning if the event
> should be propagated (and window closed) or if it should be stopped
> (evt.Skip() or evt.Veto()).  Now let's see how a rule that decides
> that could like like:
>
>    @maintain
>    def on_close(self):
>    if self.closing:
>        if not self.button_close.clicked:
>            self.closing.cancel()
>
> This makes sure the window only closes in response to button_close. So
> it should just work, right? In fact it doesn't, because the on_close
> rule runs too late.
>
> This call chain would work:
>
> got click event from wx
>    -> atomically
>        -> process click event (button_close.clicked = True)
>            -> on_close_click
>                -> on_commit(self.close)
>        -> frame.Close
>            -> process close event (.closing = CancellableEvent)
>                -> on_close
>                    -> closing.cancel()
>
> But the actual chain is different, the on_close is only called later,
> before the end of the pulse, at the "atomically" level which makes it
> too late to influence the propagation of CloseEvent. One way to work
> around this would be avoid nested event handler calls, so the .close
> would have not to immediately call wx.Frame.Close but use wx.CallAfter
> or otherwise schedule the call. But would break the on_close rule,
> because it wouldn't know the source of the event (button_close.clicked
> would revert back to False).
>
> Can anything be done for such cases? Is it even possible to make sure
> all dependent rules recalculate before EVT_CLOSE handler exits without
> violating some basic assumptions?
>
> If my explanation is incomprehensible, please let me know, I'll try to
> explain it some other way.
>
> --
> Best Regards,
> Sergey Schetinin
>
> http://s3bk.com/ -- S3 Backup
> http://word-to-html.com/ -- Word to HTML Converter
>



-- 
Best Regards,
Sergey Schetinin

http://s3bk.com/ -- S3 Backup
http://word-to-html.com/ -- Word to HTML Converter



More information about the PEAK mailing list