Re: How do I Block Events in wxPython

2009-12-10 Thread Stephen Hansen
On Wed, Dec 9, 2009 at 10:21 PM, Frank Millman fr...@chagford.com 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
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How do I Block Events in wxPython

2009-12-10 Thread Frank Millman
Stephen Hansen wrote:

 On Wed, Dec 9, 2009 at 10:21 PM, Frank Millman fr...@chagford.com 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



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


Re: How do I Block Events in wxPython

2009-12-10 Thread Stephen Hansen
On Thu, Dec 10, 2009 at 6:01 AM, Frank Millman fr...@chagford.com 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
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How do I Block Events in wxPython

2009-12-10 Thread Frank Millman
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



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


How do I Block Events in wxPython

2009-12-09 Thread Wanderer
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
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How do I Block Events in wxPython

2009-12-09 Thread Philip Semanchuk


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
--
http://mail.python.org/mailman/listinfo/python-list


Re: How do I Block Events in wxPython

2009-12-09 Thread zeph
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.)
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How do I Block Events in wxPython

2009-12-09 Thread r0g
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
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How do I Block Events in wxPython

2009-12-09 Thread Wanderer
On Dec 9, 11:48 am, r0g aioe@technicalbloke.com 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).

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


Re: How do I Block Events in wxPython

2009-12-09 Thread Jeff Peck

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
--
http://mail.python.org/mailman/listinfo/python-list


Re: How do I Block Events in wxPython

2009-12-09 Thread Stephen Hansen
On Wed, Dec 9, 2009 at 9:06 AM, Wanderer wande...@dialup4less.com 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
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How do I Block Events in wxPython

2009-12-09 Thread Dave Angel

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

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


Re: How do I Block Events in wxPython

2009-12-09 Thread Frank Millman
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
 



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