wxPython Background Image Scaling

A user interface with a background picture of daffodils made out of lego.

What is a user interface without a background image? Not only does it need an image, it also needs to automatically resize to fit, as the user resizes the user interface. The photo used here is my original photo. It is only for exercising the code. I don’t have any intention of using this exact image in the final version.

It’s interesting to note that most of the sample code I found is based around the same few examples. The example I used in the end came from Stack Overflow. This is a good starting point because it works.

nicely with the window.

import wx

class MainPanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent, -1, style=wx.FULL_REPAINT_ON_RESIZE)
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.img = wx.Image('daffodils.jpg', wx.BITMAP_TYPE_JPEG)
        self.imgx, self.imgy = self.img.GetSize()

    def OnPaint(self, event):
        dc = wx.PaintDC(self)
        dc.Clear()
        x,y = self.GetSize()
        posx,posy = 0, 0
        newy = int(float(x)/self.imgx*self.imgy)
        if newy < y:
            posy = int((y - newy) / 2) 
            y = newy
        else:
            newx = int(float(y)/self.imgy*self.imgx)
            posx = int((x - newx) / 2)
            x = newx        

        img = self.img.Scale(x,y, wx.IMAGE_QUALITY_HIGH)
        self.bmp = wx.Bitmap(img)
        dc.DrawBitmap(self.bmp,posx,posy)

class MainFrame(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, -1, title='Test', size=(600,400))
        self.panel = MainPanel(self)
        self.Show()

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

In the OnPaint(): function, it does the calculation for keeping the image in scale. This particular algorithm keeps the aspect ratio correct. So this is what we will need when actually showing photos. But for the background picture I want it to forget the aspect ratio.

From the last line in the MainPanel init, we see that imgx and imgy are the original height and width of the image.

        self.imgx, self.imgy = self.img.GetSize()

I am going to rename this to img_height and img_width. This is confusing.

This is how it looks at the moment, if the UI is scaled:

When the user interface goes tall and narrow, white space appears above and below the image.
When the user interface goes tall and narrow, white space appears above and below the image.
When the user interface goes wide and narrow, white space appears to the left and right of the image.
When the user interface goes wide and narrow, white space appears to the left and right of the image.

To make the image scale with the user interface, as you would expect for a background picture, you can simply remove the lines which recalculate x and y – or as it will be called – width and height. Here is the code that scales ignoring the aspect ratio.

import wx

class MainPanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent, -1, style=wx.FULL_REPAINT_ON_RESIZE)
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.img = wx.Image('daffodils.jpg', wx.BITMAP_TYPE_JPEG)
        self.imgx, self.imgy = self.img.GetSize()

    def OnPaint(self, event):
        dc = wx.PaintDC(self)
        dc.Clear()
        x,y = self.GetSize()
        posx,posy = 0, 0
  
        # Deleted lines here
        
        img = self.img.Scale(x,y, wx.IMAGE_QUALITY_HIGH)
        self.bmp = wx.Bitmap(img)
        dc.DrawBitmap(self.bmp,posx,posy)

class MainFrame(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, -1, title='Test', size=(600,400))
        self.panel = MainPanel(self)
        self.Show()

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

This is good now. Next task is to get a quieter background image, that won’t take the focus.

Leave a Reply

Your email address will not be published. Required fields are marked *