views:

902

answers:

2

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?

+4  A: 

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.

GRB
+3  A: 

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()
FogleBird
My guess is that it'll be impossible to eliminate the flicker. The OnSize event is always fired after resizing has started, which means calling SetSize when the event is received afterward will always result in flickering (this is an OS limitation, not a wx-specific issue). Additionally, the window frame (the drawing of and functionality of) is completely controlled by the OS, so there's no way to 'override' it to try and alter its functionality.
GRB