[wxPython-users] Forcing a Refresh

1,261 views
Skip to first unread message

cool-RR

unread,
Apr 20, 2010, 10:34:46 AM4/20/10
to wxPython-users
Hello,

I have a question:

Is it possible in wxPython to programmatically cause a widget to be
redrawn? (i.e. its EVT_PAINT handler to be called.) I am expecting
that this will work on Mac/Linux/Windows, regardless of whether the
operating system thinks the widget should be just fine without getting
redrawn.

Ram.

--
To unsubscribe, send email to wxPython-user...@googlegroups.com
or visit http://groups.google.com/group/wxPython-users?hl=en

werner

unread,
Apr 20, 2010, 11:37:31 AM4/20/10
to wxpytho...@googlegroups.com
Hi Ram,

On 20/04/2010 16:34, cool-RR wrote:
> Hello,
>
> I have a question:
>
> Is it possible in wxPython to programmatically cause a widget to be
> redrawn? (i.e. its EVT_PAINT handler to be called.) I am expecting
> that this will work on Mac/Linux/Windows, regardless of whether the
> operating system thinks the widget should be just fine without getting
> redrawn.
>

self.Refresh()
self.Update()

As suggested by Andrea should do it, but check the wx doc there is a
note regarding GTK1 - I guess you are still fighting an issue on Linux/GTK.

Maybe add a call to self.Layout() first.

Werner

cool-RR

unread,
Apr 20, 2010, 11:54:27 AM4/20/10
to wxPython-users, Werner F. Bruhin
On Tue, Apr 20, 2010 at 5:37 PM, werner <wbr...@free.fr> wrote:
Hi Ram,

On 20/04/2010 16:34, cool-RR wrote:
Hello,

I have a question:

Is it possible in wxPython to programmatically cause a widget to be
redrawn? (i.e. its EVT_PAINT handler to be called.) I am expecting
that this will work on Mac/Linux/Windows, regardless of whether the
operating system thinks the widget should be just fine without getting
redrawn.
 

self.Refresh()
self.Update()

As suggested by Andrea should do it, but check the wx doc there is a note regarding GTK1 - I guess you are still fighting an issue on Linux/GTK.

As I said on the other thread, it didn't work on GTK.

Can you please point to the documentation note you're speaking about? I don't know where to find it.
  
Maybe add a call to self.Layout() first.

Like, every time I want to do refresh or just in the `__init__`? 

Ram.

Andrea Gavana

unread,
Apr 20, 2010, 11:59:36 AM4/20/10
to wxpytho...@googlegroups.com
Hi,

On 20 April 2010 16:54, cool-RR wrote:
>
>
> On Tue, Apr 20, 2010 at 5:37 PM, werner <wbr...@free.fr> wrote:
>>
>> Hi Ram,
>>
>> On 20/04/2010 16:34, cool-RR wrote:
>>>
>>> Hello,
>>>
>>> I have a question:
>>>
>>> Is it possible in wxPython to programmatically cause a widget to be
>>> redrawn? (i.e. its EVT_PAINT handler to be called.) I am expecting
>>> that this will work on Mac/Linux/Windows, regardless of whether the
>>> operating system thinks the widget should be just fine without getting
>>> redrawn.
>>>
>>
>> self.Refresh()
>> self.Update()
>>
>> As suggested by Andrea should do it, but check the wx doc there is a note
>> regarding GTK1 - I guess you are still fighting an issue on Linux/GTK.
>
> As I said on the other thread, it didn't work on GTK.
> Can you please point to the documentation note you're speaking about? I
> don't know where to find it.

http://docs.wxwidgets.org/stable/wx_wxwindow.html#wxwindowrefresh
http://docs.wxwidgets.org/stable/wx_wxwindow.html#wxwindowupdate
http://docs.wxwidgets.org/trunk/classwx_window.html#29dc7251746154c821b17841b9877830
http://docs.wxwidgets.org/trunk/classwx_window.html#baf28f1a075fd1b10f761a8febe597ec
DRIVE:/Path_to_wxPython_Demo/wx.chm => wxWindow

>>
>> Maybe add a call to self.Layout() first.
>
> Like, every time I want to do refresh or just in the `__init__`?

Yes, but it shouldn't be necessary in general, unless you bump on the
GTK1 issue (which shouldn't happen anymore I believe, GTK1 is dead as
far as I understand).

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.alice.it/infinity77/

==> Never *EVER* use RemovalGroup for your house removal. You'll
regret it forever.
http://thedoomedcity.blogspot.com/2010/03/removal-group-nightmare.html <==

Christopher Barker

unread,
Apr 20, 2010, 12:46:37 PM4/20/10
to wxpytho...@googlegroups.com
cool-RR wrote:
> Is it possible in wxPython to programmatically cause a widget to be
> redrawn? (i.e. its EVT_PAINT handler to be called.) I am expecting
> that this will work on Mac/Linux/Windows, regardless of whether the
> operating system thinks the widget should be just fine without getting
> redrawn.

self.Refresh()
self.Update()

should work -- if not, something else may be going on -- can you isolate
an example?

http://wiki.wxpython.org/MakingSampleApps

You might also be able to force a size event or call Layout() to get
around your issue.

-Chris





--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris....@noaa.gov

cool-RR

unread,
Apr 20, 2010, 3:50:35 PM4/20/10
to werner, wxPython-users
On Tue, Apr 20, 2010 at 8:22 PM, werner <wbr...@free.fr> wrote:
On 20/04/2010 17:54, cool-RR wrote:
On Tue, Apr 20, 2010 at 5:37 PM, werner <wbr...@free.fr> wrote:
Hi Ram,

On 20/04/2010 16:34, cool-RR wrote:
Hello,

I have a question:

Is it possible in wxPython to programmatically cause a widget to be
redrawn? (i.e. its EVT_PAINT handler to be called.) I am expecting
that this will work on Mac/Linux/Windows, regardless of whether the
operating system thinks the widget should be just fine without getting
redrawn.
 

self.Refresh()
self.Update()

As suggested by Andrea should do it, but check the wx doc there is a note regarding GTK1 - I guess you are still fighting an issue on Linux/GTK.

As I said on the other thread, it didn't work on GTK.

Can you please point to the documentation note you're speaking about? I don't know where to find it.
wxWindow::Refresh
virtual void Refresh(bool eraseBackground = true, const wxRect* rect = NULL)
Causes this window, and all of its children recursively (except under wxGTK1 where this is not implemented), to be repainted. Note that repainting doesn't happen immediately but only during the next event loop iteration, if you need to update the window immediately you should use Update instead.

Werner

Thanks, though GTK1 is a red herring, since the problem happens on a modern Ubuntu.

I will try to replicate the problem in a sample app and send it.

Ram.

Robin Dunn

unread,
Apr 20, 2010, 3:33:27 PM4/20/10
to wxpytho...@googlegroups.com
On 4/20/10 8:54 AM, cool-RR wrote:
>
>
> On Tue, Apr 20, 2010 at 5:37 PM, werner <wbr...@free.fr
> <mailto:wbr...@free.fr>> wrote:
>
> Hi Ram,
>
> On 20/04/2010 16:34, cool-RR wrote:
>
> Hello,
>
> I have a question:
>
> Is it possible in wxPython to programmatically cause a widget to be
> redrawn? (i.e. its EVT_PAINT handler to be called.) I am expecting
> that this will work on Mac/Linux/Windows, regardless of whether the
> operating system thinks the widget should be just fine without
> getting
> redrawn.
>
>
> self.Refresh()
> self.Update()
>
> As suggested by Andrea should do it, but check the wx doc there is a
> note regarding GTK1 - I guess you are still fighting an issue on
> Linux/GTK.
>
>
> As I said on the other thread, it didn't work on GTK.

What kind of window is self? Please make a sample that shows this problem.


--
Robin Dunn
Software Craftsman
http://wxPython.org

cool-RR

unread,
Apr 20, 2010, 6:04:23 PM4/20/10
to wxPython-users, robin
Here's a sample:

'''
import wx

class Panel(wx.Panel):
    def __init__(self, frame):
        wx.Panel.__init__(self, frame, size=(300, 300))

        self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
        
        self.Bind(wx.EVT_PAINT, self.on_paint)        
self.Bind(wx.EVT_IDLE, self.on_idle)                

        self.text_ctrl = wx.TextCtrl(
            self,
            style=wx.TE_MULTILINE | wx.NO_BORDER
        )
        font = wx.Font(9, wx.DEFAULT, wx.NORMAL, wx.BOLD, False,
                       u'Courier New')
        self.text_ctrl.SetFont(font)
        
        self.sizer_v = wx.BoxSizer(wx.VERTICAL)
        self.sizer_h = wx.BoxSizer(wx.HORIZONTAL)
        self.sizer_v.Add(self.sizer_h, 1, wx.EXPAND)
        self.sizer_h.Add(self.text_ctrl, 1, wx.EXPAND)
        
        self.SetSizer(self.sizer_v)
        self.sizer_v.Layout()
        

    def on_paint(self, event):
        event.Skip()
        print('on_paint called.')
         
    def on_idle(self, event):
        event.Skip()
        self.Refresh()
        self.Update()
        print('on_idle called.')
    

class Frame(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent)
        
        self.panel = Panel(self)

        self.Layout()
        self.Show(True)


app = wx.PySimpleApp()
Frame(None)
app.MainLoop()
'''

The idle handler is trying to `Refresh` the window, but on Ubuntu we can see that `on_paint` is no getting called. (Because when it does it prints 'on_paint called.'). On Ubuntu we just see a long line of 'on_idle called', while on Windows it's a mix of that and 'on_paint called'.

Ram.

Andrea Gavana

unread,
Apr 20, 2010, 6:11:10 PM4/20/10
to wxpytho...@googlegroups.com
Hi,
( I thought twice before posting this time :-D ).

On Windows at least, if you bind a paint event, you *must* create a
wx.PaintDC inside the on_paint handler. Once I do that, I get the
correct result.

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.alice.it/infinity77/

==> Never *EVER* use RemovalGroup for your house removal. You'll
regret it forever.
http://thedoomedcity.blogspot.com/2010/03/removal-group-nightmare.html <==

Robin Dunn

unread,
Apr 20, 2010, 6:23:15 PM4/20/10
to wxPython-users
On 4/20/10 3:04 PM, cool-RR wrote:

> The idle handler is trying to `Refresh` the window, but on Ubuntu we can
> see that `on_paint` is no getting called. (Because when it does it
> prints 'on_paint called.'). On Ubuntu we just see a long line of
> 'on_idle called', while on Windows it's a mix of that and 'on_paint called'.

Because the textctrl fully covers the panel, so there is nothing to
paint. If you make some part of the panel be visible (like in the
attachment) then you'll get the events. Personally I don't think that
Windows should be sending the pain events in this case either.

--
Robin Dunn
Software Craftsman
http://wxPython.org

paint.py

Robin Dunn

unread,
Apr 20, 2010, 6:26:11 PM4/20/10
to wxpytho...@googlegroups.com
On 4/20/10 3:11 PM, Andrea Gavana wrote:

> ( I thought twice before posting this time :-D ).

No worries, this time I forgot about something and you remembered it.


--
Robin Dunn
Software Craftsman
http://wxPython.org

cool-RR

unread,
Apr 20, 2010, 6:26:13 PM4/20/10
to wxpython-users, Andrea Gavana
I think your answer is wrong, I tried putting a `dc = wx.PaintDC(self); dc.Destroy()` in the paint handler and it didn't change the behavior on Ubuntu.

Ram.

cool-RR

unread,
Apr 20, 2010, 6:47:26 PM4/20/10
to wxpython-users, robin
On Wed, Apr 21, 2010 at 12:23 AM, Robin Dunn <ro...@alldunn.com> wrote:
On 4/20/10 3:04 PM, cool-RR wrote:

The idle handler is trying to `Refresh` the window, but on Ubuntu we can
see that `on_paint` is no getting called. (Because when it does it
prints 'on_paint called.'). On Ubuntu we just see a long line of
'on_idle called', while on Windows it's a mix of that and 'on_paint called'.

Because the textctrl fully covers the panel, so there is nothing to paint.  If you make some part of the panel be visible (like in the attachment) then you'll get the events.  Personally I don't think that Windows should be sending the pain events in this case either.
 
Robin Dunn

I see, so it seems that the answer to my original question:

Is it possible in wxPython to programmatically cause a widget to be redrawn? (i.e. its EVT_PAINT handler to be called.) I am expecting that this will work on Mac/Linux/Windows, regardless of whether the operating system thinks the widget should be just fine without getting redrawn.

 is "No." I think we would have saved time if you gave me the "no" when you saw my question...

Please explain something: If I bind my Panel's `EVT_PAINT` to my own handler, and then in my own handler call `event.Skip()`, how come the paint handler of `wx.Panel` takes control? I thought only one handler could be assigned to each event. So after I bound my own handler, how come the original handler still works without me calling it explicitly?

Also, if I am subclassing some widget class which has a paint handler, and I override the paint handler, and in the new one I want to do some unrelated actions and then use the original paint handler, do I just call it, like `BaseWidget.on_paint(self, event)`?

Feeling very confused... Good night.

Ram.

Kevin Ollivier

unread,
Apr 20, 2010, 7:35:45 PM4/20/10
to wxpytho...@googlegroups.com, robin
Hi Ram,

On Apr 20, 2010, at 3:47 PM, cool-RR wrote:

On Wed, Apr 21, 2010 at 12:23 AM, Robin Dunn <ro...@alldunn.com> wrote:
On 4/20/10 3:04 PM, cool-RR wrote:

The idle handler is trying to `Refresh` the window, but on Ubuntu we can
see that `on_paint` is no getting called. (Because when it does it
prints 'on_paint called.'). On Ubuntu we just see a long line of
'on_idle called', while on Windows it's a mix of that and 'on_paint called'.

Because the textctrl fully covers the panel, so there is nothing to paint.  If you make some part of the panel be visible (like in the attachment) then you'll get the events.  Personally I don't think that Windows should be sending the pain events in this case either.
 
Robin Dunn

I see, so it seems that the answer to my original question:

Is it possible in wxPython to programmatically cause a widget to be redrawn? (i.e. its EVT_PAINT handler to be called.) I am expecting that this will work on Mac/Linux/Windows, regardless of whether the operating system thinks the widget should be just fine without getting redrawn.

 is "No." I think we would have saved time if you gave me the "no" when you saw my question...

The answer to the question you actually asked is not "No", the answer to that question is to call Refresh() and Update(). However, what you wanted to know, and what you asked, were two different things. I don't think anyone could have read your mind to know that you wanted to fire a paint event on a control that was completely behind another control (and BTW, that's a very unusual request, you may in fact be one of the first to try it). You didn't provide that information, and until now, you never provided code so that we could see for ourselves what you were doing. This is why people were asking you for sample code.

Please explain something: If I bind my Panel's `EVT_PAINT` to my own handler, and then in my own handler call `event.Skip()`, how come the paint handler of `wx.Panel` takes control? I thought only one handler could be assigned to each event. So after I bound my own handler, how come the original handler still works without me calling it explicitly?

You're incorrect that only one handler can be assigned to each event.

Also, if I am subclassing some widget class which has a paint handler, and I override the paint handler, and in the new one I want to do some unrelated actions and then use the original paint handler, do I just call it, like `BaseWidget.on_paint(self, event)`?

No, you call event.Skip().... I strongly recommend you consider getting wxPython in Action if you haven't already and reading through that (particularly section 3.4.1). From your questions, I get the impression that you're missing something fundamental about how event handling works in wxPython, and coding wxPython apps is going to be hard if you're working under mistaken assumptions about fundamentals like event propagation. 

Moreover, you handle EVT_PAINT when you want to paint a control. That's the only time you want to handle it. If you want to do unrelated things, you do them somewhere else, because if one of your unrelated things happens to indirectly triggers a paint event in your paint handler, you'll end up in an endless loop. Also, painting is an expensive operation, so you should only do it when needed. Calling self.Update() when a control does not need to be redrawn, when it does do what you'd expect (i.e. when it's visible), wastes a lot of CPU cycles.

I don't know what you're trying to do, but the more I read about your questions and the discussion as a whole, the more I get the distinct impression that you're trying to use EVT_PAINT for no other reason other than because it is an event that gets fired on the control frequently. If that's a correct assumption, I suspect you want to use something more like a wx.Timer.

Regards,

Kevin

Feeling very confused... Good night.

Ram.

--
To unsubscribe, send email to wxPython-user...@googlegroups.com
or visit http://groups.google.com/group/wxPython-users?hl=en

cool-RR

unread,
Apr 21, 2010, 9:14:46 AM4/21/10
to wxPython-users, kevin-lists
On Wed, Apr 21, 2010 at 1:35 AM, Kevin Ollivier <kevin...@theolliviers.com> wrote:
Hi Ram,

The answer to the question you actually asked is not "No", the answer to that question is to call Refresh() and Update(). However, what you wanted to know, and what you asked, were two different things. I don't think anyone could have read your mind to know that you wanted to fire a paint event on a control that was completely behind another control (and BTW, that's a very unusual request, you may in fact be one of the first to try it). You didn't provide that information, and until now, you never provided code so that we could see for ourselves what you were doing. This is why people were asking you for sample code. 

Please explain something: If I bind my Panel's `EVT_PAINT` to my own handler, and then in my own handler call `event.Skip()`, how come the paint handler of `wx.Panel` takes control? I thought only one handler could be assigned to each event. So after I bound my own handler, how come the original handler still works without me calling it explicitly?

You're incorrect that only one handler can be assigned to each event.

Also, if I am subclassing some widget class which has a paint handler, and I override the paint handler, and in the new one I want to do some unrelated actions and then use the original paint handler, do I just call it, like `BaseWidget.on_paint(self, event)`?

No, you call event.Skip().... I strongly recommend you consider getting wxPython in Action if you haven't already and reading through that (particularly section 3.4.1). From your questions, I get the impression that you're missing something fundamental about how event handling works in wxPython, and coding wxPython apps is going to be hard if you're working under mistaken assumptions about fundamentals like event propagation. 

Thanks for following up on my quest.

I've read 3.4.1 now. I see this is the part I've been missing:

'''
If a binder isn’t found for the object itself [or the handler does `Skip()`], the processing walks up the class hierarchy to find a binder defined in a superclass of the object—this is different than the walk up in the container hierarchy that happens in the next step.
'''

Now I understand. Though in my opinion this is an abuse of Python's class/object system. Usually in Python when you override a method, it is *your* responsibility to call the original method (if you want it), and it does not get called magically for you as in wxPython.

But if it's the wxPython way then that's what I'll have to do.

 
Moreover, you handle EVT_PAINT when you want to paint a control. That's the only time you want to handle it. If you want to do unrelated things, you do them somewhere else, because if one of your unrelated things happens to indirectly triggers a paint event in your paint handler, you'll end up in an endless loop. Also, painting is an expensive operation, so you should only do it when needed. Calling self.Update() when a control does not need to be redrawn, when it does do what you'd expect (i.e. when it's visible), wastes a lot of CPU cycles.

I don't know what you're trying to do, but the more I read about your questions and the discussion as a whole, the more I get the distinct impression that you're trying to use EVT_PAINT for no other reason other than because it is an event that gets fired on the control frequently. If that's a correct assumption, I suspect you want to use something more like a wx.Timer.

Regards,

Kevin

Thanks for your analysis, I think you're mostly right. Let me explain what I'm trying to do and why I use `EVT_PAINT`.

I have a bunch of widgets in my program. And, when some events occur in my program, these widgets need to do some recalculations and some redrawings. What kinds of events? Mainly changes of important variables. Here are examples: `pseudoclock_modified`, `tree_structure_modified`, `path_contents_changed`.

The way I announce these events is with a little publisher-subscriber system I made. For example, there is a `pseudoclock_modified_emitter`, which is an `Emitter` object. When the pseudoclock gets modified in some process, that process calls `pseudoclock_modified_emitter.emit()`. That `emit` function will then directly call a bunch of functions that have "subscribed" to this event. For example, I have a widget `ScratchWheel` that cares a lot whether the pseudoclock changed. When the pseudoclock changes, the scratch wheel needs to do some recalculations and, if the pseudoclock changed by a big-enough amount, possibly redraw itself.

So now the question is, what kind of function will the scratch wheel "subscribe" to the `pseudoclock_modified_emitter`? Let's refer to it as `ScratchWheel.subscribed_function`.

The first thought was to let `ScratchWheel.subscribed_function` just do the recalculation, and if a redraw is needed, order a `Refresh`. But the problem with that is that the pseudoclock may get changed many times before the end of one event loop. I will not want the scratch wheel to do the unneeded work of recalculating dozens of time before the scratch wheel even gets repainted once. It should do that work only once, when the scratch wheel gets repainted. If the scratch wheel doesn't get repainted (like if it's hidden), then it shouldn't do the work at all.

(Yeah, a few people said this is premature optimization. I don't think it's premature, I think I should try to get this right before I make a lot more widgets that work on this system.)

So I made `ScratchWheel.subscribed_function` something like this:

'''
def subscribed_function(self):
    self._needs_recalculation = True
    self.Refresh()
''''

And then made an `EVT_PAINT` handler that checks that flag and recalculate if it's up.

Do you think this is a good approach? Do you have any comments or suggestions?

I see a few problems with my approach:
  1. I am calling `Refresh` even though the widget might not need to get repainted. So it's doing some unneeded redrawing. I plan to get all my widgets to double-buffer in order to make this less of an issue.
  2. The problem I have now: That I call `Refresh` and my `on_paint` doesn't get called, because it has nothing to draw. (The "calculation" in this case results in changing the text in the child `TextCtrl`.)
So yeah, I can hack something to fix it in this case. I can give the panel a few pixels to draw. I just hope that there won't be bigger problems with this approach I'm taking.

If anyone has suggestions or ideas for an alternative, I'd be happy to hear them.

Ram.

Kevin Ollivier

unread,
Apr 21, 2010, 11:06:47 AM4/21/10
to cool-RR, wxPython-users
Hi Ram,

On Apr 21, 2010, at 6:14 AM, cool-RR wrote:

On Wed, Apr 21, 2010 at 1:35 AM, Kevin Ollivier <kevin...@theolliviers.com> wrote:
Hi Ram,

The answer to the question you actually asked is not "No", the answer to that question is to call Refresh() and Update(). However, what you wanted to know, and what you asked, were two different things. I don't think anyone could have read your mind to know that you wanted to fire a paint event on a control that was completely behind another control (and BTW, that's a very unusual request, you may in fact be one of the first to try it). You didn't provide that information, and until now, you never provided code so that we could see for ourselves what you were doing. This is why people were asking you for sample code. 

Please explain something: If I bind my Panel's `EVT_PAINT` to my own handler, and then in my own handler call `event.Skip()`, how come the paint handler of `wx.Panel` takes control? I thought only one handler could be assigned to each event. So after I bound my own handler, how come the original handler still works without me calling it explicitly?

You're incorrect that only one handler can be assigned to each event.

Also, if I am subclassing some widget class which has a paint handler, and I override the paint handler, and in the new one I want to do some unrelated actions and then use the original paint handler, do I just call it, like `BaseWidget.on_paint(self, event)`?

No, you call event.Skip().... I strongly recommend you consider getting wxPython in Action if you haven't already and reading through that (particularly section 3.4.1). From your questions, I get the impression that you're missing something fundamental about how event handling works in wxPython, and coding wxPython apps is going to be hard if you're working under mistaken assumptions about fundamentals like event propagation. 

Thanks for following up on my quest.

I've read 3.4.1 now. I see this is the part I've been missing:

'''
If a binder isn’t found for the object itself [or the handler does `Skip()`], the processing walks up the class hierarchy to find a binder defined in a superclass of the object—this is different than the walk up in the container hierarchy that happens in the next step.
'''

Now I understand. Though in my opinion this is an abuse of Python's class/object system. Usually in Python when you override a method, it is *your* responsibility to call the original method (if you want it), and it does not get called magically for you as in wxPython.

But if it's the wxPython way then that's what I'll have to do.

Event handling is different from inheritance, though. When you call Skip(), it does not mean "the base class will handle this event", it means "keep looking for an object that is subscribed to this event, and send this message to it as well". So when you call event.Skip(), the next handler it calls could be another widget's event handler, or even an event handler bound to the wx.App object itself.  

 
Moreover, you handle EVT_PAINT when you want to paint a control. That's the only time you want to handle it. If you want to do unrelated things, you do them somewhere else, because if one of your unrelated things happens to indirectly triggers a paint event in your paint handler, you'll end up in an endless loop. Also, painting is an expensive operation, so you should only do it when needed. Calling self.Update() when a control does not need to be redrawn, when it does do what you'd expect (i.e. when it's visible), wastes a lot of CPU cycles.

I don't know what you're trying to do, but the more I read about your questions and the discussion as a whole, the more I get the distinct impression that you're trying to use EVT_PAINT for no other reason other than because it is an event that gets fired on the control frequently. If that's a correct assumption, I suspect you want to use something more like a wx.Timer.

Regards,

Kevin

Thanks for your analysis, I think you're mostly right. Let me explain what I'm trying to do and why I use `EVT_PAINT`.

I have a bunch of widgets in my program. And, when some events occur in my program, these widgets need to do some recalculations and some redrawings. What kinds of events? Mainly changes of important variables. Here are examples: `pseudoclock_modified`, `tree_structure_modified`, `path_contents_changed`.

The way I announce these events is with a little publisher-subscriber system I made. For example, there is a `pseudoclock_modified_emitter`, which is an `Emitter` object. When the pseudoclock gets modified in some process, that process calls `pseudoclock_modified_emitter.emit()`. That `emit` function will then directly call a bunch of functions that have "subscribed" to this event. For example, I have a widget `ScratchWheel` that cares a lot whether the pseudoclock changed. When the pseudoclock changes, the scratch wheel needs to do some recalculations and, if the pseudoclock changed by a big-enough amount, possibly redraw itself.

So now the question is, what kind of function will the scratch wheel "subscribe" to the `pseudoclock_modified_emitter`? Let's refer to it as `ScratchWheel.subscribed_function`.

The first thought was to let `ScratchWheel.subscribed_function` just do the recalculation, and if a redraw is needed, order a `Refresh`. But the problem with that is that the pseudoclock may get changed many times before the end of one event loop. I will not want the scratch wheel to do the unneeded work of recalculating dozens of time before the scratch wheel even gets repainted once. It should do that work only once, when the scratch wheel gets repainted. If the scratch wheel doesn't get repainted (like if it's hidden), then it shouldn't do the work at all.

(Yeah, a few people said this is premature optimization. I don't think it's premature, I think I should try to get this right before I make a lot more widgets that work on this system.)

So I made `ScratchWheel.subscribed_function` something like this:

'''
def subscribed_function(self):
    self._needs_recalculation = True
    self.Refresh()
''''

Here's the problem, you've created a catch-22. ;-) You're trying to avoid unnecessary recalculation by handling the recalculation in the paint event, but, in order to make sure the recalculation happens, you're telling the OS it needs to paint the widget. So now subscribed_function is always causing a repaint, instead of sometimes when recalculation determines it's needed, and repaints are one of the most expensive CPU operations you can do. While I can't know for sure, the likelihood is that doing it this way actually performs more poorly than your original solution of doing the recalculation in subscribed_function. In short, calling self.Refresh() is no different as a practical matter from just putting the recalculation logic inside subscribed_function, because in both cases subscribe_function will always make sure the recalculation happens. It's just that now you're always repainting as well. (Except, of course, in the case when the widget is not visible at all, in which case you have a problem.)

I agree that this is a premature optimization. A premature optimization is when you try to solve / avoid a problem before you're really sure that it is actually a problem. For example, you try and speed up performance without actually measuring the performance of the two designs, and by making blind assumptions that one must perform better than the other. If the logic in subscribed_function is actually causing performance problems in your app, then you should certainly optimize it. But if it is not, say, if it takes almost no CPU time at all, you may be trying to solve the problem in an overly complex manner (and perhaps even making performance worse) in order to optimize performance by such a small amount that no one will actually ever even notice the speed up. 

If you want to make sure subscribed_function is not called too frequently, you can solve that problem by having the function calling pseudoclock_modified_emitter.emit() make sure that a certain amount of time has passed (say, 50 ms) since the last call before calling it again. However, again, I wouldn't suggest doing this unless you find there's a reason to do it.

And then made an `EVT_PAINT` handler that checks that flag and recalculate if it's up.

Do you think this is a good approach? Do you have any comments or suggestions?

I see a few problems with my approach:
  1. I am calling `Refresh` even though the widget might not need to get repainted. So it's doing some unneeded redrawing. I plan to get all my widgets to double-buffer in order to make this less of an issue.
  2. The problem I have now: That I call `Refresh` and my `on_paint` doesn't get called, because it has nothing to draw. (The "calculation" in this case results in changing the text in the child `TextCtrl`.)
So yeah, I can hack something to fix it in this case. I can give the panel a few pixels to draw. I just hope that there won't be bigger problems with this approach I'm taking.

As I said in a previous email, if you do something that causes the window to repaint in your paint event handler, which it seems could happen as a result of your recalculation, then you can end up in a loop. EVT_PAINT is really not the right place for this logic.

Regards,

Kevin

If anyone has suggestions or ideas for an alternative, I'd be happy to hear them.

Ram.

cool-RR

unread,
Apr 21, 2010, 1:02:44 PM4/21/10
to wxpython-users, kevin-lists
On Wed, Apr 21, 2010 at 1:35 AM, Kevin Ollivier <kevin...@theolliviers.com> wrote:

You're incorrect that only one handler can be assigned to each event.

I remember some time ago someone on this list told me to bind `EVT_ERASE_BACKGROUND` to a "do nothing" function. I understood this was in order to unbind it from a previous handler, so I assumed there could be only one handler. What did I get wrong there?

Ram.

Kevin Ollivier

unread,
Apr 21, 2010, 1:23:45 PM4/21/10
to cool-RR, wxpython-users
Hi Ram,

On Apr 21, 2010, at 10:02 AM, cool-RR wrote:

On Wed, Apr 21, 2010 at 1:35 AM, Kevin Ollivier <kevin...@theolliviers.com> wrote:

You're incorrect that only one handler can be assigned to each event.

I remember some time ago someone on this list told me to bind `EVT_ERASE_BACKGROUND` to a "do nothing" function. I understood this was in order to unbind it from a previous handler, so I assumed there could be only one handler. What did I get wrong there?

It does not unbind it from the previous handler. It makes your handler the top one in the event stack and, unless you call event.Skip(), only the top handler is ever run.

Regards,

Kevin

Ram.

cool-RR

unread,
Apr 21, 2010, 1:25:51 PM4/21/10
to Kevin Ollivier, wxPython-users
On Wed, Apr 21, 2010 at 7:23 PM, Kevin Ollivier <kevin...@theolliviers.com> wrote:
Hi Ram,
On Apr 21, 2010, at 10:02 AM, cool-RR wrote:
On Wed, Apr 21, 2010 at 1:35 AM, Kevin Ollivier <kevin...@theolliviers.com> wrote:

You're incorrect that only one handler can be assigned to each event.

I remember some time ago someone on this list told me to bind `EVT_ERASE_BACKGROUND` to a "do nothing" function. I understood this was in order to unbind it from a previous handler, so I assumed there could be only one handler. What did I get wrong there?

It does not unbind it from the previous handler. It makes your handler the top one in the event stack and, unless you call event.Skip(), only the top handler is ever run.

Regards,

Kevin

I understand. In retrospect I should have just done `Unbind` instead of overriding.

Ram.

Robin Dunn

unread,
Apr 21, 2010, 1:46:39 PM4/21/10
to wxpytho...@googlegroups.com
On 4/21/10 8:06 AM, Kevin Ollivier wrote:
>>
>> I've read 3.4.1 now. I see this is the part I've been missing:
>>
>> '''
>> If a binder isn’t found for the object itself [or the handler does
>> `Skip()`], the processing walks up the class hierarchy to find a
>> binder defined in a superclass of the object—this is different than
>> the walk up in the container hierarchy that happens in the next step.
>> '''
>>
>> Now I understand. Though in my opinion this is an abuse of Python's
>> class/object system. Usually in Python when you override a method, it
>> is *your* responsibility to call the original method (if you want it),
>> and it does not get called magically for you as in wxPython.
>>
>> But if it's the wxPython way then that's what I'll have to do.
>
> Event handling is different from inheritance, though. When you call
> Skip(), it does not mean "the base class will handle this event", it
> means "keep looking for an object that is subscribed to this event, and
> send this message to it as well". So when you call event.Skip(), the
> next handler it calls could be another widget's event handler, or even
> an event handler bound to the wx.App object itself.


Another way to look at this is that Bind simply adds another entry to a
virtual chain of event handlers, such that the one most recently added
to the instance is found first when a search is done. If that handler
calls Skip then the next one in the chain is called. If there are no
matching handlers in the chain, or if all of them call Skip, then wx
tells the system that the event was unhandled. The fact that some
segments of that chain may be coming from base classes, parent windows,
or the application object itself doesn't really matter as much, although
you do need to be aware of it to understand how they are ordered.

--
Robin Dunn
Software Craftsman
http://wxPython.org

Kevin Ollivier

unread,
Apr 21, 2010, 1:48:52 PM4/21/10
to cool-RR, wxPython-users
Hi Ram,

On Apr 21, 2010, at 10:25 AM, cool-RR wrote:

On Wed, Apr 21, 2010 at 7:23 PM, Kevin Ollivier <kevin...@theolliviers.com> wrote:
Hi Ram,
On Apr 21, 2010, at 10:02 AM, cool-RR wrote:
On Wed, Apr 21, 2010 at 1:35 AM, Kevin Ollivier <kevin...@theolliviers.com> wrote:

You're incorrect that only one handler can be assigned to each event.

I remember some time ago someone on this list told me to bind `EVT_ERASE_BACKGROUND` to a "do nothing" function. I understood this was in order to unbind it from a previous handler, so I assumed there could be only one handler. What did I get wrong there?

It does not unbind it from the previous handler. It makes your handler the top one in the event stack and, unless you call event.Skip(), only the top handler is ever run.

Regards,

Kevin

I understand. In retrospect I should have just done `Unbind` instead of overriding.

No, the advice you were given was correct. I'm not even sure you can call Unbind on methods defined at the C++ level.

Regards,

Kevin

Ram.

Robin Dunn

unread,
Apr 21, 2010, 2:06:11 PM4/21/10
to wxpytho...@googlegroups.com
On 4/21/10 10:48 AM, Kevin Ollivier wrote:
> Hi Ram,
>
> On Apr 21, 2010, at 10:25 AM, cool-RR wrote:
>
>> On Wed, Apr 21, 2010 at 7:23 PM, Kevin Ollivier
>> <kevin...@theolliviers.com <mailto:kevin...@theolliviers.com>>
>> wrote:
>>
>> Hi Ram,
>> On Apr 21, 2010, at 10:02 AM, cool-RR wrote:
>>> On Wed, Apr 21, 2010 at 1:35 AM, Kevin Ollivier
>>> <kevin...@theolliviers.com
>>> <mailto:kevin...@theolliviers.com>> wrote:
>>>
>>>
>>> You're incorrect that only one handler can be assigned to
>>> each event.
>>>
>>>
>>> I remember some time ago someone on this list told me to bind
>>> `EVT_ERASE_BACKGROUND` to a "do nothing" function. I understood
>>> this was in order to unbind it from a previous handler, so I
>>> assumed there could be only one handler. What did I get wrong there?
>>
>> It does not unbind it from the previous handler. It makes your
>> handler the top one in the event stack and, unless you call
>> event.Skip(), only the top handler is ever run.
>>
>> Regards,
>>
>> Kevin
>>
>>
>> I understand. In retrospect I should have just done `Unbind` instead
>> of overriding.
>
> No, the advice you were given was correct. I'm not even sure you can
> call Unbind on methods defined at the C++ level.

Unbind will probably work with events bound dynamically, but since most
of the event bindings in the library C++ classes are done in static
event tables it won't help much.


--
Robin Dunn
Software Craftsman
http://wxPython.org

cool-RR

unread,
Apr 21, 2010, 3:42:12 PM4/21/10
to wxpython-users, robin, kevin-lists
I understand, thanks.

Kevin: I'm still digesting your long email.

Ram.

cool-RR

unread,
Apr 21, 2010, 4:24:57 PM4/21/10
to wxpython-users, kevin-lists
On Wed, Apr 21, 2010 at 5:06 PM, Kevin Ollivier <kevin...@theolliviers.com> wrote:
Hi Ram,

On Apr 21, 2010, at 6:14 AM, cool-RR wrote:
Thanks for your analysis, I think you're mostly right. Let me explain what I'm trying to do and why I use `EVT_PAINT`.

I have a bunch of widgets in my program. And, when some events occur in my program, these widgets need to do some recalculations and some redrawings. What kinds of events? Mainly changes of important variables. Here are examples: `pseudoclock_modified`, `tree_structure_modified`, `path_contents_changed`.

The way I announce these events is with a little publisher-subscriber system I made. For example, there is a `pseudoclock_modified_emitter`, which is an `Emitter` object. When the pseudoclock gets modified in some process, that process calls `pseudoclock_modified_emitter.emit()`. That `emit` function will then directly call a bunch of functions that have "subscribed" to this event. For example, I have a widget `ScratchWheel` that cares a lot whether the pseudoclock changed. When the pseudoclock changes, the scratch wheel needs to do some recalculations and, if the pseudoclock changed by a big-enough amount, possibly redraw itself.

So now the question is, what kind of function will the scratch wheel "subscribe" to the `pseudoclock_modified_emitter`? Let's refer to it as `ScratchWheel.subscribed_function`.

The first thought was to let `ScratchWheel.subscribed_function` just do the recalculation, and if a redraw is needed, order a `Refresh`. But the problem with that is that the pseudoclock may get changed many times before the end of one event loop. I will not want the scratch wheel to do the unneeded work of recalculating dozens of time before the scratch wheel even gets repainted once. It should do that work only once, when the scratch wheel gets repainted. If the scratch wheel doesn't get repainted (like if it's hidden), then it shouldn't do the work at all.

(Yeah, a few people said this is premature optimization. I don't think it's premature, I think I should try to get this right before I make a lot more widgets that work on this system.)

So I made `ScratchWheel.subscribed_function` something like this:

'''
def subscribed_function(self):
    self._needs_recalculation = True
    self.Refresh()
''''

Here's the problem, you've created a catch-22. ;-) You're trying to avoid unnecessary recalculation by handling the recalculation in the paint event, but, in order to make sure the recalculation happens, you're telling the OS it needs to paint the widget. So now subscribed_function is always causing a repaint, instead of sometimes when recalculation determines it's needed, and repaints are one of the most expensive CPU operations you can do. While I can't know for sure, the likelihood is that doing it this way actually performs more poorly than your original solution of doing the recalculation in subscribed_function. In short, calling self.Refresh() is no different as a practical matter from just putting the recalculation logic inside subscribed_function, because in both cases subscribe_function will always make sure the recalculation happens. It's just that now you're always repainting as well. (Except, of course, in the case when the widget is not visible at all, in which case you have a problem.)

You seem to be neglecting the case where I could have a dozen recalculation requests before one paint handling. In my approach all these dozen recalculation will be collapsed into one recalculation. In your approach, a dozen recalculations will take place.

 
I agree that this is a premature optimization. A premature optimization is when you try to solve / avoid a problem before you're really sure that it is actually a problem. For example, you try and speed up performance without actually measuring the performance of the two designs, and by making blind assumptions that one must perform better than the other. If the logic in subscribed_function is actually causing performance problems in your app, then you should certainly optimize it. But if it is not, say, if it takes almost no CPU time at all, you may be trying to solve the problem in an overly complex manner (and perhaps even making performance worse) in order to optimize performance by such a small amount that no one will actually ever even notice the speed up. 

If you want to make sure subscribed_function is not called too frequently,
 
you can solve that problem by having the function calling pseudoclock_modified_emitter.emit() make sure that a certain amount of time has passed (say, 50 ms) since the last call before calling it again.

I think this'll make things too complex. (i.e. I'll need to take care of the case where it changes by 30ms and then 30ms again.)
 
However, again, I wouldn't suggest doing this unless you find there's a reason to do it.

And then made an `EVT_PAINT` handler that checks that flag and recalculate if it's up.

Do you think this is a good approach? Do you have any comments or suggestions?

I see a few problems with my approach:
  1. I am calling `Refresh` even though the widget might not need to get repainted. So it's doing some unneeded redrawing. I plan to get all my widgets to double-buffer in order to make this less of an issue.
  2. The problem I have now: That I call `Refresh` and my `on_paint` doesn't get called, because it has nothing to draw. (The "calculation" in this case results in changing the text in the child `TextCtrl`.)
So yeah, I can hack something to fix it in this case. I can give the panel a few pixels to draw. I just hope that there won't be bigger problems with this approach I'm taking.

As I said in a previous email, if you do something that causes the window to repaint in your paint event handler, which it seems could happen as a result of your recalculation, then you can end up in a loop. EVT_PAINT is really not the right place for this logic.

Kevin

I think that my recalculations won't cause a `Refresh`, I think they're okay to put in the paint handler. (It's recalculations about how to paint the widget.)


I thought about it, and I think I'll stick with my method. Most of the `emit`tings will result in a repaint anyway, so I'm not losing much by calling `Refresh` indiscriminately. (Especially if I make sure all widgets are double-buffered.)

I'll just do some hack to get the current issue fixed, like give a border of 1 pixel around the text control so the panel will have something to draw.

Thanks for your help and observations.

Ram.

Kevin Ollivier

unread,
Apr 21, 2010, 5:03:33 PM4/21/10
to cool-RR, wxpython-users
Hi Ram,

On Apr 21, 2010, at 1:24 PM, cool-RR wrote:

On Wed, Apr 21, 2010 at 5:06 PM, Kevin Ollivier <kevin...@theolliviers.com> wrote:
Hi Ram,

On Apr 21, 2010, at 6:14 AM, cool-RR wrote:
Thanks for your analysis, I think you're mostly right. Let me explain what I'm trying to do and why I use `EVT_PAINT`.

I have a bunch of widgets in my program. And, when some events occur in my program, these widgets need to do some recalculations and some redrawings. What kinds of events? Mainly changes of important variables. Here are examples: `pseudoclock_modified`, `tree_structure_modified`, `path_contents_changed`.

The way I announce these events is with a little publisher-subscriber system I made. For example, there is a `pseudoclock_modified_emitter`, which is an `Emitter` object. When the pseudoclock gets modified in some process, that process calls `pseudoclock_modified_emitter.emit()`. That `emit` function will then directly call a bunch of functions that have "subscribed" to this event. For example, I have a widget `ScratchWheel` that cares a lot whether the pseudoclock changed. When the pseudoclock changes, the scratch wheel needs to do some recalculations and, if the pseudoclock changed by a big-enough amount, possibly redraw itself.

So now the question is, what kind of function will the scratch wheel "subscribe" to the `pseudoclock_modified_emitter`? Let's refer to it as `ScratchWheel.subscribed_function`.

The first thought was to let `ScratchWheel.subscribed_function` just do the recalculation, and if a redraw is needed, order a `Refresh`. But the problem with that is that the pseudoclock may get changed many times before the end of one event loop. I will not want the scratch wheel to do the unneeded work of recalculating dozens of time before the scratch wheel even gets repainted once. It should do that work only once, when the scratch wheel gets repainted. If the scratch wheel doesn't get repainted (like if it's hidden), then it shouldn't do the work at all.

(Yeah, a few people said this is premature optimization. I don't think it's premature, I think I should try to get this right before I make a lot more widgets that work on this system.)

So I made `ScratchWheel.subscribed_function` something like this:

'''
def subscribed_function(self):
    self._needs_recalculation = True
    self.Refresh()
''''

Here's the problem, you've created a catch-22. ;-) You're trying to avoid unnecessary recalculation by handling the recalculation in the paint event, but, in order to make sure the recalculation happens, you're telling the OS it needs to paint the widget. So now subscribed_function is always causing a repaint, instead of sometimes when recalculation determines it's needed, and repaints are one of the most expensive CPU operations you can do. While I can't know for sure, the likelihood is that doing it this way actually performs more poorly than your original solution of doing the recalculation in subscribed_function. In short, calling self.Refresh() is no different as a practical matter from just putting the recalculation logic inside subscribed_function, because in both cases subscribe_function will always make sure the recalculation happens. It's just that now you're always repainting as well. (Except, of course, in the case when the widget is not visible at all, in which case you have a problem.)

You seem to be neglecting the case where I could have a dozen recalculation requests before one paint handling. In my approach all these dozen recalculation will be collapsed into one recalculation. In your approach, a dozen recalculations will take place.

No, I'm not neglecting it. However, if what I have written above is not convincing to you, then I think you should just use your design and see what happens when you implement it extensively throughout an app. I have a feeling it won't turn out quite how you suspect it will, but without knowing the specifics of your recalculation routines, I can't say for sure. (But I do know that calling self.Refresh() repeatedly like this is rarely a good idea, if it is ever a good idea.)

I agree that this is a premature optimization. A premature optimization is when you try to solve / avoid a problem before you're really sure that it is actually a problem. For example, you try and speed up performance without actually measuring the performance of the two designs, and by making blind assumptions that one must perform better than the other. If the logic in subscribed_function is actually causing performance problems in your app, then you should certainly optimize it. But if it is not, say, if it takes almost no CPU time at all, you may be trying to solve the problem in an overly complex manner (and perhaps even making performance worse) in order to optimize performance by such a small amount that no one will actually ever even notice the speed up. 

If you want to make sure subscribed_function is not called too frequently,
 
you can solve that problem by having the function calling pseudoclock_modified_emitter.emit() make sure that a certain amount of time has passed (say, 50 ms) since the last call before calling it again.

I think this'll make things too complex. (i.e. I'll need to take care of the case where it changes by 30ms and then 30ms again.)
 
However, again, I wouldn't suggest doing this unless you find there's a reason to do it.

And then made an `EVT_PAINT` handler that checks that flag and recalculate if it's up.

Do you think this is a good approach? Do you have any comments or suggestions?

I see a few problems with my approach:
  1. I am calling `Refresh` even though the widget might not need to get repainted. So it's doing some unneeded redrawing. I plan to get all my widgets to double-buffer in order to make this less of an issue.
  2. The problem I have now: That I call `Refresh` and my `on_paint` doesn't get called, because it has nothing to draw. (The "calculation" in this case results in changing the text in the child `TextCtrl`.)
So yeah, I can hack something to fix it in this case. I can give the panel a few pixels to draw. I just hope that there won't be bigger problems with this approach I'm taking.

As I said in a previous email, if you do something that causes the window to repaint in your paint event handler, which it seems could happen as a result of your recalculation, then you can end up in a loop. EVT_PAINT is really not the right place for this logic.

Kevin

I think that my recalculations won't cause a `Refresh`, I think they're okay to put in the paint handler. (It's recalculations about how to paint the widget.)

I thought about it, and I think I'll stick with my method. Most of the `emit`tings will result in a repaint anyway, so I'm not losing much by calling `Refresh` indiscriminately. (Especially if I make sure all widgets are double-buffered.)

I'll just do some hack to get the current issue fixed, like give a border of 1 pixel around the text control so the panel will have something to draw.

Okay, then good luck to you. :-)

Regards,

Kevin

Thanks for your help and observations.

Ram.

Christopher Barker

unread,
Apr 21, 2010, 5:30:33 PM4/21/10
to wxpytho...@googlegroups.com
Hi all,

I have to say that at first glance It seems obvious that Kevin is on the
right track, but since it's not obvious to everyone, I may have
understood the problem. I'm going to step back a bit and see if I've got
it right:

1) You have a process in which various parameters might be changed at
arbitrary (and fairly often) times.

2) You have a GUI that displays the results of some calculations based
on these parameters.

3) you want the user to see the "current" results at all times.

4) The calculations are not trivial, and the parameters might change
very frequently, so you don't want to re-calculate every time something
changes.


Have I got that right?

If so, then you are thinking that there is no need to re-calculate if
the results are not going to be seen. This leads you to the idea that a
Paint event should trigger the calculation -- why bother calculating if
you're not going to re-paint?

However, this still feels backward -- it's the parameters changing that
create a need for a re-calculation, and the changing results of the
calculation that create a need to re-paint (update) the GUI. If not,
then as the parameters change away, and the user is staring at the
screen, when are they ever going to see a change? When they happen to
move another window or something, which would trigger a Paint event?
that seems odd.

So you'll need to trigger that Paint event based on some other criteria
what is that criteria? What it triggering those paint events?


I'd think of it like this:

- Every time a parameter changes, this triggers a calculation.
- Every time the results change, this should trigger a screen update.

That will assure that the screen always reflects latest information.

But what if the parameter changes come too fast to do all that each time
(or there is no point -- a user can only process the changes so fast
anyway)?

This is where a timer approach comes in.

- If you want an update every second, set a timer that triggers the
re-calculation every second.

- If you want the updates about as fast as you can process them, but
no faster, then each time there is a parameter change, start a one-shot
timer for a bit longer than it takes to do the full calculate-screen
update process. Then re-set that timer when a new parameter change come
in. When the timer completes, trigger the recalculation.

- This is how things like re-painting a window that is re-sizing is
often done. If it takes a while to paint the Window, things really go to
heck when the user re-sizes (if the system is set to try to draw the
window as it is is re-sized) -- the size and paint events come much too
fast. With a little time delay, it can work nicely.

HTH,

-Chris














--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris....@noaa.gov

cool-RR

unread,
Apr 22, 2010, 12:59:05 PM4/22/10
to wxpython-users
On Wed, Apr 21, 2010 at 11:30 PM, Christopher Barker <Chris....@noaa.gov> wrote:
Hi all,

I have to say that at first glance It seems obvious that Kevin is on the right track, but since it's not obvious to everyone, I may have understood the problem. I'm going to step back a bit and see if I've got it right:

1) You have a process in which various parameters might be changed at arbitrary (and fairly often) times.

2) You have a GUI that displays the results of some calculations based on these parameters.

3) you want the user to see the "current" results at all times.

4) The calculations are not trivial, and the parameters might change very frequently, so you don't want to re-calculate every time something changes.


Have I got that right?

Yes, that's right. 

 
If so, then you are thinking that there is no need to re-calculate if the results are not going to be seen. This leads you to the idea that a Paint event should trigger the calculation -- why bother calculating if you're not going to re-paint?

However, this still feels backward -- it's the parameters changing that create a need for a re-calculation, and the changing results of the calculation that create a need to re-paint (update) the GUI. If not, then as the parameters change away, and the user is staring at the screen, when are they ever going to see a change? When they happen to move another window or something, which would trigger a Paint event? that seems odd.

So you'll need to trigger that Paint event based on some other criteria what is that criteria? What it triggering those paint events?


I'd think of it like this:

- Every time a parameter changes, this triggers a calculation.
- Every time the results change, this should trigger a screen update.

That will assure that the screen always reflects latest information.

But what if the parameter changes come too fast to do all that each time (or there is no point -- a user can only process the changes so fast anyway)?

This is where a timer approach comes in.

 - If you want an update every second, set a timer that triggers the re-calculation every second.

 - If you want the updates about as fast as you can process them, but no faster, then each time there is a parameter change, start a one-shot timer for a bit longer than it takes to do the full calculate-screen update process. Then re-set that timer when a new parameter change come in. When the timer completes, trigger the recalculation.

 - This is how things like re-painting a window that is re-sizing is often done. If it takes a while to paint the Window, things really go to heck when the user re-sizes (if the system is set to try to draw the window as it is is re-sized) -- the size and paint events come much too fast. With a little time delay, it can work nicely.

HTH,


-Chris

Thanks for the idea, I've started attempting to program it yesterday, still working on it.

Ram. 
 

cool-RR

unread,
Apr 22, 2010, 4:26:58 PM4/22/10
to wxpython-users, Chris.Barker
Hey, I got it working. It works like this: When the watched parameter changes, and the `emit` is done, a recalculation flag is raised (if it wasn't raised already) and a one-shot timer of 30ms is started (if it wasn't started already by an earlier `emit`.) When the timer is done it checks if the flag is still up, and if so does the recalculation, calling a Refresh *only* if the recalculation says it's necessary, and then lowering the flag. You can ask, why does it check if the flag is up? Because the `on_paint` also checks if the flag is up, and if so does the recalculation and lowers the flag. Just so I could be sure that when the widget gets painted, it's updated.

Seems to work okay. What do you think?

Ram
Reply all
Reply to author
Forward
0 new messages