Hi,
I’m trying to use CallAfter to get the size of a panel after the application goes into MainLoop.
I placed code to get and print the client size as soon as the function invoked by CallAfter runs.
It is the initial panel size.
The same logic is executed when I press the “Panel” button.
It is the maximum panel size.
Can someone please explain why the logic does not get the maximum size in the function invoked by CallAfter?
A minimal working code sample is attached.
Thanks
draw.py (2.7 KB)
After a bit of trial and error, I found that if I changed the following line in DrawPlotFrame.__init__()
self.SetSizer(self.framesizer)
to:
self.SetSizerAndFit(self.framesizer)
then the output from the CallAfter()
function does match that from the button event handler.
Tested using wxPython 4.2.2 gtk3 (phoenix) wxWidgets 3.2.6 + Python 3.12.3 + Linux Mint 22
Hi Richard,
Thanks very much for testing & replying.
I’m running the following applications
“”"
‘4.0.7 gtk3 (phoenix) wxWidgets 3.0.5’
Python 3.10.6
“”"
The OS is Ubuntu Release 22.04(jammy jellyfish) 64-bit
Mate 1.26.0
In method OnSize in class DrawPlotPanel, I added a print statement at the beginning of the method so that “OnSize” is printed & I commented out the CallAfter call
def OnSize(self, event):
print(" OnSize")
self.update_drawing()
self.panel_width, self.panel_height = self.GetClientSize()
print(self.panel_width, self.panel_height)
“”"
if self.get_pixels_flag:
self.get_pixels_flag = 0
wx.CallAfter(self.CallAfterInfoSetup)
“”"
When I run this, OnSize is called 3 times and prints the following
OnSize
398 154
OnSize
1920 923
OnSize
1920 923
When I change the SetSizer statement in DrawPlotPanel to SetSizerAndFit, OnSize is called 4 times and prints the following
OnSize
200 1
OnSize
200 1
OnSize
1920 923
OnSize
1920 923
Very peculiar.
Are you able to explain this behavior?
Thanks again for your help.
Sorry. That should be:
When I change the SetSizer statement in DrawPlotFrame to SetSizerAndFit, OnSize is called 4 times and prints the following
Thanks
I made your changes to the Panel’s OnSize()
method.
I then added bindings to the Frame for EVT_SHOW, EVT_MAXIMISE and EVT_SIZE. The handlers just print their names, but the EVT_SIZE handler also needed a call to event.Skip()
.
I then ran the code in debug and tried to tie the events happening in the Frame to each call to the Panel’s OnSize()
method.
The first call to the Panel’s OnSize()
method happens after the Frame gets its initial EVT_SIZE event.
The second and third calls to the Panel’s OnSize()
method happens after the Frame gets an EVT_SHOW event, followed by an EVT_MAXIMISE event, followed by an EVT_SIZE event.
Note: although the code calls self.Maximize()
before self.Show()
, their corresponding events are actually triggered in the opposite order.
In the case where SetSizerAndFit()
is used, it is the call to that method itself that triggers the Panel’s OnSize()
method, i.e. that call happens before the main loop is started.
Does the following work on your system?
def OnSize(self, event):
self.update_drawing()
if self.parent.IsMaximized() and self.get_pixels_flag:
self.get_pixels_flag = 0
self.panel_width, self.panel_height = self.GetClientSize()
print(self.panel_width, self.panel_height)
Hi Richard,
Your solution works correctly here.
Thanks very much for your help.
If I may, I’m still curious as to why CallAfter did not work.
I obviously don’t understand all of its intricasies.
I thought that events were only processed once MainLoop was entered and that CallAfter placed an event at the end of queue.
What is it that I mis-understood?
Thanks
It’s just a guess, but perhaps there is an interval between the initial EVT_SIZE event when the Frame and Panel are created and the point where the Frame gets maximised, in which which there are no pending events in the queue, so the CallAfter’s target gets called gets called in that interval?
I found an alternative technique which works on my system.
Instead of binding EVT_SIZE in the Panel, it binds EVT_MAXIMIZE in the Frame.
Here is the OnMaximize()
handler:
def OnMaximize(self, event):
self.Update()
wx.CallAfter(self.drawplotpanel.CallAfterInfoSetup)
The call to self.Update()
causes the Frame and its children to be updated, so that when the CallAfter target is triggered, the Panel has reached its correct size.
Here is the modified example:
draw_8.py (2.8 KB)
Hi Richard,
Your alternate solution works correctly here also.
This seems to be a more straight forward method to get the maximum size.
Thanks again for your help.