Mix-in to base events?

Can I mix-in my own functionality to the event objects that get
passed to the callback functions?

For example:

self.Bind(wx.EVT_BUTTON, self.onButton)

def onButton(self, event):
  # I'd like event to be the normally-passed wx event object
  # which has a class of mine mixed-in with it.

I've already got my own wx.PyCommandEvent and wx.PyEvent
subclasses with my mixed-in class, and this works for sending
my own custom events, but I also want the wx-generated events
to include my mixin class.

I thought of just catching the wx event and re-raising it as a
custom event, but that would fork the event and user code no
longer has control over whether the original wx event is
Skipped or not...

···

--
Paul McNett
Independent Software Consultant
http://www.paulmcnett.com

Paul McNett wrote:

I've already got my own wx.PyCommandEvent and wx.PyEvent subclasses with my mixed-in class, and this works for sending my own custom events, but I also want the wx-generated events to include my mixin class.

If I understand you correctly, I tried to do this, and I couldn't get it to work. What I wanted to do was raise events that were exactly like the build-in ones, but had one added attribute. If Events were pure python, this would have worked fine, but as wrappers around C++ objects, it just didn't work. I don't remember why exactly, but I did post some questions about it here, so you might find it in the archives.

I thought of just catching the wx event and re-raising it as a custom event,

That's exactly what I did. This is all in wx.lib.floatcanvas.FloatCanvas.py (in the latest release, anyway), if you want to take a look.

but that would fork the event and user code no longer has control over whether the original wx event is Skipped or not...

Well, you could skip() the regular event, and also raise your custom event, so the user can choose which one to catch.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer
                                         
NOAA/OR&R/HAZMAT (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

Chris Barker wrote:

I thought of just catching the wx event and re-raising it as a custom event,

That's exactly what I did. This is all in wx.lib.floatcanvas.FloatCanvas.py (in the latest release, anyway), if you want to take a look.

One other note: I used delegation (def __getattr__) so that all the ordinary event attributes are available.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer
                                         
NOAA/OR&R/HAZMAT (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

Chris Barker writes:

One other note: I used delegation (def __getattr__) so that
all the ordinary event attributes are available.

Thanks Chris,

Seeing that you are doing it this way makes me think I'm not
off-track as much as I thought. I tried the delegation thing
yesterday, but was getting strange results for key events.
Perhaps I should try it again using your code as a starting
point... there may have been other things at play.

···

--
Paul McNett
Independent Software Consultant
http://www.paulmcnett.com

I'm guessing that it isn't doable, but you'll have to wait for Robin to return to get an answer.

I can tell you from past experience that having your own virtual event queue and trying to keep the event behavior correct across all the platforms is a nightmare, which is why the old PythonCard event system was tossed out.

Depending on what you want in the event instances, you could go the PythonCard route and bind all events to a central dispatcher and then "decorate" the incoming wxPython events based on the event type. In PythonCard 0.8 this is pretty straightforward and doesn't involve much code for the binding and dispatch. I went ahead and made wrapper classes for every event so that I could group the wxPython event function and id. Here's a snippet of a KeyDownEvent class. These are not subclasses or mixins of the native wxPython events, they are simply helpers.

class Event :
     """
     Superclass of all event classes.
     """

     def decorate(self, aWxEvent, source):
         aWxEvent.target = aWxEvent.eventObject = source
         return aWxEvent

class KeyEvent(Event):
     def decorate(self, aWxEvent, source):
         aWxEvent = Event.decorate(self, aWxEvent, source)

         # this is basically the same block as MouseEvent.decorate
         # but it seems wrong to have KeyEvent be a subclass of MouseEvent
         aWxEvent.position = tuple(aWxEvent.GetPosition())
         aWxEvent.x = aWxEvent.GetX()
         aWxEvent.y = aWxEvent.GetY()
         aWxEvent.altDown = aWxEvent.AltDown()
         aWxEvent.controlDown = aWxEvent.ControlDown()
         aWxEvent.shiftDown = aWxEvent.ShiftDown()

         aWxEvent.keyCode = aWxEvent.GetKeyCode()
         return aWxEvent

class KeyDownEvent(KeyEvent):
     name = 'keyDown'
     binding = wx.EVT_KEY_DOWN
     id = wx.wxEVT_KEY_DOWN

In the dispatcher there is a reverse lookup from the id, which is all the native wxPython event provides, to the event class, so that I can "decorate" the native event before calling the real event handler or just calling skip if there is no event handler.

ka

···

On Aug 18, 2004, at 12:10 PM, Paul McNett wrote:

Can I mix-in my own functionality to the event objects that get
passed to the callback functions?

For example:

self.Bind(wx.EVT_BUTTON, self.onButton)

def onButton(self, event):
  # I'd like event to be the normally-passed wx event object
  # which has a class of mine mixed-in with it.

I've already got my own wx.PyCommandEvent and wx.PyEvent
subclasses with my mixed-in class, and this works for sending
my own custom events, but I also want the wx-generated events
to include my mixin class.

I thought of just catching the wx event and re-raising it as a
custom event, but that would fork the event and user code no
longer has control over whether the original wx event is
Skipped or not...

Paul McNett wrote:

Can I mix-in my own functionality to the event objects that get passed to the callback functions?

For example:

self.Bind(wx.EVT_BUTTON, self.onButton)

def onButton(self, event):
  # I'd like event to be the normally-passed wx event object
  # which has a class of mine mixed-in with it.

I've already got my own wx.PyCommandEvent and wx.PyEvent subclasses with my mixed-in class, and this works for sending my own custom events, but I also want the wx-generated events to include my mixin class.

Since the instance is created in C++ wx code there is no way to tell it to create an instance of your Python class instead.

···

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

Robin Dunn writes:

Since the instance is created in C++ wx code there is no way
to tell it to create an instance of your Python class
instead.

Okay, thanks. I've taken to catching the wx events and then
re-raising my own custom events for user code to bind to, which
is working but has caused some hard to track down lockups and
segfaults, mostly with FocusEvents, and mostly on Windows and
Linux.

For example, if I try to raise a custom event from within a
onSetFocus() event handler on Linux, my app will completely
lock up. Interestingly, it seems to work flawlessly on Mac.

(All platforms were tested with wxPython 2.5.2.7 Unicode).

One thing that I've gained by doing it this way is the ability
to conditionally log certain events. I now have a greater
understanding of the event firing order, and some bafflement as
well. For example, when I change to a different application on
Linux, my main frame will fire:

LostFocus (EVT_KILLFOCUS)
GotFocus (EVT_SETFOCUS)
LostFocus
Deactivate (EVT_ACTIVATE where False)

But, it may be a futile exercise because of the
seeming-randomness of crashes and lockups on Linux and Windows.
There must be some hanging object references behind the scenes
in certain situations that I probably don't have control over.
<sigh>

Is there something different (perhaps newer) going on with Mac
events that may explain the relative stability of my approach
on that platform?

(Yes, I'll endeavor to put this into a small sample that shows
the problems, but for now treat this as a general, somewhat
vague, discussion. <g>)

···

--
Paul McNett
Independent Software Consultant
http://www.paulmcnett.com

Paul McNett writes:

(Yes, I'll endeavor to put this into a small sample that
shows the problems, but for now treat this as a general,
somewhat vague, discussion. <g>)

Okay, I spent all morning trying to simplify my code, but in the
process of simplification it appears that my problems
disappeared. I'll have to spend more time on this, but in the
meantime if anyone is interested, here are my simplified
scripts:

http://paulmcnett.com/python/dabo/daboEventsProblemDemo/

Download both files and then:

python daboEventsProblemDemo.py

This shows my basic approach of catching wx events and raising
custom events. It still isn't as simple as it should be for a
demo, but as I said I haven't been able to reproduce any of my
problems...

···

--
Paul McNett
Independent Software Consultant
http://www.paulmcnett.com