FAQ
I have a wxPython program which does some calculations and displays
the results. During these calculations if I click the mouse inside the
dialog the program locks up. If I leave the dialog alone the process
completes fine. I have tried running the function from a separate
dialog with Show Modal and I have tried using SetEvtHandlerEnabled all
to no avail. The program is long and occupies several files so I won't
show the whole thing but here is the calculation part. How do I block
events?

def DoEfficiency(self):

from time import sleep

self.timer.Stop()



TotalPower = 0
Counter = 0
for ang in range(1,89):
self.tc_angle.SetValue(ang)
height = int(self.eclwidth * 10)
for hgt in range(0,height):
self.tc_height.SetValue(float(hgt)/10.0)
self.UpdateValues()
self.Redraw()
self.DrawRays()
sPower = self.tc_power.GetValue()
Power = sPower.split('%')
TotalPower +=float(Power[0])
Counter +=1
sleep(0.1)

efficiency = TotalPower/Counter
self.tc_eff.SetLabel(str(round(efficiency,1)))
self.timer.Start(10)


# end DoEfficiency

def OnEfficiency(self, event):

self.tc_aangle.SetEvtHandlerEnabled(False)
self.tc_angle.SetEvtHandlerEnabled(False)
self.tc_calc_len.SetEvtHandlerEnabled(False)
self.tc_cpclength.SetEvtHandlerEnabled(False)
self.tc_cpcwidth.SetEvtHandlerEnabled(False)
self.tc_det.SetEvtHandlerEnabled(False)
self.tc_ecl.SetEvtHandlerEnabled(False)
self.tc_eff.SetEvtHandlerEnabled(False)
self.tc_gap1.SetEvtHandlerEnabled(False)
self.tc_gap2.SetEvtHandlerEnabled(False)
self.tc_height.SetEvtHandlerEnabled(False)
self.tc_parab.SetEvtHandlerEnabled(False)
self.tc_power.SetEvtHandlerEnabled(False)
self.tc_refresh.SetEvtHandlerEnabled(False)
self.tc_tlength.SetEvtHandlerEnabled(False)
self.tc_twidth.SetEvtHandlerEnabled(False)
self.tc_use_tir.SetEvtHandlerEnabled(False)
self.SetEvtHandlerEnabled(False)

dlf = CalcEfficiency(self,"CalcEfficiency",wx.DefaultPosition,
(90,60))

self.tc_aangle.SetEvtHandlerEnabled(True)
self.tc_angle.SetEvtHandlerEnabled(True)
self.tc_calc_len.SetEvtHandlerEnabled(True)
self.tc_cpclength.SetEvtHandlerEnabled(True)
self.tc_cpcwidth.SetEvtHandlerEnabled(True)
self.tc_det.SetEvtHandlerEnabled(True)
self.tc_ecl.SetEvtHandlerEnabled(True)
self.tc_eff.SetEvtHandlerEnabled(True)
self.tc_gap1.SetEvtHandlerEnabled(True)
self.tc_gap2.SetEvtHandlerEnabled(True)
self.tc_height.SetEvtHandlerEnabled(True)
self.tc_parab.SetEvtHandlerEnabled(True)
self.tc_power.SetEvtHandlerEnabled(True)
self.tc_refresh.SetEvtHandlerEnabled(True)
self.tc_tlength.SetEvtHandlerEnabled(True)
self.tc_twidth.SetEvtHandlerEnabled(True)
self.tc_use_tir.SetEvtHandlerEnabled(True)
self.SetEvtHandlerEnabled(True)

# end MyInterface


class CalcEfficiency(wx.Dialog):
"""
"""
def __init__(self, parent, title, pos, size):

self.parent = parent


wx.Dialog.__init__(self,parent, -1, title, pos, size)

self.runButton = wx.ToggleButton(self, ID_TOGGLE, "Start",
wx.DefaultPosition, (70,30))
self.Bind(wx.EVT_TOGGLEBUTTON, self.OnToggle, id =
ID_TOGGLE)

self.ShowModal()

self.Destroy()

# end init

def OnToggle(self, event):

if self.runButton.GetValue():
self.runButton.SetLabel("WAIT")
self.SetEvtHandlerEnabled(False)
self.parent.DoEfficiency()
self.SetEvtHandlerEnabled(True)
else:
self.Close()


# end OnQuit

# end CalcEfficiency


if __name__ == '__main__':
app = MyApp(False)
app.MainLoop()

# end main

Search Discussions

  • Zeph at Dec 9, 2009 at 4:42 pm
    The wxPython wiki actually has a page on dealing with long running
    tasks called from event handlers called (surprise surprise):
    http://wiki.wxpython.org/LongRunningTasks

    Hint: the second to last example on that page has the clearest example
    - using a worker thread object to do your DoEfficiency() function.

    I also don't think you want to disable so many event handlers, do
    you? Nothing will respond to inputs as long as that process is
    running (assuming you aren't running it in another thread.)
  • Philip Semanchuk at Dec 9, 2009 at 4:43 pm

    On Dec 9, 2009, at 10:42 AM, Wanderer wrote:

    I have a wxPython program which does some calculations and displays
    the results. During these calculations if I click the mouse inside the
    dialog the program locks up. If I leave the dialog alone the process
    completes fine. I have tried running the function from a separate
    dialog with Show Modal and I have tried using SetEvtHandlerEnabled all
    to no avail. The program is long and occupies several files so I won't
    show the whole thing but here is the calculation part. How do I block
    events?

    Hi Wanderer,
    I don't have a solution for you but I have three suggestions.

    First, your program shouldn't be locking up just because you clicked
    on it. IMO that's the real problem, and discarding events is just a
    band-aid to cover it up. Nevertheless, sometimes a band-aid is an
    appropriate solution and you're the best judge of that.

    Second, the wxPython mailing list would be a better place for this
    question.

    Third, if you can't seem to resolve the problem, try paring it down to
    a minimal example that reproduces the problem. It's difficult to offer
    suggestions when we can't see the whole code or try the sample code
    ourselves.


    Good luck
    Philip
  • Jeff Peck at Dec 9, 2009 at 5:00 pm

    Philip Semanchuk wrote:
    On Dec 9, 2009, at 10:42 AM, Wanderer wrote:

    I have a wxPython program which does some calculations and displays
    the results. During these calculations if I click the mouse inside the
    dialog the program locks up. If I leave the dialog alone the process
    completes fine. I have tried running the function from a separate
    dialog with Show Modal and I have tried using SetEvtHandlerEnabled all
    to no avail. The program is long and occupies several files so I won't
    show the whole thing but here is the calculation part. How do I block
    events?

    Hi Wanderer,
    I don't have a solution for you but I have three suggestions.

    First, your program shouldn't be locking up just because you clicked
    on it. IMO that's the real problem, and discarding events is just a
    band-aid to cover it up. Nevertheless, sometimes a band-aid is an
    appropriate solution and you're the best judge of that.

    Second, the wxPython mailing list would be a better place for this
    question.

    Third, if you can't seem to resolve the problem, try paring it down to
    a minimal example that reproduces the problem. It's difficult to offer
    suggestions when we can't see the whole code or try the sample code
    ourselves.


    Good luck
    Philip
    Wanderer,
    I agree with Philip. You probably want your calculation code in a
    separate thread. I'd advise against this, but if you're just looking for
    a bandaid you could try creating an event handler to catch the mouse
    clicks and simply call event.Skip(). If you do this, you might have to
    introduce a flag that gets set to True only during your calculation, and
    then your event hander could look something like this:

    def OnMouseClick(self, event):
    # Only skip mouse click event if calculating
    if self.busy:
    event.Skip()


    Jeff
  • R0g at Dec 9, 2009 at 4:48 pm

    Wanderer wrote:
    I have a wxPython program which does some calculations and displays
    the results. During these calculations if I click the mouse inside the
    dialog the program locks up. If I leave the dialog alone the process
    completes fine.
    If anything in your GUI app takes a non trivial length of time to
    execute you need to run it in either a thread or a separate process.

    http://linuxgazette.net/107/pai.html

    Roger
  • Wanderer at Dec 9, 2009 at 5:06 pm

    On Dec 9, 11:48?am, r0g wrote:
    Wanderer wrote:
    I have a wxPython program which does some calculations and displays
    the results. During these calculations if I click the mouse inside the
    dialog the program locks up. If I leave the dialog alone the process
    completes fine.
    If anything in your GUI app takes a non trivial length of time to
    execute you need to run it in either a thread or a separate process.

    http://linuxgazette.net/107/pai.html

    Roger
    Thanks Everyone. I'll have to look over these wikis about threading. I
    decided to go another route and user a timer to perform the loops.
    That way the events can be processed normally.

    def DoEfficiency(self, event):


    ang = self.tc_angle.GetValue()
    hgt = self.tc_height.GetValue()
    hgt += 0.1
    if hgt > self.eclwidth:
    hgt = 0
    ang +=1
    self.tc_angle.SetValue(ang)
    self.height = hgt
    self.tc_height.SetValue(hgt)
    self.tc_height.SetValue(hgt)
    self.UpdateValues()
    self.Redraw()
    self.DrawRays()
    sPower = self.tc_power.GetValue()
    Power = sPower.split('%')
    self.TotalPower +=float(Power[0])
    self.Counter +=1
    efficiency = self.TotalPower/self.Counter
    self.tc_eff.SetLabel(str(round(efficiency,1)))
    if ang > 89:
    self.efftimer.Stop()
    self.timer.Start(10)



    # end DoEfficiency

    def OnEfficiency(self, event):

    self.TotalPower = 0
    self.Counter = 0
    self.tc_angle.SetValue(1)
    self.tc_height.SetValue(0)
    self.timer.Stop()
    self.efftimer.Start(100)


    # end MyInterface

    Found another strange bug (Strange to me, anyway). int(0.8 * 10.0) =
    7. Had to change the code to int(0.8 * 10.0 + 0.0001).
  • Stephen Hansen at Dec 9, 2009 at 5:40 pm

    On Wed, Dec 9, 2009 at 9:06 AM, Wanderer wrote:

    Found another strange bug (Strange to me, anyway). int(0.8 * 10.0) =
    7. Had to change the code to int(0.8 * 10.0 + 0.0001).
    http://effbot.org/pyfaq/why-are-floating-point-calculations-so-inaccurate.htm

    Floating point math is not precise; if you need precision, use the decimal
    module. Alternately, you can just be sure to round() your floats to whatever
    precision you need to consider significant after calculations.

    --S
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: <http://mail.python.org/pipermail/python-list/attachments/20091209/77ec35da/attachment.htm>
  • Dave Angel at Dec 9, 2009 at 10:10 pm

    Wanderer wrote:
    <snip>

    Found another strange bug (Strange to me, anyway). int(0.8 * 10.0) 7. Had to change the code to int(0.8 * 10.0 + 0.0001).

    Floating point is intrinsically imprecise. The value 0.8 cannot be
    exactly represented in IEEE fp notation (binary). One answer is to
    round() the result before converting to int.


    DaveaA
  • Frank Millman at Dec 10, 2009 at 6:21 am

    Wanderer wrote:
    I have a wxPython program which does some calculations and displays
    the results. During these calculations if I click the mouse inside the
    dialog the program locks up. If I leave the dialog alone the process
    completes fine. I have tried running the function from a separate
    dialog with Show Modal and I have tried using SetEvtHandlerEnabled all
    to no avail. The program is long and occupies several files so I won't
    show the whole thing but here is the calculation part. How do I block
    events?
    I also need to block events in my wxPython app, though the time duration is
    very short. I have a separate thread that sends notification of gui events
    to a server, and waits for a response. I do not want the user to do anything
    until the response is received.

    I use threading.Event() for this -
    import threading
    event_waiting = threading.Event()
    event_waiting.set() # set event to True

    In the gui thread, when I want to block, I have this -
    event_waiting.clear() # set event to False
    event_waiting.wait() # block until event becomes True

    In the worker thread, when the response has been received and acted upon, I
    have -
    event_waiting.set() # set event to True, which unblocks the gui thread

    HTH

    Frank Millman
  • Stephen Hansen at Dec 10, 2009 at 7:57 am

    On Wed, Dec 9, 2009 at 10:21 PM, Frank Millman wrote:

    Wanderer wrote:
    I have a wxPython program which does some calculations and displays
    the results. During these calculations if I click the mouse inside the
    dialog the program locks up. If I leave the dialog alone the process
    completes fine. I have tried running the function from a separate
    dialog with Show Modal and I have tried using SetEvtHandlerEnabled all
    to no avail. The program is long and occupies several files so I won't
    show the whole thing but here is the calculation part. How do I block
    events?
    I also need to block events in my wxPython app, though the time duration is
    very short. I have a separate thread that sends notification of gui events
    to a server, and waits for a response. I do not want the user to do
    anything
    until the response is received.
    I don't think "blocking" events is the right way to think about this.

    If you need to halt new input for some reason (bearing in mind that its best
    to run such things in a background task, but yes, sometimes blocking the UI
    is important), then there's a couple ways to go about it. But trying to mess
    with the event loop isn't it.

    First, you always want a visual indicator-- use SetCursor on your top level
    window to set a busy cursor. You never want any sort of block-ish action to
    happen without the user being able to see "something is going on"; if its
    more then a second or so I /really/ think you should throw up a progress
    indicator dialog, even if its an infinate one.

    To actually 'block' the events themselves, you can just call
    wnd.Enable(False). Just be sure to Enable(True) when you want to process
    stuff again.

    Another approach is to use wnd.CaptureMouse() on a particular control which
    doesn't really respond to anything. Just be sure to ReleaseMouse() later and
    follow the instructions in the docs about capturing that cancel-capture
    event.

    HTH,
    --S
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: <http://mail.python.org/pipermail/python-list/attachments/20091209/e9df92f3/attachment-0001.htm>
  • Frank Millman at Dec 10, 2009 at 2:01 pm

    Stephen Hansen wrote:
    On Wed, Dec 9, 2009 at 10:21 PM, Frank Millman wrote:

    I also need to block events in my wxPython app, though the time duration
    is
    very short. I have a separate thread that sends notification of gui
    events
    to a server, and waits for a response. I do not want the user to do
    anything until the response is received.
    I don't think "blocking" events is the right way to think about this.

    If you need to halt new input for some reason (bearing in mind that its
    best
    to run such things in a background task, but yes, sometimes blocking the
    UI
    is important), then there's a couple ways to go about it. But trying to
    mess
    with the event loop isn't it.
    In fact my method does not work. All that happens is that the events are
    queued, and as soon as I release the lock the events are processed in a
    bunch. Not clever :-(
    First, you always want a visual indicator-- use SetCursor on your top
    level
    window to set a busy cursor. You never want any sort of block-ish action
    to
    happen without the user being able to see "something is going on"; if its
    more then a second or so I /really/ think you should throw up a progress
    indicator dialog, even if its an infinate one. Agreed.
    To actually 'block' the events themselves, you can just call
    wnd.Enable(False). Just be sure to Enable(True) when you want to process
    stuff again.
    This may work for the OP, but would not really work for me, because it
    changes the visual appearance of all the controls. In my case the time
    duration for blocking is usually very short, so it could result in flicker.
    Another approach is to use wnd.CaptureMouse() on a particular control
    which
    doesn't really respond to anything. Just be sure to ReleaseMouse() later
    and
    follow the instructions in the docs about capturing that cancel-capture
    event.
    I like this. Unfortunately it does not block keyboard input. However, I have
    a keyboard event handler on virtually all my controls, so it should be easy
    to set a flag and tell it to ignore keystrokes while in a 'blocked' state.
    HTH,
    It certainly does - thanks.

    Frank
  • Stephen Hansen at Dec 10, 2009 at 4:16 pm

    On Thu, Dec 10, 2009 at 6:01 AM, Frank Millman wrote:

    Another approach is to use wnd.CaptureMouse() on a particular control
    which
    doesn't really respond to anything. Just be sure to ReleaseMouse() later
    and
    follow the instructions in the docs about capturing that cancel-capture
    event.
    I like this. Unfortunately it does not block keyboard input. However, I
    have
    a keyboard event handler on virtually all my controls, so it should be easy
    to set a flag and tell it to ignore keystrokes while in a 'blocked' state.
    Hm, that's a point.

    Well if you have a legitimate case for pre-empting the event loop with these
    periodic regular short blocking moments (it seems you may), I think what you
    want to do is overwrite FilterEvent on your App object. You can then make
    that flag something you set on the app, and while it's true, returning False
    (or True, I really don't know the differenced between telling wx 'Ok, I
    processed this event you can ignore it' and 'Ok, I'm not going to process
    this event and neither should you'). Otherwise, return -1.

    --S

    HTH,
    It certainly does - thanks.

    Frank



    --
    http://mail.python.org/mailman/listinfo/python-list

    --S
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: <http://mail.python.org/pipermail/python-list/attachments/20091210/267589a8/attachment.htm>
  • Frank Millman at Dec 11, 2009 at 7:00 am

    Stephen Hansen wrote:
    Well if you have a legitimate case for pre-empting the event loop with
    these
    periodic regular short blocking moments (it seems you may), I think what
    you
    want to do is overwrite FilterEvent on your App object. You can then make
    that flag something you set on the app, and while it's true, returning
    False
    (or True, I really don't know the differenced between telling wx 'Ok, I
    processed this event you can ignore it' and 'Ok, I'm not going to process
    this event and neither should you'). Otherwise, return -1.
    This works beautifully - thanks, Stephen.

    As you say, the difference between returning True or False is not clear, but
    in practice I found that I had to return True - then all mouse and keyboard
    activity is blocked.

    There is another step required, which I did not find in the docs, but found
    in help(wx.App.FilterEvent). If you override FilterEvent, you also have to
    call SetCallFilterEvent(True) on the App object when you want it to be
    called, and set it back to False when finished. This is handy, as it avoids
    the overhead of calling it when you don't need it.

    In fact, as I am writing this, I realise that I don't need a flag at all. I
    just override FilterEvent, and return True. Then when I want to block, I
    call SetCallFilterEvent(True), and when I want to stop, I call
    SetCallFilterEvent(False).

    This is very useful. Thanks again.

    Frank

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouppython-list @
categoriespython
postedDec 9, '09 at 3:42p
activeDec 11, '09 at 7:00a
posts13
users8
websitepython.org

People

Translate

site design / logo © 2023 Grokbase