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.
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
On 4/20/10 3:04 PM, cool-RR wrote: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.
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'.
Robin Dunn
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.
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: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.
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'.
Robin DunnI 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.--
To unsubscribe, send email to wxPython-user...@googlegroups.com
or visit http://groups.google.com/group/wxPython-users?hl=en
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
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,KevinThanks 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 = Trueself.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:
- 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.
- 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.
You're incorrect that only one handler can be assigned to each event.
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.
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
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,KevinI understand. In retrospect I should have just done `Unbind` instead of overriding.
Ram.
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 = Trueself.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:
- 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.
- 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
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 = Trueself.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:
- 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.
- 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.KevinI 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.
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