Search code examples
pythonwxpython

wxPython Notebook Pages


I'm trying to add code to a notebook page. It works fine in a frame, but in a notebook page derived from Panel it does not. I need some help understanding panel and help fixing my code. Here is the code for the notebook page:

class PageOne(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)

        vbox_left = wx.BoxSizer(wx.VERTICAL)
        vbox_right = wx.BoxSizer(wx.VERTICAL)

        panel = wx.Panel(self, -1)
        hbox = wx.BoxSizer(wx.HORIZONTAL)

        driveList=["D:/", "E:/"]

        font = wx.Font(14, wx.SWISS, wx.NORMAL, wx.NORMAL)

        label = wx.StaticText(panel, -1, "Audio Source") # Add type/name of source
        label.SetFont(font)
        label.SetSize(label.GetBestSize())
        self.combo1 = wx.ComboBox(panel, style=wx.CB_DROPDOWN, choices=driveList)
        self.listbox = wx.ListBox(panel, 1, size=(380, 220))
        vbox_left.Add(label, 0, wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER_HORIZONTAL, 5)
        vbox_left.Add(self.combo1, 0, wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL | wx.LEFT | wx.RIGHT, 15)
        vbox_left.Add(self.listbox, 1, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, 15)

        label = wx.StaticText(panel, -1, "Local Disk") # Add disk name
        label.SetFont(font)
        label.SetSize(label.GetBestSize())
        self.combo2 = wx.ComboBox(panel, style=wx.CB_DROPDOWN, choices=driveList)
        self.listbox = wx.ListBox(panel, 0, size=(380, 220))
        vbox_right.Add(label, 0, wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER_HORIZONTAL, 5)
        vbox_right.Add(self.combo2, 0, wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL | wx.LEFT | wx.RIGHT, 15)       
        vbox_right.Add(self.listbox, 1, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, 15)

        hbox.Add(vbox_left, 0, wx.EXPAND | wx.LEFT, 20)
        hbox.Add(vbox_right, 0, wx.EXPAND | wx.RIGHT, 20)
        panel.SetSizer(hbox)
        panel.Layout()

How can I alter it to display on a notebook page right now it's just blank.

I have a second notebok page that's code is this:

class PageTwo(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        panel = wx.Panel(self, -1)

        font = wx.Font(14, wx.SWISS, wx.NORMAL, wx.NORMAL)

        vbox = wx.BoxSizer(wx.VERTICAL)

        label = wx.StaticText(panel, -1, "Audio Source") # Add type/name of source
        label.SetFont(font)
        label.SetSize(label.GetBestSize())

        vbox.Add(label, 0, wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER_HORIZONTAL, 5)

For that one I just see an A in the top right corner with a cutoff u as in the text I set "Audio Source". I don't understand positioning onthese notebook pages. If someone could give me a quick explanation of panels and notebook page positioning, and help me alter my code to work in the notebook page it would be a huge help. But mainly I just want to understand why my code doesn't work. I've put 2 hours in so far and am getting stuck.

Oh and the code that generates the notebook:

    nb = wx.Notebook(panel)

    # create the page windows as children of the notebook
    page1 = PageOne(nb)
    page2 = PageTwo(nb)
    page3 = PageThree(nb)

    # add the pages to the notebook with the label to show on the tab
    nb.AddPage(page1, "Page 1")
    nb.AddPage(page2, "Page 2")
    nb.AddPage(page3, "Page 3")

    hbox = wx.BoxSizer(wx.HORIZONTAL)
    hbox.Add(nb, 1, wx.EXPAND)
    hbox.Add(btnPanel, 0.6, wx.EXPAND | wx.RIGHT, 20)
    btnPanel.SetSizer(vbox)
    panel.SetSizer(hbox)
    panel.Layout() 

Thanks

EDIT: I was able to add a dialog to the notebook and have it work. But I can't get it to work as a panel. I want to add the code in PageOne into the notebook page, but all I get is a piece of a button smooshed into the top right corner of the tab page. How do you add items to a notebook page? I found another example where they use wx.SplitterWindow and then wthin that they create two Grids. However I can't seem to figure out how to put things into the page such a s listboxes, treebooks, etc. What is the correct method?

Here is the working code for the splitter:

import wx
import wx.grid as gridlib

class RegularPanel(wx.Panel):
def __init__(self, parent):
    """Constructor"""
    wx.Panel.__init__(self, parent)
    self.SetBackgroundColour("pink")

class GridPanel(wx.Panel):
def __init__(self, parent):
    """Constructor"""
    wx.Panel.__init__(self, parent)
    self.grid = gridlib.Grid(self, style=wx.BORDER_SUNKEN)
    self.grid.CreateGrid(25,8)

    sizer = wx.BoxSizer(wx.VERTICAL)
    sizer.Add(self.grid, 1, wx.EXPAND)
    self.SetSizer(sizer)

class MainPanel(wx.Panel):
def __init__(self, parent):
    """Constructor"""
    wx.Panel.__init__(self, parent)

    notebook = wx.Notebook(self)

    page = wx.SplitterWindow(notebook)
    notebook.AddPage(page, "Splitter")
    hSplitter = wx.SplitterWindow(page)

    panelOne = GridPanel(hSplitter)
    panelTwo = GridPanel(hSplitter)
    hSplitter.SplitVertically(panelOne, panelTwo)
    hSplitter.SetSashGravity(0.5)

    panelThree = RegularPanel(page)
    page.SplitHorizontally(hSplitter, panelThree)
    page.SetSashGravity(0.5)

    sizer = wx.BoxSizer(wx.VERTICAL)
    sizer.Add(notebook, 1, wx.EXPAND)
    self.SetSizer(sizer)

class MainFrame(wx.Frame):
def __init__(self):
    """Constructor"""
    wx.Frame.__init__(self, None, title="Nested Splitters",
                      size=(800,600))
    panel = MainPanel(self)
    self.Show()

if __name__ == "__main__":
    app = wx.App(False)
    frame = MainFrame()
    app.MainLoop()

I have tried to merge the code, trying to copy the last pattern and integrate my listboxes and treebooks. But it never seems to work. I just want to be able to place a treebook on a page and some listboxes on another. What am I missing?

Thanks!


Solution

  • Let's start by creating a simple notebook:

    import random
    import wx
    
    ########################################################################
    class TabPanel(wx.Panel):
        #----------------------------------------------------------------------
        def __init__(self, parent):
            """"""
            wx.Panel.__init__(self, parent=parent)
    
            colors = ["red", "blue", "gray", "yellow", "green"]
            self.SetBackgroundColour(random.choice(colors))
    
            btn = wx.Button(self, label="Press Me")
            sizer = wx.BoxSizer(wx.VERTICAL)
            sizer.Add(btn, 0, wx.ALL, 10)
            self.SetSizer(sizer)
    
    ########################################################################
    class DemoFrame(wx.Frame):
        """
        Frame that holds all other widgets
        """
    
        #----------------------------------------------------------------------
        def __init__(self):
            """Constructor"""        
            wx.Frame.__init__(self, None, wx.ID_ANY, 
                              "Notebook Tutorial",
                              size=(600,400)
                              )
            panel = wx.Panel(self)
            self.tab_num = 3
    
            self.notebook = wx.Notebook(panel)
            tabOne = TabPanel(self.notebook)
            self.notebook.AddPage(tabOne, "Tab 1")
    
            tabTwo = TabPanel(self.notebook)
            self.notebook.AddPage(tabTwo, "Tab 2")
    
            sizer = wx.BoxSizer(wx.VERTICAL)
            sizer.Add(self.notebook, 1, wx.ALL|wx.EXPAND, 5)
    
            btn = wx.Button(panel, label="Add Page")
            btn.Bind(wx.EVT_BUTTON, self.addPage)
            sizer.Add(btn)
    
            panel.SetSizer(sizer)
            self.Layout()
    
            self.Show()
    
        #----------------------------------------------------------------------
        def addPage(self, event):
            """"""
            new_tab = TabPanel(self.notebook)
            self.notebook.AddPage(new_tab, "Tab %s" % self.tab_num)
            self.tab_num += 1
    
    #----------------------------------------------------------------------
    if __name__ == "__main__":
        app = wx.App(False)
        frame = DemoFrame()
        app.MainLoop()
    

    You will note that we are creating a panel instance for each tab in the notebook. The notebook is the parent of the tab panel. Then we call the notebook's AddPage method to add the panel instance to the notebook along with the name of the tab.

    In your example, you have created a panel inside your tab's panel. The problem here is that this nested panel does not expand automatically when its parent is also a panel. Frankly, you don't need to nest the panel at all. So to make it work, just remove the nested panel and make each of the widget's parent the top level panel in PageOne. Here's an example using your PageOne class:

    import wx
    
    class PageOne(wx.Panel):
        def __init__(self, parent):
            wx.Panel.__init__(self, parent)
    
            vbox_left = wx.BoxSizer(wx.VERTICAL)
            vbox_right = wx.BoxSizer(wx.VERTICAL)
    
            hbox = wx.BoxSizer(wx.HORIZONTAL)
    
            driveList=["D:/", "E:/"]
    
            font = wx.Font(14, wx.SWISS, wx.NORMAL, wx.NORMAL)
    
            label = wx.StaticText(self, -1, "Audio Source") # Add type/name of source
            label.SetFont(font)
            label.SetSize(label.GetBestSize())
            self.combo1 = wx.ComboBox(self, style=wx.CB_DROPDOWN, choices=driveList)
            self.listbox = wx.ListBox(self, 1, size=(380, 220))
            vbox_left.Add(label, 0, wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER_HORIZONTAL, 5)
            vbox_left.Add(self.combo1, 0, wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL | wx.LEFT | wx.RIGHT, 15)
            vbox_left.Add(self.listbox, 1, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, 15)
    
            label = wx.StaticText(self, -1, "Local Disk") # Add disk name
            label.SetFont(font)
            label.SetSize(label.GetBestSize())
            self.combo2 = wx.ComboBox(self, style=wx.CB_DROPDOWN, choices=driveList)
            self.listbox = wx.ListBox(self, 0, size=(380, 220))
            vbox_right.Add(label, 0, wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER_HORIZONTAL, 5)
            vbox_right.Add(self.combo2, 0, wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL | wx.LEFT | wx.RIGHT, 15)       
            vbox_right.Add(self.listbox, 1, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, 15)
    
            hbox.Add(vbox_left, 0, wx.EXPAND | wx.LEFT, 20)
            hbox.Add(vbox_right, 0, wx.EXPAND | wx.RIGHT, 20)
            self.SetSizer(hbox)
            self.Layout()
    
    ########################################################################
    class MyFrame(wx.Frame):
        """"""
    
        #----------------------------------------------------------------------
        def __init__(self):
            """Constructor"""
            wx.Frame.__init__(self, None, title='Notebooks')
            panel = wx.Panel(self)
            notebook = wx.Notebook(panel)
            page_one = PageOne(notebook)
            notebook.AddPage(page_one, 'Page 1')
    
            main_sizer = wx.BoxSizer(wx.VERTICAL)
            main_sizer.Add(notebook, 1, wx.EXPAND)
            panel.SetSizer(main_sizer)
            self.Show()
    
    
    if __name__ == '__main__':
        app = wx.App(False)
        frame = MyFrame()
        app.MainLoop()
    

    Hopefully this example will help you see how to finish up your code.