Psionman
Psionman

Reputation: 3719

wx python how to place a button on a frame

I have two buttons on a panel. I want one on the left and one on the right. There must be a simple way but I can't see it (the (400, 0) spacer is just an example; it should work on any panel)

import wx


class MainFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1,
                          'Demonstrate wxPython button')
        self.panel = MainPanel(self)
        self.Fit()
        self.Centre()
        self.Show()


class MainPanel(wx.Panel):
    def __init__(self, frame):
        wx.Panel.__init__(self, frame)

        # Button
        button_sizer = self._button_sizer(frame)

        # Main sizer
        main_sizer = wx.BoxSizer(wx.VERTICAL)
        main_sizer.Add((400, 0))
        main_sizer.Add(button_sizer)
        self.SetSizer(main_sizer)
        self.Fit()

    def _button_sizer(self, frame):
        cmd_save = wx.Button(self, wx.ID_SAVE)
        cmd_cancel = wx.Button(self, wx.ID_CANCEL)
        button_sizer = wx.BoxSizer(wx.HORIZONTAL)
        button_sizer.Add(cmd_save)
        button_sizer.Add(cmd_cancel, flag=wx.ALIGN_RIGHT)
        return button_sizer


if __name__ == '__main__':
    screen_app = wx.App()
    main_frame = MainFrame()
    screen_app.MainLoop()

(Sorry about this; StackOverflow want more text)

Lorem ipsum dolor sit amet, porttitor donec, eget dolor tempor imperdiet, dignissim a sit wisi sed, congue sit accumsan aliquam urna fusce. Placerat vel ligula curabitur in nostra nunc, lorem lorem morbi in aliquet. Etiam ultricies ante sed at aenean id, ligula nibh aenean fusce sapien, ipsum felis sapien eu, mollis ut tempus odio suspendisse fames. A massa wisi sed nunc maecenas pretium, massa duis vitae non rhoncus nunc, orci sit maecenas ut, aliquet amet, vitae sit. Quam velit rutrum justo varius felis ligula, ut habitasse mauris, platea nunc. Et tincidunt vel, libero vitae aliquet donec suspendisse arcu, faucibus orci. Praesent mollis diam eu justo, quam diam arcu vel tincidunt. Aliquam eu fusce ipsum, ante turpis sociosqu, quis posuere pellentesque in pellentesque, nulla sit, phasellus lorem inceptos. Sociis ornare quam magnis eget cursus, ut pretium, velit vitae et sit vivamus, mi malesuada at lectus amet amet vitae. Convallis tristique gravida cras aenean, amet risus sem vehicula ac lacinia et, elit ac, magna eget ut.

Upvotes: 0

Views: 1235

Answers (2)

Mike Driscoll
Mike Driscoll

Reputation: 33111

You don't want to add your buttons to the frame itself. The frame should only have one child, a panel. In this case, its only child should be an instance of your MainPanel class. You could just change your call to _button_sizer to the following:

button_sizer = self._button_sizer(self)

Note that here we are passing the _button_sizer the panel as its parent instead of the frame.

Of course, you can also move the creation of the buttons completely outside of the class if you want to:

import wx

def save_cancel(parent):
    cmd_save = wx.Button(parent, wx.ID_SAVE)
    cmd_cancel = wx.Button(parent, wx.ID_CANCEL)
    button_sizer = wx.BoxSizer(wx.HORIZONTAL)
    button_sizer.Add(cmd_save)
    button_sizer.Add(cmd_cancel, flag=wx.ALIGN_RIGHT)
    return button_sizer

class MainFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1,
                          'Demonstrate wxPython button')
        self.panel = MainPanel(self)
        self.Fit()
        self.Centre()
        self.Show()


class MainPanel(wx.Panel):
    def __init__(self, frame):
        wx.Panel.__init__(self, frame)

        # Button
        button_sizer = save_cancel(self)

        # Main sizer
        main_sizer = wx.BoxSizer(wx.VERTICAL)
        main_sizer.Add((400, 0))
        main_sizer.Add(button_sizer)
        self.SetSizer(main_sizer)
        self.Fit()


if __name__ == '__main__':
    screen_app = wx.App()
    main_frame = MainFrame()
    screen_app.MainLoop()

This will make binding events trickier, but it's one interesting way to make your code a bit more modular as well.

If you want the buttons to be separate, then you add a StretchSpacer or a tuple like (-1, -1) (see Rolf's answer). Here's an example using the StretchSpacer:

import wx



class MainFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1,
                          'Demonstrate wxPython button')
        self.panel = MainPanel(self)
        self.Fit()
        self.Centre()
        self.Show()


class MainPanel(wx.Panel):
    def __init__(self, frame):
        wx.Panel.__init__(self, frame)

        # Button
        button_sizer = self.save_cancel()

        # Main sizer
        main_sizer = wx.BoxSizer(wx.VERTICAL)
        main_sizer.Add((400, 0))
        main_sizer.Add(button_sizer, proportion=1, flag=wx.EXPAND)
        self.SetSizer(main_sizer)
        self.Fit()

    def save_cancel(self):
        cmd_save = wx.Button(self, wx.ID_SAVE)
        cmd_cancel = wx.Button(self, wx.ID_CANCEL)
        button_sizer = wx.BoxSizer(wx.HORIZONTAL)
        button_sizer.Add(cmd_save)
        button_sizer.AddStretchSpacer()
        button_sizer.Add(cmd_cancel, flag=wx.ALIGN_RIGHT)
        return button_sizer    


if __name__ == '__main__':
    screen_app = wx.App()
    main_frame = MainFrame()
    screen_app.MainLoop()

Upvotes: 0

Rolf of Saxony
Rolf of Saxony

Reputation: 22458

I have always found the the sizer element proportion is your friend in cases like these. Which defines how much room a certain element should take up in relation to others.
Here is your code, with the proportion option being used.

import wx
class MainFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1, 'Demonstrate wxPython button')
        self.panel = MainPanel(self)
       # self.Fit()
        self.Centre()
        self.Show()

class MainPanel(wx.Panel):
    def __init__(self, frame):
        wx.Panel.__init__(self, frame)
        # Button
        button_sizer = self._button_sizer(frame)
        # Main sizer
        main_sizer = wx.BoxSizer(wx.VERTICAL)
        main_sizer.Add(button_sizer,proportion=1, flag=wx.EXPAND)
        self.SetSizer(main_sizer)
        self.Fit()

    def _button_sizer(self, frame):
        cmd_save = wx.Button(self, wx.ID_SAVE)
        cmd_cancel = wx.Button(self, wx.ID_CANCEL)
        button_sizer = wx.BoxSizer(wx.HORIZONTAL)
        button_sizer.Add(cmd_save)
        button_sizer.Add((-1, -1), proportion=1)
        button_sizer.Add(cmd_cancel)
        return button_sizer

if __name__ == '__main__':
    screen_app = wx.App()
    main_frame = MainFrame()
    screen_app.MainLoop()

Upvotes: 1

Related Questions