wxPython/wxWidgets 带有缩略图的超长滚动区域
wxPython/wxWidgets very long scroll area with thumbnails
我正在尝试创建一个垂直的图像缩略图列表,可能会达到 hundreds/thousands 个图像。 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,0,255))
main_sizer.Add(right_panel, 4, wx.ALL | wx.EXPAND, 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,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()
您应该避免创建数千个 windows。相反,您可以自己绘制图像——这样您也可以按需加载它们。
然后您可以轻松地在列表中拥有数百万(或更多)项目,例如参见wxHtmlListBox
使用这种方法。
按照的建议,我意识到只手动绘制可见的缩略图是最好的解决方案。
有几个 类 可以在 wxpython 中完成此操作:wx.VListBox
、wx.VScrolledWindow
或 wx.ScrolledWindow
wx.VListBox
提供了最简单的API。您创建了一个自定义子类并实现了 OnMeasureItem
来指定单元格高度并 OnDrawItem
指定
仅适用于您的项目的绘图代码。这种方法的缺点是滚动会 'lock' 在每个项目的顶部。 wx.VScrolledWindow
与锁定滚动位置有同样的问题,但略有不同 API 这可能在其他情况下有用。
wx.ScrolledWindow
是最有用的,因为它解决了锁定滚动位置的问题。但是只绘制可见的单元格需要一些计算。下面是实现这个的原型:
import wx
class ThumbnailView(wx.ScrolledWindow):
def __init__(self, *args, **kwargs):
wx.VScrolledWindow.__init__(self, *args, **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, wx.ALL | wx.EXPAND, 0)
frame.Show()
frame.SetSize(1440,875)
frame.CenterOnScreen()
eng.MainLoop()
原型截图如下:
这种方法可以很好地扩展到数千、数万或十万行,而只需要绘制显示的行。
我正在尝试创建一个垂直的图像缩略图列表,可能会达到 hundreds/thousands 个图像。 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,0,255))
main_sizer.Add(right_panel, 4, wx.ALL | wx.EXPAND, 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,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()
您应该避免创建数千个 windows。相反,您可以自己绘制图像——这样您也可以按需加载它们。
然后您可以轻松地在列表中拥有数百万(或更多)项目,例如参见wxHtmlListBox
使用这种方法。
按照
有几个 类 可以在 wxpython 中完成此操作:wx.VListBox
、wx.VScrolledWindow
或 wx.ScrolledWindow
wx.VListBox
提供了最简单的API。您创建了一个自定义子类并实现了 OnMeasureItem
来指定单元格高度并 OnDrawItem
指定
仅适用于您的项目的绘图代码。这种方法的缺点是滚动会 'lock' 在每个项目的顶部。 wx.VScrolledWindow
与锁定滚动位置有同样的问题,但略有不同 API 这可能在其他情况下有用。
wx.ScrolledWindow
是最有用的,因为它解决了锁定滚动位置的问题。但是只绘制可见的单元格需要一些计算。下面是实现这个的原型:
import wx
class ThumbnailView(wx.ScrolledWindow):
def __init__(self, *args, **kwargs):
wx.VScrolledWindow.__init__(self, *args, **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, wx.ALL | wx.EXPAND, 0)
frame.Show()
frame.SetSize(1440,875)
frame.CenterOnScreen()
eng.MainLoop()
原型截图如下:
这种方法可以很好地扩展到数千、数万或十万行,而只需要绘制显示的行。