0

In my app, I want to handle allocation / deallocation of sizers inside a scrolledPanel. In my first try, I was hiding / showing the contents of the sizers, but this was causing a lot of problems. The hidden sizers would "stay there", effectively ocuppying space, it would not update propely, etc. The solution that worked better was to destroy and create them over and over again.

But this that its problems too. The scrolledPanel blinks while I'm updating it and seems to be resource heavy. In my real app, I put the references of the buttons and checkboxes in lists and it becames more dificult to handle them.

So, if anyone has a better solution, I'm all ears!

I'm up to a hiding / showing solution! Something to reset the size of the scrolledPanel to accomodate only the sizer it currently has it would be nice too.

Thanks!

import wx
import wx.lib.scrolledpanel as scrolled

class WaterDataBase(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent)

        self.setupSizers()
        self.setupData()

    def setupSizers(self):
        masterSizer = wx.BoxSizer(wx.HORIZONTAL)
        itemsSizer = wx.BoxSizer(wx.VERTICAL)

        itemsSizer.Add(self.addSearchControl(), flag=wx.ALL, border=7)

        self.scrolledPanelSizer = wx.BoxSizer(wx.VERTICAL)
        self.scrolled_panel = scrolled.ScrolledPanel(self, wx.ID_ANY, size=(200, 200))
        self.scrolled_panel.SetSizer(self.scrolledPanelSizer)

        itemsSizer.Add(self.scrolled_panel, flag=wx.ALL, border=7)
        masterSizer.Add(itemsSizer)
        self.scrolled_panel.SetupScrolling()

        self.SetSizer(masterSizer)

    def addSearchControl(self):
        sizer = wx.BoxSizer(wx.HORIZONTAL)

        self.searchField = wx.TextCtrl(self, -1)
        self.searchField.Bind(wx.EVT_TEXT, self.OnSearched)
        sizer.Add(self.searchField)

        return sizer

    def setupData(self):
        self.words = "I'm trying to make this work, please. Let's keep it on! The day is beautiful today. Together we are stronger!".split()
        for word in self.words:
            self.addSizerToPanel(word)

    def createSizer(self, word):
        # Creates a sizer with a CheckBox and a StaticText to display.

        sizer = wx.BoxSizer(wx.HORIZONTAL)
        checkBox = wx.CheckBox(self.scrolled_panel, -1)
        text = wx.StaticText(self.scrolled_panel, -1, word)

        sizer.Add(checkBox, flag=wx.ALL, border=5)
        sizer.Add(text, flag=wx.LEFT, border=5)

        return sizer

    def addSizerToPanel(self, word):
        sizer = self.createSizer(word)
        self.scrolledPanelSizer.Add(sizer, flag=wx.ALL, border=5)

    def OnSearched(self, event):
        query = self.searchField.GetValue().lower()
        result = []

        # If query's empty, print all words
        if not query or query.isspace():
            for word in self.words:
                result.append(word)
        else:
            for word in self.words:
                if word.lower().find(query) != -1:
                    result.append(word)

        # Destroy all panel sizers and put exactly the ones we want.
        self.scrolled_panel.DestroyChildren()
        for word in result:
            self.addSizerToPanel(word)

        self.scrolled_panel.Layout()
        self.scrolled_panel.Scroll(0, 0) # Using this to cause the scrollPanel get back to the top.

app = wx.App()
frame = WaterDataBase(None).Show()
app.MainLoop()

So, it seems I've made it, finally. I still wants the advice about reseting the size of the scrolledPanel. xD

import wx
import wx.lib.scrolledpanel as scrolled

class Frame(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent)

        self.sizerRefs = []
        self.words = []

        self.setupSizers()
        self.setupData()

    def setupSizers(self):
        masterSizer = wx.BoxSizer(wx.HORIZONTAL)
        itemsSizer = wx.BoxSizer(wx.VERTICAL)

        itemsSizer.Add(self.addSearchControl(), flag=wx.ALL, border=7)

        self.scrolledPanelSizer = wx.BoxSizer(wx.VERTICAL)
        self.scrolled_panel = scrolled.ScrolledPanel(self, wx.ID_ANY, size=(200, 200))
        self.scrolled_panel.SetSizer(self.scrolledPanelSizer)

        itemsSizer.Add(self.scrolled_panel, flag=wx.ALL, border=7)
        masterSizer.Add(itemsSizer)
        self.scrolled_panel.SetupScrolling()

        self.SetSizer(masterSizer)

    def addSearchControl(self):
        sizer = wx.BoxSizer(wx.HORIZONTAL)

        self.searchField = wx.TextCtrl(self, -1)
        self.searchField.Bind(wx.EVT_TEXT, self.OnSearched)
        sizer.Add(self.searchField)

        return sizer

    def setupData(self):
        self.words = "I'm trying to make this work, please. Let's keep it on! The day is beautiful today. Together we are stronger!".split()

        for i in range(0, len(self.words)):
            self.addSizerToPanel(i)

    def createSizer(self, index):
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        checkBox = wx.CheckBox(self.scrolled_panel, -1)
        text = wx.StaticText(self.scrolled_panel, -1, self.words[index])

        sizer.Add(checkBox, flag=wx.ALL, border=5)
        sizer.Add(text, flag=wx.LEFT, border=5)

        self.sizerRefs.append(sizer)
        return sizer

    def addSizerToPanel(self, index):
        sizer = self.createSizer(index)
        self.scrolledPanelSizer.Add(sizer, flag=wx.ALL, border=5)

    def hideAllSizers(self):
        for sizer in self.sizerRefs:
            sizer.ShowItems(False)

    def unhideSizer(self, index):
        self.sizerRefs[index].ShowItems(True)

    def OnSearched(self, event):
        query = self.searchField.GetValue().lower()
        result = [] # Storing the indexes of the words found

        # If query's empty, print all words
        if not query or query.isspace():
            for i in range(0, len(self.words)):
                result.append(i)
        else:
            for i in range(0, len(self.words)):
                if self.words[i].lower().find(query) != -1:
                    result.append(i)

        # Hides all panel sizers and unhide exactly the ones we want.
        self.hideAllSizers()
        for i in range(0, len(result)):
            self.unhideSizer(result[i])

        self.scrolled_panel.Layout()
        self.scrolled_panel.Scroll(0, 0) # Using this to cause the scrollPanel get back to the top.

app = wx.App()
frame = Frame(None).Show()
app.MainLoop()
NeoFahrenheit
  • 347
  • 5
  • 16
  • 1
    It's not entirely clear what your question is, just as it isn't clear what your aim was for the code. You forgot to state that. However, adding `self.Layout()` to the end of `OnSearched` will, probably, be the answer to what you're looking for. – Rolf of Saxony Jun 16 '21 at 08:27
  • You forgot the self.Layout() as Rolf of Saxony told you. – Dan A.S. Jun 16 '21 at 08:43
  • Sorry if this wans't clear, but the question was how make the code better to hide and show the items on the scrolledPanel. Eventually I figure it out (see second code), so now is only a question if anyone has some advice to make it better. – NeoFahrenheit Jun 16 '21 at 12:40

0 Answers0