问题描述
我正在尝试创建一个垂直的图像缩略图列表,这些缩略图可能会覆盖数百/数千张图像。 wxPython/wxWidgets 中是否有推荐的策略可以有效地加载列表,以便不需要立即加载所有图像。在 iOS 上,UITableView
中有单元重用的概念,我不确定这里是否有类似的东西,或者推荐的解决方案是否只是预加载所有这些。我还考虑过加载默认图像,然后在单独的线程中加载图像。
这是一个原型,展示了我正在尝试完成的事情(红色框替换为图像缩略图)
import wx
from wx.lib.scrolledpanel import ScrolledPanel
eng = wx.App()
frame = wx.Frame(parent=None,title='wxPython')
main_panel = wx.Panel(frame)
main_sizer = wx.BoxSizer(wx.HORIZONTAL)
main_panel.SetSizer(main_sizer)
left_panel = ScrolledPanel(main_panel)
left_panel.SetupScrolling()
left_panel.SetBackgroundColour(wx.Colour(0,255,0))
left_panel_sizer = wx.BoxSizer(wx.VERTICAL)
left_panel.SetSizer(left_panel_sizer)
main_sizer.Add(left_panel,1,wx.ALL | wx.EXPAND,0)
right_panel = wx.Panel(main_panel)
right_panel.SetBackgroundColour(wx.Colour(0,255))
main_sizer.Add(right_panel,4,0)
for i in range(1000):
left_panel_sizer.Addspacer(10)
thumbnail = wx.Panel(left_panel)
thumbnail.SetMinSize((175,240))
thumbnail.SetBackgroundColour(wx.Colour(255,0))
left_panel_sizer.Add(thumbnail,3,wx.ALL | wx.CENTER)
left_panel_sizer.Addspacer(10)
frame.Show()
frame.SetSize(1440,875)
frame.CenterOnScreen()
eng.MainLoop()
解决方法
您应该避免创建数千个窗口。相反,您可以自己绘制图像——这也将允许您按需加载它们。
然后您可以轻松地在列表中包含数百万(或更多)项,例如参见wxHtmlListBox
使用这种方法。
根据 VZ's 的建议,我意识到仅手动绘制可见缩略图是最佳解决方案。
在 wxpython 中有几个类可以实现这一点:wx.VListBox
、wx.VScrolledWindow
或 wx.ScrolledWindow
wx.VListBox
提供了最简单的 API。您创建了一个自定义子类并实现了 OnMeasureItem
来指定单元格高度和 OnDrawItem
指定
仅适用于您的项目的绘图代码。这种方法的缺点是滚动会“锁定”在每个项目顶部的位置。 wx.VScrolledWindow
在锁定滚动位置时遇到了同样的问题,其 API 略有不同,可能在其他情况下有用。
wx.ScrolledWindow
是最有用的,因为它解决了锁定滚动位置的问题。但是只绘制可见的单元格需要进行一些计算。下面是实现这个的原型:
import wx
class ThumbnailView(wx.ScrolledWindow):
def __init__(self,*args,**kwargs):
wx.VScrolledWindow.__init__(self,**kwargs)
self.ScrollRate = 10
self.ThumbnailHeight = 100
self.NumThumbnails = 100000
self.SetVirtualSize(-1,self.ThumbnailHeight*self.NumThumbnails)
self.SetScrollRate(0,self.ScrollRate)
def OnDraw(self,dc):
width,height = self.GetSize()
# Calculate min and max thumbnails in view
min_visible_thumb = int((self.GetViewStart()[1]*self.ScrollRate) / self.ThumbnailHeight)
max_visible_thumb = min_visible_thumb + int(height / self.ThumbnailHeight) + 2
# TEMP - Print min/max visible thumbnails
print(f"min_visible_thumb = {min_visible_thumb}")
print(f"max_visible_thumb = {max_visible_thumb}")
print(f"height = {height}")
for n in range(min_visible_thumb,max_visible_thumb):
# Define the thumnail rectangle
r = wx.Rect(0,n*100,width,100)
# Set the color alternate between red,green,or blue
dc.SetBrush(wx.Brush(wx.Colour(255 * (n % 3 == 0),255 * (n % 3 == 1),255 * (n % 3 == 2))))
# Draw the background
dc.DrawRectangle(r)
# Draw the text label
dc.SetTextForeground(wx.WHITE)
dc.DrawLabel(str(n),r,wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL)
eng = wx.App()
frame = wx.Frame(parent=None,title='wxPython')
main_panel = wx.Panel(frame)
main_sizer = wx.BoxSizer(wx.HORIZONTAL)
main_panel.SetSizer(main_sizer)
left_panel = ThumbnailView(main_panel)
main_sizer.Add(left_panel,1,wx.ALL | wx.EXPAND,0)
right_panel = wx.Panel(main_panel)
main_sizer.Add(right_panel,4,0)
frame.Show()
frame.SetSize(1440,875)
frame.CenterOnScreen()
eng.MainLoop()
这是原型的截图:
这种方法可以很好地扩展到数千、数万或十万行,而只需要绘制显示的行。