Benco
Benco

Reputation: 67

scrolled panel with lazy loading in wxPython

I'm trying to implement a ScrolledPanel with lazy loading, which means that only visible widgets are loaded and added to the panel. Objects are then loaded as scrolling occurs (but I'm not there yet).

What I'm having an issue with is set up the scroll bar to its real size, which is the one it would have if the objects were all in the panel.

Note that all the objects in this proof of concept have the same size. In the real use case, it will almost be the case, with some objects being a little less high (which is why I use the max_row_height variable).

Here is my code. The height that should be applied to the vertical scrollbar is correctly computed, but I fail to apply it. I set up the panel's virtual size, which I thought was the right way, but it doesn't work.

import random
import wx
import wx.lib.scrolledpanel as scrolled
from wx.lib.buttons import GenButton
import math

########################################################################
class LazyLoadingScrolledPanel(scrolled.ScrolledPanel):
    def __init__(self, parent):
        scrolled.ScrolledPanel.__init__(self, parent, -1)
        
        self.sizer = wx.WrapSizer()

        wx.CallAfter(self.build, self)
        # wx.CallAfter(self.build)
        
    def build(self, evt):
        text = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"
        margin = 5
        client_size = self.GetClientSize()
        panel_width = client_size.width
        panel_height = client_size.height
        x, y = margin, margin  # Commencer avec une marge
        row_height = 0
        max_row_height = 0
        buttons_per_row = 0

        for index, letter in enumerate(text):
            btn = GenButton(self, label=letter)
            r, g, b = [random.randint(128, 255) for _ in range(3)]
            btn.SetBackgroundColour(wx.Colour(r, g, b))
            
            btn.Fit()
            button_size = btn.GetSize()
            total_button_width = button_size.width + 2 * margin
            total_button_height = button_size.height + 2 * margin
            
            if x + total_button_width > panel_width:
                # Passer à la ligne suivante
                x = margin
                y += row_height
                max_row_height = max(max_row_height, row_height)
                row_height = 0
                if buttons_per_row == 0:
                    buttons_per_row = index
                
            if y > panel_height:
                self.sizer.Detach(btn)
                btn.Destroy()
                break
            
            self.sizer.Add(btn, 0, wx.ALL, margin)
            x += total_button_width - margin
            
            row_height = max(row_height, total_button_height)
        
        total_rows = math.ceil(len(text) / buttons_per_row)
        total_height = int(total_rows * max_row_height)
        print(f"Total height for scrollbar: {total_height}")
        
        self.SetVirtualSize(panel_width, total_height)
        self.Layout()
        self.SetSizer(self.sizer)
        self.SetupScrolling()
        self.SetScrollRate(0, 20)

        

########################################################################
class TestFrame(wx.Frame):
    """"""

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, None, title="WrapSizers in ScrolledPanel", size=(400,500))
        panel = LazyLoadingScrolledPanel(self)
        self.Show()
    
#----------------------------------------------------------------------
if __name__ == "__main__":
    app = wx.App(False)
    frame = TestFrame()
    app.MainLoop()

Upvotes: 0

Views: 40

Answers (0)

Related Questions