wxPython: Updatable Static Bitmap that has scrolls

505 views Asked by At

Objective

StaticBitmap that can be updated by main frame's method and has scrolls.

Details

I want to add an image (StaticBitmap) in the first cell of the sizer. The issue is that the image is cropped and has no scrolls.

The image can not be scaled to fit in the cell. This is not what I need for my program.

Uploaded code shows my last attempt to make it work. I tried to wrap the StaticBitmap in ScrolledPanel. This works until I update the Bitmap (function update_crnt_bm ) and then resize the frame.

Code

from PIL import Image
import wx
import wx.lib.scrolledpanel as scrl

class Button(wx.Button):
    def __init__(self, parent, label, action=None):
        super().__init__(parent, label=label)
        self.Bind(wx.EVT_BUTTON, action)

class ImgPanel(scrl.ScrolledPanel):
    '''Scrolled Panel with Image'''
    def __init__(self, parent, bitmap):
        super().__init__(parent)
        self.img_sizer = wx.BoxSizer(wx.VERTICAL)
        self.sbm = wx.StaticBitmap(self, bitmap=bitmap)
        self.img_sizer.Add(self.sbm, 1, wx.EXPAND)
        self.SetSizer(self.img_sizer)
        self.SetupScrolling()
        self.Bind(wx.EVT_SIZE, self.on_resize)

    def load_bm(self, bitmap):
        self.sbm.Destroy()
        self.sbm = wx.StaticBitmap(self, bitmap=bitmap)

    def on_resize(self, event):
        super().Layout()

class MainFrame(wx.Frame):
    def __init__(self, fns):
        super().__init__(None, title='Test multiple images')
        self.resized = False
        if len(fns) < 1:
            print('Please select at lease one image')
            exit(1)
        self.fns = fns
        self.init_panel()
        self.Show()

    def side_bar(self):
        sizer = wx.GridBagSizer()
        for i, fn in enumerate(self.fns):
            bttn = Button(self.panel, 'Image #'+str(i), self.getupd_crnt_bm(fn))
            sizer.Add(bttn, pos=(i,0))
        return sizer

    def init_panel(self):
        self.panel = wx.Panel(self)
        self.sizer = wx.GridBagSizer()
        self.sizer.Add(self.side_bar(), pos=(0,1))

        self.img_panel = ImgPanel(self.panel, self.open_bm(self.fns[0]))
        self.sizer.Add(self.img_panel, pos=(0,0), flag=wx.EXPAND)

        self.sizer.AddGrowableCol(0)
        self.sizer.AddGrowableRow(0)
        self.panel.SetSizerAndFit(self.sizer)

    def getupd_crnt_bm(self, fn):
        def update_crnt_bm(event):
            bm = self.img_to_bm(Image.open(fn))
            self.img_panel.load_bm(bm)
            self.current_bm = bm
        return update_crnt_bm

    def open_bm(self, fn):
        return self.img_to_bm(Image.open(fn))

    def img_to_bm(self, image):
        scale = 0.3
        image = image.resize((int(image.size[0]*scale), int(image.size[1]*scale)))
        width, height = image.size
        bm = wx.Bitmap.FromBuffer(width, height, image.tobytes())
        return bm

if __name__ == '__main__':
    fns = ['image0.jpg', 'image1.jpg', 'image2.jpg']
    app = wx.App()
    frame = MainFrame(fns)
    app.MainLoop()

Versions

  • Python 3.6.5
  • wx 4.0.1 msw (phoenix)
  • PIL 1.1.7
1

There are 1 answers

0
JakubP On

Answer to my own question

Leaving it here anyway so others can find this code.

Solution

It turns out that re-created StaticBitmap had to be added to a sizer once again. This is the load_bm function now. (Can't believe it was so obvious)

def load_bm(self, bitmap):
    self.sbm.Destroy()
    self.Scroll(0,0)
    self.sbm = wx.StaticBitmap(self, bitmap=bitmap)
    self.img_sizer.Add(self.sbm, 1, wx.EXPAND)

Additionally, the scroll status is set to 0. This forces the image to be added in upper-left corner of ScrolledPanel.