使用wxPython显示缩略图的简单方法

1 投票
3 回答
1987 浏览
提问于 2025-04-17 22:35

我在找一个简单的方法,用wxPython来显示缩略图。这不是关于如何创建缩略图的问题。我有一个存放缩略图的文件夹,想把它们显示在屏幕上。我故意不使用像(面板、框架、窗口、滚动窗口)这样的术语,因为我对各种解决方案都持开放态度。

另外,我发现了很多关于显示单张图片的例子,所以提到这些解决方案对我没有帮助。我的需求是要同时显示多张图片。

看起来我想做的事情可以通过ThumbnailCtrl来实现,但Andrea的代码比较复杂,我找不到负责在屏幕上显示的那部分。我在Mark Lutz的《Programming Python》一书中找到了一个简单的解决方案,但他的viewer_thumbs.py例子虽然简单,但使用的是Tkinter。

所以,如果有任何wx的解决方案,我将非常感激。

补充:我添加了一个链接,里面有Mark Lutz的Tkinter代码。有没有人能想到wx的对应解决方案呢?

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

3 个回答

0

我建议你把它们显示为 wx.Image,放在一个框架里。

http://www.wxpython.org/docs/api/wx.Image-class.html

根据这个类的介绍:“这是一个平台无关的图像类。你可以通过数据创建图像,或者使用 wx.Bitmap.ConvertToImage,或者从多种格式的文件中加载图像。它提供了一些功能,可以设置和获取图像的像素,所以可以用来做一些基本的图像处理。”

看起来这个方法应该能满足你的需求,除非我漏掉了什么。

2

我建议你使用ThumbNailCtrl这个小部件:http://wxpython.org/Phoenix/docs/html/lib.agw.thumbnailctrl.html。在wxPython的演示中有个不错的例子。或者你也可以参考文档中的这个例子。需要注意的是,ThumbNailCtrl需要安装Python图像库。

import os

import wx
import wx.lib.agw.thumbnailctrl as TC

class MyFrame(wx.Frame):

    def __init__(self, parent):

        wx.Frame.__init__(self, parent, -1, "ThumbnailCtrl Demo")

        panel = wx.Panel(self)

        sizer = wx.BoxSizer(wx.VERTICAL)

        thumbnail = TC.ThumbnailCtrl(panel, imagehandler=TC.NativeImageHandler)
        sizer.Add(thumbnail, 1, wx.EXPAND | wx.ALL, 10)

        thumbnail.ShowDir(os.getcwd())
        panel.SetSizer(sizer)


# our normal wxApp-derived class, as usual

app = wx.App(0)

frame = MyFrame(None)
app.SetTopWindow(frame)
frame.Show()

app.MainLoop()

只需要把thumbnail.ShowDir(os.getcwd())这一行改成指向你电脑上正确的文件夹。

我还写了一篇关于查看照片的文章,地址在这里:http://www.blog.pythonlibrary.org/2010/03/26/creating-a-simple-photo-viewer-with-wxpython/。不过那篇文章没有使用缩略图。

2

我不太确定自己是否应该回答自己的问题,但我找到了解决办法,想和大家分享一下。我之前用的是wx版本2.8。后来我发现,在2.9和3.0版本中新增了一个叫做WrapSizer的小工具。于是我把wx更新到3.0版本,这样解决问题就变得非常简单了。下面是相关的代码片段。

    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

我从另一个StackOverflow的帖子中得到了pil_to_image的部分代码,而ResizeAndCenterImage的部分是我自己写的,目的是让我的所有缩略图大小一致,同时保持图片的比例,不进行裁剪。如果你愿意,可以完全不调用resize和center的部分。

撰写回答