Sunday, September 24, 2017

Resize image dynamically when frame is maximized in wxPython

Hello,

I will work you through on how you will "Resize a wxStaticBitmap image dynamically when frame is maximized in wxPython

Here I have two StaticBitmap images placed side-by-side in box sizers. So, we want the size of the images to scale appropriately with the frame whenever it is been maximized.

The code....

import wx

class MyFrame2 ( wx.Frame ):

    def __init__( self, parent ):
        wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size( 500,300 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )

        self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize )

        bSizer11 = wx.BoxSizer( wx.HORIZONTAL )

        self.m_bitmap3 = wx.StaticBitmap( self, wx.ID_ANY, wx.Bitmap( u"img/im1.jpg", wx.BITMAP_TYPE_ANY ), wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer11.Add( self.m_bitmap3, 1, wx.ALL|wx.EXPAND, 5 )

        self.m_bitmap4 = wx.StaticBitmap( self, wx.ID_ANY, wx.Bitmap( u"img/im2.jpg", wx.BITMAP_TYPE_ANY ), wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer11.Add( self.m_bitmap4, 1, wx.ALL|wx.EXPAND, 5 )


        self.SetSizer( bSizer11 )
        self.Layout()

        self.Centre( wx.BOTH )

    def __del__( self ):
        pass

app = wx.App(0)
MyFrame2(None).Show()
app.MainLoop()

When you first launch the GUI it is like this....





When you maximize the GUI, you have this....



Now, this is not good as the images remain in there original size ratio even though the size of the frame has increased.

Lets see how we can make the frame's size event (wx.EVT_SIZE) to listen to the frame size been changed and then re-scale the images accordingly.

A wx.StaticBitmap does not automatically size its contents to fit the container. You will have to catch the wx.EVT_SIZE event and do the scaling manually.

Basically when you first draw your images you have to calculate the space to put them in and scale them to fit and then draw them.

The wx.EVT_SIZE event tells you that the window size has changed, so you have to redo the above. You may wish to use some logic to see if the resizing has finished before doing so as to avoid slowing things down.

The updated code...

import wx

class MyFrame2 ( wx.Frame ):

    def __init__( self, parent ):
        wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size( 500,300 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
        self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize )
        bSizer11 = wx.BoxSizer( wx.HORIZONTAL )
        self.img1=wx.Image("img/im1.jpg", wx.BITMAP_TYPE_ANY)
        self.img2=wx.Image("img/im2.jpg", wx.BITMAP_TYPE_ANY)
        self.m_bitmap3 = wx.StaticBitmap( self, wx.ID_ANY, wx.BitmapFromImage(self.img1), wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer11.Add( self.m_bitmap3, 1, wx.EXPAND, 0 )
        self.m_bitmap4 = wx.StaticBitmap( self, wx.ID_ANY, wx.BitmapFromImage(self.img2))
        bSizer11.Add( self.m_bitmap4, 1, wx.EXPAND, 0 )
        self.Bind(wx.EVT_SIZE, self.onResize)
        self.SetSizer( bSizer11 )
        self.Layout()
        self.Centre(wx.BOTH)

    def __del__( self ):
        pass

    def onResize(self, event):
        # self.Layout()
        frame_size = self.GetSize()
        frame_h = (frame_size[0]-10) / 2
        frame_w = (frame_size[1]-10) / 2
        img1 = self.img1.Scale(frame_h,frame_w)
        img2 = self.img2.Scale(frame_h,frame_w)
        self.m_bitmap3.SetBitmap(wx.BitmapFromImage(img1))
        self.m_bitmap4.SetBitmap(wx.BitmapFromImage(img2))
        self.Refresh()
        self.Layout()

app = wx.App(0)
MyFrame2(None).Show()
app.MainLoop()



Thanks for reading...

No comments:

Post a Comment