wxwidgets/wxPython: Resizing a wxFrame while keeping aspect ratio
-
18-09-2019 - |
Question
I have a wx.Frame that has only a single child. While setting up the child's wx.Sizer, I can use the wx.SHAPED flag, which keeps the aspect ratio of the child locked. However, the Frame still has complete freedom in it's aspect ratio, and will leave a blank space in the area that is left unused by the child.
How can I lock the aspect ratio of the wx.Frame during resizing?
Solution
Sizers cannot be applied to top-level windows (in order to define properties of the windows themselves as opposed to their contents), so unfortunately there is no "true" way to lock in the aspect ratio. Your best bet would be to catch your window's OnSize
event, get the size that the user wants the window to be (which is stored in the wxSizeEvent
), calculate the new width and height according to the aspect ratio and then immediately call SetSize
with the new size.
This technique has the drawback of visual artifacts during resizing (the operating system will initially paint the window according to how the user has dragged it but then immediately redraw it after you call SetSize
, leading to a flickering effect) so it isn't a great solution, however since you cannot lock top-level windows into aspect ratios (and prevent the need to resize with SetSize
at all) you'll have to decide whether the flickering is worth it.
OTHER TIPS
Here is some sample code. There is a good bit of flicker, and I'm not sure of a good way to eliminate it.
import wx
class Frame(wx.Frame):
def __init__(self):
super(Frame, self).__init__(None, -1, 'Shaped Frame')
self.Bind(wx.EVT_SIZE, self.on_size)
self.panel = panel = wx.Panel(self, -1)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(panel, 1, wx.SHAPED)
self.SetSizer(sizer)
def on_size(self, event):
event.Skip()
self.Layout()
self.panel.SetMinSize(self.panel.GetSize())
self.Fit()
if __name__ == '__main__':
app = wx.PySimpleApp()
frame = Frame()
frame.Show()
app.MainLoop()