How to pause an event until another event happens

56 views
Skip to first unread message

Ryan Holmes

unread,
Apr 15, 2017, 12:13:45 AM4/15/17
to wxPython-users
Hi there,

I have an event that is scattered throughout my program. Whenever we make a change that is committed to the database, we fire off a ModelChanged event that includes various information, which is then picked up by a variety of GUI elements to update the screen. However, I'm doing a bit of refactoring on how this is working. Instead of the GUI elements capturing the event as soon as it's fired, I wish to pause it until another event happens. So, instead of doing this:

Fire Event -> Bindings receive event

I want it to do this:

Fire Event -> Wait for another separate event to fire -> Bindings receive original event.

Here is some code:

import wxversion
wxversion
.select(['3.0', '2.8'])
import wx
import wx.lib.newevent

OriginalEvent, ORIGINAL_EVT = wx.lib.newevent.NewEvent()
ReleaseEvent, RELEASE_EVT = wx.lib.newevent.NewEvent()

class MyFrame(wx.Frame):
   
def __init__(self, parent, title):
        wx
.Frame.__init__(self, parent, title=title, size=(200,100))

       
self.sizer = wx.BoxSizer(wx.VERTICAL)
       
self.fireOriginalBtn = wx.Button(self, wx.ID_ANY, "Fire Event")
       
self.fireOriginalBtn.Bind(wx.EVT_BUTTON, self.fireOriginal)

       
self.releaseEventBtn = wx.Button(self, wx.ID_ANY, "Release Event")
       
self.releaseEventBtn.Bind(wx.EVT_BUTTON, self.releaseEvent)

       
self.sizer.Add(self.fireOriginalBtn, 1, wx.EXPAND)
       
self.sizer.Add(self.releaseEventBtn, 1, wx.EXPAND)

       
self.SetSizer(self.sizer)
       
self.SetAutoLayout(1)
       
self.sizer.Fit(self)

       
self.Bind(ORIGINAL_EVT, self.captureOriginal)
       
self.Bind(RELEASE_EVT, self.captureRelease)
       
self.Show(True)

   
def fireOriginal(self, evt):
        wx
.PostEvent(self, OriginalEvent(myInfo=[1,2,3,4]))

   
def releaseEvent(self, evt):
        wx
.PostEvent(self, ReleaseEvent())

   
def captureOriginal(self, evt):
       
print "Event captured"

    def captureRelease(self, evt):
       
print "Release captured"

app = wx.App(False)
frame
= MyFrame(None, 'Small editor')
app
.MainLoop()

Currently, when you click Fire Event, you'll get text printed to the console. I want to be able to click the "Fire Event" button, but wait until I click the "Release Event" button before my frame gets the original event and prints to console.

I don't know enough about how to write my own event classes - maybe there's some things I can override to tell it when to emit the event or not, and a cursory look didn't get anywhere. Thought I'd ask you guys if it's possible and, if so, how? :)

Thanks!

PS: Preferably this would work in 2.8 and 3.0.







Steve Barnes

unread,
Apr 15, 2017, 1:25:22 AM4/15/17
to wxpytho...@googlegroups.com
Ryan,

The main missing trick is a queue, when your usual events happen trigger
an event that results in a handler that simply adds that event, or just
the important parts of it, to a queue. When your display update event
happens process the events in that queue. (Standard python queues should
work nicely for this).

You might also find it worth reading up a little on the "pubsub model"
where most of your events would publish their data and one, or more,
subscribers would deal with them.
--
Steve (Gadget) Barnes
Any opinions in this message are my personal opinions and do not reflect
those of my employer.

Ryan Holmes

unread,
Apr 15, 2017, 5:17:07 PM4/15/17
to wxPython-users
This sounds like it would take a large refactoring of the code, and would require changes to each place that binds to that event. I was hoping to avoid a large refactor (the project is fairly large) and instead utilize the existing PostEvents and Binds, but add this additional requirement of having another event actually release the events to those areas that bind to it. Perhaps I'm not fully understanding your suggestion though. I'll read up a bit more on event handling and pubsub, but would like to hear about any other possible solutions that may be available. :)

Steve Barnes

unread,
Apr 16, 2017, 3:03:05 AM4/16/17
to wxpytho...@googlegroups.com


On 15/04/2017 22:17, Ryan Holmes wrote:
> This sounds like it would take a large refactoring of the code, and
> would require changes to each place that binds to that event. I was
> hoping to avoid a large refactor (the project is fairly large) and
> instead utilize the existing PostEvents and Binds, but add this
> additional requirement of having another event actually release the
> events to those areas that bind to it. Perhaps I'm not fully
> understanding your suggestion though. I'll read up a bit more on event
> handling and pubsub, but would like to hear about any other possible
> solutions that may be available. :)
>
Rather than trying to modify the underlying framework behaviour, by
getting it to postpone event processing it is much easier to bind all of
the existing events to a handler that queues the request, with the
control ID and possibly the event type and then have a single handler
for the get on with it event that could use a look up of the original
event handlers for the controls & events and call them as the queued
events pop off of the queue. You could even move the body of each
current event handler to a new function and replace the content with a
call to an add_to_queue with the new function in it then your binds
would not change.
Reply all
Reply to author
Forward
0 new messages