Search code examples
wxpythonpanel

Two panels side by side (one with TextCtrl) - wxPython


This is my code:

import wx #For graphics' interface
import os #For operating system compatibility


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

        #SETUP
        wx.Frame.__init__(self, parent, wx.ID_ANY, title = "MyTitle", size = (550,300))
        self.dirname=''

        #CREATE
        self.create_status_bar()
        self.create_menu_bar()
        self.create_text_panel()
        self.create_graphics_panel()

        self.SetAutoLayout(True)

        lc = wx.LayoutConstraints()
        lc.top.SameAs(self, wx.Top, 5)
        lc.left.SameAs(self, wx.Left, 5)
        lc.bottom.SameAs(self, wx.Bottom, 5)
        lc.right.PercentOf(self, wx.Right, 40)
        self.panelA.SetConstraints(lc)

        lc = wx.LayoutConstraints()
        lc.top.SameAs(self, wx.Top, 5)
        lc.left.RightOf(self.panelA, 5)
        lc.bottom.SameAs(self, wx.Bottom, 5)
        lc.right.SameAs(self, wx.Right, 5)
        self.panelB.SetConstraints(lc)


# FUNCTIONS
# ------------------------------------------------------------------------------
    def create_status_bar(self):
        self.CreateStatusBar() #A Statusbar at the bottom of the window


    def create_menu_bar(self):

    # File Menu
        filemenu= wx.Menu()

        menuOpen = filemenu.Append(wx.ID_OPEN, "&Open", "Open file to edit")
        filemenu.AppendSeparator()
        menuSave = filemenu.Append(wx.ID_SAVE, "&Save", "Save the file")
        menuSaveAs = filemenu.Append(wx.ID_SAVEAS, "Save &As", "Save the file with a new name")
        filemenu.AppendSeparator()
        menuExit = filemenu.Append(wx.ID_EXIT, "E&xit", "Terminate communication and close window")

    #The Menu Bar
        menuBar = wx.MenuBar()
        menuBar.Append(filemenu,"&File") #Adding the "File" menu to the 'menuBar'
        self.SetMenuBar(menuBar)  #Adding the 'menuBar' to the Frame content

    #Event binding
        self.Bind(wx.EVT_MENU, self.OnOpen, menuOpen)
        self.Bind(wx.EVT_MENU, self.OnExit, menuExit)
        self.Bind(wx.EVT_MENU, self.OnSave, menuSave)
        self.Bind(wx.EVT_MENU, self.OnSaveAs, menuSaveAs)


    def create_text_panel(self):
        self.panelA = wx.Panel(self)
        self.panelA.control = wx.TextCtrl(self.panelA, wx.ID_ANY, style = wx.TE_MULTILINE) #Text area with multiline
        self.panelA.SetBackgroundColour(wx.WHITE)


    def create_graphics_panel(self):
        self.panelB = wx.Panel(self)
        self.panelB.SetBackgroundColour(wx.BLACK)


# EVENTS
# ------------------------------------------------------------------------------
    def OnExit(self, event):
        self.Close(True) #Close the frame


    def OnOpen(self, event):
        dlg = wx.FileDialog(self, "Choose a file", self.dirname, "", "*.*", wx.OPEN)

        if dlg.ShowModal() == wx.ID_OK:
            self.filename = dlg.GetFilename()
            self.dirname = dlg.GetDirectory()
            f = open(os.path.join(self.dirname, self.filename), 'r')
            self.panelA.control.SetValue(f.read())
            f.close()
        dlg.Destroy()


    def OnSave(self, event):
        f = open(os.path.join(self.dirname, self.filename), 'w')
        f.write(self.panelA.control.GetValue())
        f.close()


    def OnSaveAs(self, event):
        file_choices = "TXT (*.txt)|*.txt"
        dlg = wx.FileDialog(self, message = "Save file as...", defaultDir = os.getcwd(), defaultFile = self.filename, wildcard = file_choices, style = wx.SAVE)

        if dlg.ShowModal() == wx.ID_OK:
            f = open(os.path.join(dlg.GetDirectory(), dlg.GetFilename()), 'w')
            f.write(self.panelA.control.GetValue())
            f.close()


# RUN!
# ------------------------------------------------------------------------------
if __name__ == '__main__':
    app = wx.PySimpleApp(False)
    app.frame = MainWindow(None, wx.ID_ANY, "tSock - Adaptation Technologies")
    app.frame.Show()
    app.MainLoop()

My problem is that I can't seem to get it to work the way I want it. I want to have two panels: the one on the left to work as a text editor and the other one on the right to receive input from the serial port (future work).

However, I can't seem to get the left panel to work properly. Is there something I'm missing?


Solution

  • You need to add a sizer to panelA and add the text control to the sizer so that it can expand and take up space appropriately:

    import wx #For graphics' interface
    import os #For operating system compatibility
    
    
    class MainWindow(wx.Frame):
        def __init__(self, parent, id, title):
    
            #SETUP
            wx.Frame.__init__(self, parent, wx.ID_ANY, title = "MyTitle", size = (550,300))
            self.dirname=''
    
            #CREATE
            self.create_status_bar()
            self.create_menu_bar()
            self.create_text_panel()
            self.create_graphics_panel()
    
            self.SetAutoLayout(True)
    
            lc = wx.LayoutConstraints()
            lc.top.SameAs(self, wx.Top, 5)
            lc.left.SameAs(self, wx.Left, 5)
            lc.bottom.SameAs(self, wx.Bottom, 5)
            lc.right.PercentOf(self, wx.Right, 40)
            self.panelA.SetConstraints(lc)
    
            lc = wx.LayoutConstraints()
            lc.top.SameAs(self, wx.Top, 5)
            lc.left.RightOf(self.panelA, 5)
            lc.bottom.SameAs(self, wx.Bottom, 5)
            lc.right.SameAs(self, wx.Right, 5)
            self.panelB.SetConstraints(lc)
    
    
    
    # FUNCTIONS
    # ------------------------------------------------------------------------------
        def create_status_bar(self):
            self.CreateStatusBar() #A Statusbar at the bottom of the window
    
    
        def create_menu_bar(self):
    
        # File Menu
            filemenu= wx.Menu()
    
            menuOpen = filemenu.Append(wx.ID_OPEN, "&Open", "Open file to edit")
            filemenu.AppendSeparator()
            menuSave = filemenu.Append(wx.ID_SAVE, "&Save", "Save the file")
            menuSaveAs = filemenu.Append(wx.ID_SAVEAS, "Save &As", "Save the file with a new name")
            filemenu.AppendSeparator()
            menuExit = filemenu.Append(wx.ID_EXIT, "E&xit", "Terminate communication and close window")
    
        #The Menu Bar
            menuBar = wx.MenuBar()
            menuBar.Append(filemenu,"&File") #Adding the "File" menu to the 'menuBar'
            self.SetMenuBar(menuBar)  #Adding the 'menuBar' to the Frame content
    
        #Event binding
            self.Bind(wx.EVT_MENU, self.OnOpen, menuOpen)
            self.Bind(wx.EVT_MENU, self.OnExit, menuExit)
            self.Bind(wx.EVT_MENU, self.OnSave, menuSave)
            self.Bind(wx.EVT_MENU, self.OnSaveAs, menuSaveAs)
    
    
        def create_text_panel(self):
            self.panelA = wx.Panel(self)
            self.panelA.control = wx.TextCtrl(self.panelA, wx.ID_ANY, style = wx.TE_MULTILINE) #Text area with multiline
            self.panelA.SetBackgroundColour(wx.WHITE)
    
            panelA_sizer = wx.BoxSizer(wx.VERTICAL)
            panelA_sizer.Add(self.panelA.control, 1, wx.EXPAND)
            self.panelA.SetSizer(panelA_sizer)
    
    
        def create_graphics_panel(self):
            self.panelB = wx.Panel(self)
            self.panelB.SetBackgroundColour(wx.BLACK)
    
    
    
    # EVENTS
    # ------------------------------------------------------------------------------
        def OnExit(self, event):
            self.Close(True) #Close the frame
    
    
        def OnOpen(self, event):
            dlg = wx.FileDialog(self, "Choose a file", self.dirname, "", "*.*", wx.OPEN)
    
            if dlg.ShowModal() == wx.ID_OK:
                self.filename = dlg.GetFilename()
                self.dirname = dlg.GetDirectory()
                f = open(os.path.join(self.dirname, self.filename), 'r')
                self.panelA.control.SetValue(f.read())
                f.close()
            dlg.Destroy()
    
    
        def OnSave(self, event):
            f = open(os.path.join(self.dirname, self.filename), 'w')
            f.write(self.panelA.control.GetValue())
            f.close()
    
    
        def OnSaveAs(self, event):
            file_choices = "TXT (*.txt)|*.txt"
            dlg = wx.FileDialog(self, message = "Save file as...", defaultDir = os.getcwd(), defaultFile = self.filename, wildcard = file_choices, style = wx.SAVE)
    
            if dlg.ShowModal() == wx.ID_OK:
                f = open(os.path.join(dlg.GetDirectory(), dlg.GetFilename()), 'w')
                f.write(self.panelA.control.GetValue())
                f.close()
    
    
    # RUN!
    # ------------------------------------------------------------------------------
    if __name__ == '__main__':
        app = wx.PySimpleApp(False)
        app.frame = MainWindow(None, wx.ID_ANY, "tSock - Adaptation Technologies")
        app.frame.Show()
        app.MainLoop()
    

    Also note that wx.PySimpleApp is deprecated. You should use wx.App(False) now. I would also recommend making a top level panel that the two other panels inherit from or perhaps use a splitter widget.

    Here's how to use a top-level panel:

    import wx #For graphics' interface
    import os #For operating system compatibility
    
    
    class MainWindow(wx.Frame):
        def __init__(self, parent, id, title):
    
            #SETUP
            wx.Frame.__init__(self, parent, wx.ID_ANY, title = "MyTitle", size = (550,300))
            self.dirname=''
    
            self.top_panel = wx.Panel(self)
            self.main_sizer = wx.BoxSizer(wx.HORIZONTAL)
    
            #CREATE
            self.create_status_bar()
            self.create_menu_bar()
            self.create_text_panel()
            self.create_graphics_panel()
    
            self.SetAutoLayout(True)
    
            lc = wx.LayoutConstraints()
            lc.top.SameAs(self, wx.Top, 5)
            lc.left.SameAs(self, wx.Left, 5)
            lc.bottom.SameAs(self, wx.Bottom, 5)
            lc.right.PercentOf(self, wx.Right, 40)
            self.panelA.SetConstraints(lc)
    
            lc = wx.LayoutConstraints()
            lc.top.SameAs(self, wx.Top, 5)
            lc.left.RightOf(self.panelA, 5)
            lc.bottom.SameAs(self, wx.Bottom, 5)
            lc.right.SameAs(self, wx.Right, 5)
            self.panelB.SetConstraints(lc)
    
            self.top_panel.SetSizer(self.main_sizer)
    
    
    # FUNCTIONS
    # ------------------------------------------------------------------------------
        def create_status_bar(self):
            self.CreateStatusBar() #A Statusbar at the bottom of the window
    
    
        def create_menu_bar(self):
    
        # File Menu
            filemenu= wx.Menu()
    
            menuOpen = filemenu.Append(wx.ID_OPEN, "&Open", "Open file to edit")
            filemenu.AppendSeparator()
            menuSave = filemenu.Append(wx.ID_SAVE, "&Save", "Save the file")
            menuSaveAs = filemenu.Append(wx.ID_SAVEAS, "Save &As", "Save the file with a new name")
            filemenu.AppendSeparator()
            menuExit = filemenu.Append(wx.ID_EXIT, "E&xit", "Terminate communication and close window")
    
        #The Menu Bar
            menuBar = wx.MenuBar()
            menuBar.Append(filemenu,"&File") #Adding the "File" menu to the 'menuBar'
            self.SetMenuBar(menuBar)  #Adding the 'menuBar' to the Frame content
    
        #Event binding
            self.Bind(wx.EVT_MENU, self.OnOpen, menuOpen)
            self.Bind(wx.EVT_MENU, self.OnExit, menuExit)
            self.Bind(wx.EVT_MENU, self.OnSave, menuSave)
            self.Bind(wx.EVT_MENU, self.OnSaveAs, menuSaveAs)
    
    
        def create_text_panel(self):
            self.panelA = wx.Panel(self.top_panel)
            self.panelA.control = wx.TextCtrl(self.panelA, wx.ID_ANY, style = wx.TE_MULTILINE) #Text area with multiline
            self.panelA.SetBackgroundColour(wx.WHITE)
    
            panelA_sizer = wx.BoxSizer(wx.VERTICAL)
            panelA_sizer.Add(self.panelA.control, 1, wx.EXPAND)
            self.panelA.SetSizer(panelA_sizer)
            self.main_sizer.Add(self.panelA, 1, wx.EXPAND)
    
    
    
        def create_graphics_panel(self):
            self.panelB = wx.Panel(self.top_panel)
            self.panelB.SetBackgroundColour(wx.BLACK)
            self.main_sizer.Add(self.panelB, 1, wx.EXPAND)
    
    
    # EVENTS
    # ------------------------------------------------------------------------------
        def OnExit(self, event):
            self.Close(True) #Close the frame
    
    
        def OnOpen(self, event):
            dlg = wx.FileDialog(self, "Choose a file", self.dirname, "", "*.*", wx.OPEN)
    
            if dlg.ShowModal() == wx.ID_OK:
                self.filename = dlg.GetFilename()
                self.dirname = dlg.GetDirectory()
                f = open(os.path.join(self.dirname, self.filename), 'r')
                self.panelA.control.SetValue(f.read())
                f.close()
            dlg.Destroy()
    
    
        def OnSave(self, event):
            f = open(os.path.join(self.dirname, self.filename), 'w')
            f.write(self.panelA.control.GetValue())
            f.close()
    
    
        def OnSaveAs(self, event):
            file_choices = "TXT (*.txt)|*.txt"
            dlg = wx.FileDialog(self, message = "Save file as...", defaultDir = os.getcwd(), defaultFile = self.filename, wildcard = file_choices, style = wx.SAVE)
    
            if dlg.ShowModal() == wx.ID_OK:
                f = open(os.path.join(dlg.GetDirectory(), dlg.GetFilename()), 'w')
                f.write(self.panelA.control.GetValue())
                f.close()
    
    
    # RUN!
    # ------------------------------------------------------------------------------
    if __name__ == '__main__':
        app = wx.PySimpleApp(False)
        app.frame = MainWindow(None, wx.ID_ANY, "tSock - Adaptation Technologies")
        app.frame.Show()
        app.MainLoop()
    

    Another approach, which I like the best, is to put each panel into its own class. I believe this gives you much more flexibility. Here's one way to do that:

    import wx #For graphics' interface
    import os #For operating system compatibility
    
    class TextPanel(wx.Panel):
    
        def __init__(self, parent):
            wx.Panel.__init__(self, parent)
            self.SetBackgroundColour(wx.WHITE)
    
            self.control = wx.TextCtrl(self, style = wx.TE_MULTILINE) #Text area with multiline
    
            sizer = wx.BoxSizer(wx.VERTICAL)
            sizer.Add(self.control, 1, wx.EXPAND)
            self.SetSizer(sizer)
    
    class GraphicsPanel(wx.Panel):
    
        def __init__(self, parent):
            wx.Panel.__init__(self, parent)
            self.SetBackgroundColour(wx.BLACK)
    
    
    class TopPanel(wx.Panel):
    
        def __init__(self, parent):
            wx.Panel.__init__(self, parent)
    
            main_sizer = wx.BoxSizer(wx.HORIZONTAL)
    
            text = TextPanel(self)
            main_sizer.Add(text, 1, wx.EXPAND)
    
            graphics = GraphicsPanel(self)
            main_sizer.Add(graphics, 1, wx.EXPAND)
    
            self.SetSizer(main_sizer)
    
    
    class MainWindow(wx.Frame):
        def __init__(self, parent, id, title):
    
            #SETUP
            wx.Frame.__init__(self, parent, wx.ID_ANY, title = "MyTitle", size = (550,300))
            self.dirname=''
    
            self.top_panel = TopPanel(self)
    
            #CREATE
            self.create_status_bar()
            self.create_menu_bar()
    
    
    # FUNCTIONS
    # ------------------------------------------------------------------------------
        def create_status_bar(self):
            self.CreateStatusBar() #A Statusbar at the bottom of the window
    
    
        def create_menu_bar(self):
    
        # File Menu
            filemenu= wx.Menu()
    
            menuOpen = filemenu.Append(wx.ID_OPEN, "&Open", "Open file to edit")
            filemenu.AppendSeparator()
            menuSave = filemenu.Append(wx.ID_SAVE, "&Save", "Save the file")
            menuSaveAs = filemenu.Append(wx.ID_SAVEAS, "Save &As", "Save the file with a new name")
            filemenu.AppendSeparator()
            menuExit = filemenu.Append(wx.ID_EXIT, "E&xit", "Terminate communication and close window")
    
        #The Menu Bar
            menuBar = wx.MenuBar()
            menuBar.Append(filemenu,"&File") #Adding the "File" menu to the 'menuBar'
            self.SetMenuBar(menuBar)  #Adding the 'menuBar' to the Frame content
    
        #Event binding
            self.Bind(wx.EVT_MENU, self.OnOpen, menuOpen)
            self.Bind(wx.EVT_MENU, self.OnExit, menuExit)
            self.Bind(wx.EVT_MENU, self.OnSave, menuSave)
            self.Bind(wx.EVT_MENU, self.OnSaveAs, menuSaveAs)
    
    # EVENTS
    # ------------------------------------------------------------------------------
        def OnExit(self, event):
            self.Close(True) #Close the frame
    
    
        def OnOpen(self, event):
            dlg = wx.FileDialog(self, "Choose a file", self.dirname, "", "*.*", wx.OPEN)
    
            if dlg.ShowModal() == wx.ID_OK:
                self.filename = dlg.GetFilename()
                self.dirname = dlg.GetDirectory()
                f = open(os.path.join(self.dirname, self.filename), 'r')
                self.panelA.control.SetValue(f.read())
                f.close()
            dlg.Destroy()
    
    
        def OnSave(self, event):
            f = open(os.path.join(self.dirname, self.filename), 'w')
            f.write(self.panelA.control.GetValue())
            f.close()
    
    
        def OnSaveAs(self, event):
            file_choices = "TXT (*.txt)|*.txt"
            dlg = wx.FileDialog(self, message = "Save file as...", defaultDir = os.getcwd(), defaultFile = self.filename, wildcard = file_choices, style = wx.SAVE)
    
            if dlg.ShowModal() == wx.ID_OK:
                f = open(os.path.join(dlg.GetDirectory(), dlg.GetFilename()), 'w')
                f.write(self.panelA.control.GetValue())
                f.close()
    
    
    # RUN!
    # ------------------------------------------------------------------------------
    if __name__ == '__main__':
        app = wx.PySimpleApp(False)
        app.frame = MainWindow(None, wx.ID_ANY, "tSock - Adaptation Technologies")
        app.frame.Show()
        app.MainLoop()