Search code examples
pythonwxpythonwxwidgets

Simple way to display thumbnails using wxPython


I am looking for a simple solution to display thumbnails using wxPython. This is not about creating the thumbnails. I have a directory of thumbnails and want to display them on the screen. I am purposely not using terms like (Panel, Frame, Window, ScrolledWindow) because I am open to various solutions.

Also note I have found multiple examples for displaying a single image, so referencing any such solution will not help me. The solution must be for displaying multiple images at the same time in wx.

It seems that what I want to do is being done in ThumbnailCtrl, but Andrea's code is complex and I cannot find the portion that does the display to screen. I did find a simple solution in Mark Lutz's Programming Python book, but while his viewer_thumbs.py example definitely has the simplicity that I am looking for, it was done using Tkinter.

So please any wx solution will be greatly appreciated.

EDIT: I am adding a link to one place where Mark Lutz's working Tkinter code can be found. Can anyone think of a wx equivalent?

http://codeidol.com/community/python/viewing-and-processing-images-with-pil/17565/#part-33


Solution

  • Not sure if I am supposed to answer my own question but I did find a solution to my problem and I wanted to share. I was using wx version 2.8. I found that in 2.9 and 3.0 there was a widget added called WrapSizer. Once I updated my version of wx to 3.0 that made the solution beyond simple. Here are the code snippets that matter.

        self.PhotoMaxWidth = 100
        self.PhotoMaxHeight = 100
    
        self.GroupOfThumbnailsSizer = wx.WrapSizer()      
    
        self.CreateThumbNails(len(ListOfPhotots),ListOfPhotots)
    
        self.GroupOfThumbnailsSizer.SetSizeHints(self.whateverPanel) 
        self.whateverPanel.SetSizer(self.GroupOfThumbnailsSizer)
    
        self.whateverPanel.Layout()
    
    
    def CreateThumbNails(self, n, ListOfFiles):
        thumbnails = []
        backgroundcolor = "white"
    
        for i in range(n):
    
            ThumbnailSizer = wx.BoxSizer(wx.VERTICAL)
            self.GroupOfThumbnailsSizer.Add(ThumbnailSizer, 0, 0, 0)
            thumbnails.append(ThumbnailSizer)
    
        for thumbnailcounter, thumbsizer in enumerate(thumbnails):
    
            image = Image.open(ListOfFiles[thumbnailcounter])
    
            image = self.ResizeAndCenterImage(image, self.PhotoMaxWidth, self.PhotoMaxHeight, backgroundcolor)
    
            img = self.pil_to_image(image)
    
            thumb= wx.StaticBitmap(self.timelinePanel, wx.ID_ANY, wx.BitmapFromImage(img))
    
            thumbsizer.Add(thumb, 0, wx.ALL, 5)
    
        return
    
    def pil_to_image(self, pil, alpha=True):
        """ Method will convert PIL Image to wx.Image """
        if alpha:
            image = apply( wx.EmptyImage, pil.size )
            image.SetData( pil.convert( "RGB").tostring() )
            image.SetAlphaData(pil.convert("RGBA").tostring()[3::4])
        else:
            image = wx.EmptyImage(pil.size[0], pil.size[1])
            new_image = pil.convert('RGB')
            data = new_image.tostring()
            image.SetData(data)
        return image
    
    def ResizeAndCenterImage(self, image, NewWidth, NewHeight, backgroundcolor):
        width_ratio = NewWidth / float(image.size[0])
        temp_height = int(image.size[1] * width_ratio)
        if temp_height < NewHeight:
            img2 = image.resize((NewWidth, temp_height), Image.ANTIALIAS)
        else:
            height_ratio = NewHeight / float(image.size[1])
            temp_width = int(image.size[0] * height_ratio)
            img2 = image.resize((temp_width, NewHeight), Image.ANTIALIAS)
    
        background = Image.new("RGB", (NewWidth, NewHeight), backgroundcolor)
        masterwidth = background.size[0]
        masterheight = background.size[1]
        subwidth = img2.size[0]
        subheight = img2.size[1]
        mastercenterwidth = masterwidth // 2
        mastercenterheight = masterheight // 2
        subcenterwidth = subwidth // 2
        subcenterheight = subheight // 2
        insertpointwidth = mastercenterwidth - subcenterwidth
        insertpointheight = mastercenterheight - subcenterheight
        background.paste(img2, (insertpointwidth, insertpointheight))
    
        return background
    

    I got the pil_to_image portion from another stackoverflow post and I wrote the ResizeAndCenterImage portion to make all of my thumbnails the same size while keeping the aspect ration intact and not do any cropping. The resize and center call can be skipped all together if you like.