Search code examples
pythonuser-interfacewxpythonscalewxwidgets

Rescale a whole Panel in order to fit in a window


I have MyPanel of size (1200,800) which is embedded in a parent MainPanel (whose size can change with the size of the MainFrame) :

import wx

class MyPanel(wx.Panel):   # panel embedded in the main panel
    def __init__(self, parent):
        wx.Panel.__init__(self, parent, -1, size=(1200,800))
        sizer = wx.BoxSizer(wx.VERTICAL)
        bmp = wx.BitmapFromImage(wx.Image('background.png', wx.BITMAP_TYPE_PNG))  
        myimg = wx.StaticBitmap(self, -1, bmp)
        sizer.Add(myimg, 0, wx.SHAPED, 10)

class MainPanel(wx.Panel):   # main panel embedded in the main frame
    def __init__(self, parent):
        wx.Panel.__init__(self, parent, -1)
        self.mypanel = MyPanel(self)

class MainFrame(wx.Frame):  # main frame window
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, -1, title, size=(800,600))
        self.panel = MainPanel(self)
        self.Show()

app = wx.App(0)
frame = MainFrame(None, 'Test')
app.MainLoop()

How is it possible to automatically rescale MyPanel so that it fits in the parent MainPanel , keeping its aspect ratio ?

Remark : I am looking for a behaviour close to Windows's standard photo viewer : when the window is resized, the image is rescaled to fit in the parent window.

enter image description here


Solution

  • Just apply my previous answer to the panel that you want to maintain the aspect ration on. Not a 100% clear on the exact behavior you want but this should get you close enough.

    import wx
    
        class MyPanel(wx.Panel):   # panel embedded in the main panel
            def __init__(self, parent):
                wx.Panel.__init__(self, parent, -1)
                sizer = wx.BoxSizer(wx.VERTICAL)
                txt = wx.StaticText(self, label="Missing Bitmap");
                sizer.Add(txt, 0, wx.SHAPED, 10)
    
                self.SetInitialSize((1200, 800))
                self.BackgroundColour = wx.RED
                self.Sizer = sizer
    
                self.Bind(wx.EVT_SIZE, self.OnSize)
    
            def OnSize(self, evt):
                hsize = evt.Size[0] * 0.75 # Constrain max height to 75% of width
                self.SetSizeHints(-1, hsize, maxH=hsize)
                evt.Skip()
    

    Important part is here, you need to adjust the size hints on the sub panel window every time its size is being requested to change to tell the sizer to limit the constraints on the geometry of the window.

        class MainPanel(wx.Panel):   # main panel embedded in the main frame
            def __init__(self, parent):
                wx.Panel.__init__(self, parent, -1)
                self.mypanel = MyPanel(self)
    
                self.BackgroundColour = wx.BLACK
    

    Background color set to help show difference between parent panel and its child panel which is colored red.

                vsizer = wx.BoxSizer(wx.VERTICAL)
                vsizer.AddStretchSpacer(0)
                vsizer.Add(self.mypanel, 1, wx.SHAPED|wx.EXPAND|wx.ALIGN_CENTER)
                vsizer.AddStretchSpacer(0)
    
                hsizer = wx.BoxSizer(wx.HORIZONTAL)
                hsizer.AddStretchSpacer(0)
                hsizer.Add(vsizer, 1, wx.EXPAND|wx.ALIGN_CENTER)
                hsizer.AddStretchSpacer(0)
    
                self.Sizer = hsizer;
    

    Here in the MainPanel it uses two sizers with stretch spacers to keep the subpanel pushed towards the middle both horizontally and vertically as the window resizes.

        class MainFrame(wx.Frame):  # main frame window
            def __init__(self, parent, title):
                wx.Frame.__init__(self, parent, -1, title, size=(800,600))
                self.panel = MainPanel(self)
                self.Show()
    
        app = wx.App(0)
        frame = MainFrame(None, 'Test')
        app.MainLoop()