Search code examples
user-interfacewxpythonsizer

wxPython - Adding a BoxSizer to a ScrolledPanel


I'm building a window where I want to build a really simple calendar. I the loop of _organizeData, every time there is a new month, I want to add some buttons to a GridSizer, which is inside a vertical box with a text on the top. I can't figure it out to add this vertical BoxSizer (vBox) to the scrollPanel. self.data will be a structre like this, a list of dictionaries:

[{'date': '14-03-2021', 'xyValues': [[01:00, 02:00, ...], [18.5, 17.2, ...]]}, ...]

import wx
import wx.lib.scrolledpanel as scrolled

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

        self.data = data
        self.consumption = []
        self.text = wx.StaticText(self, wx.ID_ANY, label="This is a test")
        self.scrollPanel = scrolled.ScrolledPanel(self, wx.ID_ANY, size=((400, 600)), style=wx.SUNKEN_BORDER)
        self.scrollPanel.SetupScrolling()

        self.topVerticalBox = wx.BoxSizer(wx.VERTICAL)
        self.topVerticalBox.Add(self.text, flag=wx.EXPAND)
        self.topVerticalBox.Add(self.scrollPanel)

        self.Center()

        self._organizeData()

    def _organizeData(self):

        currentMonth = ''

        for i in range(0, len(self.data)):
            words = self.data[i]['date'].split('-')  # words -> [0]day, [1]month and [2]year.

            if currentMonth != words[1]:
                currentMonth = words[1]
                vBox = wx.BoxSizer(wx.VERTICAL)
                # Name of the month / year.
                text = wx.StaticText(self, wx.ID_ANY, f"{(words[1])} of {words[2]}")
                # Grid where the button of the days will be added
                gridSizer = wx.GridSizer(rows=5, cols=5, hgap=5, vgap=5)

                vBox.Add(text, wx.ID_ANY)
                vBox.Add(gridSizer, wx.ID_ANY)


            # Create the button of the day and add it to the gridSizer.
            button = wx.Button(self, 1000 + i, label=words[0], size=((20, 20)))
            button.Bind(wx.EVT_BUTTON, self.OnButtonClicked)
            gridSizer.Add(button, border=5)

        self.SetSizerAndFit(self.topVerticalBox)


    def OnButtonClicked(self, event):
        """ Funcao chamada quando um botao e apertado. """

        event.GetEventObject()
        print(event.GetId())

app = wx.App()
frame = GraphCalendar(None, data=[{'date': '14-03-2021', 'xyValues': [['01:00', '02:00'], [18.5, 17.2]]}, {'date': '15-04-2021', 'xyValues': [['01:00', '02:00'], [19.5, 18.2]]}])
frame.Show()
app.MainLoop()

This is the desired output:

Intended result

This is what the code above produces:

enter image description here


Solution

  • I don't know whether this is the final solution but it should point you in the right direction.
    I've added an extra sizer (as mentioned in my comment) for the scrolled panel and removed the erroneous assignment of wx.ID_ANY to the proportion parameter when you added items to vBox ( Lord knows what the sizer thought of a proportion of something like -31000 ).

    You might want to consider restructuring your data, before you start, because as it is, it's a bit ungainly.

    import wx
    import wx.lib.scrolledpanel as scrolled
    
    class GraphCalendar(wx.Frame):
        def __init__(self, parent, data):
            wx.Frame.__init__(self, parent)
    
            self.data = data
            self.consumption = []
            self.text = wx.StaticText(self, wx.ID_ANY, label="This is a test\nof my text placement above a calendar of sorts")
            self.text.SetBackgroundColour("lightgreen")
            self.scrollPanel = scrolled.ScrolledPanel(self, wx.ID_ANY, size=((400, 600)), style=wx.SUNKEN_BORDER)
            self.scrollPanel.SetupScrolling()
    
            self.topVerticalBox = wx.BoxSizer(wx.VERTICAL)
            self.sp_vbox1 = wx.BoxSizer(wx.VERTICAL)
    
            self.scrollPanel.SetSizer(self.sp_vbox1)
            self._organizeData()
            
            self.topVerticalBox.Add(self.text, flag=wx.EXPAND)
            self.topVerticalBox.AddSpacer(10)
            self.topVerticalBox.Add(self.scrollPanel)
            self.SetSizer(self.topVerticalBox)
    
            self.Center()
    
        def _organizeData(self):
    
            currentMonth = ''
    
            for d in self.data:
                words = d['date'].split('-')  # words -> [0]day, [1]month and [2]year.
    
                if currentMonth != words[1]:
                    if currentMonth != '':
                        self.sp_vbox1.Add(vBox)
                    currentMonth = words[1]
                    vBox = wx.BoxSizer(wx.VERTICAL)
                    # Name of the month / year.
                    text = wx.StaticText(self.scrollPanel, wx.ID_ANY, f"{(words[1])} of {words[2]}")
                    # Grid where the button of the days will be added
                    gridSizer = wx.GridSizer(rows=5, cols=5, hgap=5, vgap=5)
    
                    vBox.Add(text)
                    vBox.Add(gridSizer)
    
    
                # Create the button of the day and add it to the gridSizer.
                button = wx.Button(self.scrollPanel, wx.ID_ANY, label=words[0], size=((60, 20)))
                button.Bind(wx.EVT_BUTTON, self.OnButtonClicked)
                gridSizer.Add(button, border=5)
    
            self.sp_vbox1.Add(vBox)
    
    
        def OnButtonClicked(self, event):
            """ Funcao chamada quando um botao e apertado. """
    
            event.GetEventObject()
            print(event.GetId())
    
    app = wx.App()
    frame = GraphCalendar(None, data=[{'date': '14-03-2021', 'xyValues': [['01:00', '02:00'], [18.5, 17.2]]}, {'date': '15-04-2021', 'xyValues': [['01:00', '02:00'], [19.5, 18.2]]}, {'date': '16-04-2021', 'xyValues': [['01:00', '02:00'], [19.5, 18.2]]}, {'date': '19-04-2021', 'xyValues': [['01:00', '02:00'], [19.5, 18.2]]}, {'date': '11-05-2021', 'xyValues': [['01:00', '02:00'], [19.5, 18.2]]}, {'date': '15-08-2021', 'xyValues': [['01:00', '02:00'], [19.5, 18.2]]}])
    frame.Show()
    app.MainLoop()
    

    enter image description here