How to use sizer's flags to place button right justified in a frame ?

Hi,

It’s my first time to use sizers manually (based on code generated by wxGlage).
Alas, I’m not able to set a button to a fixed distance from the right edge of a frame.
I have the below frame, where I want the “Cancel” button to appear exactly below the “Find” button.
(“Cancel” needs to be relative to the right edge, because the width of from_row_combo_box changes in my real application).

Outlook.jpg

However, even after reading http://www.wxpython.org/docs/api/wx.Sizer-class.html and various examples on the web, I still am unable to find the right combination of flags that will place the “Cancel” button under the “Find” button.

Has anyone experience with sizers, and can point me in the right direction ?

Thanks,
Ron.

$ cat -n tmp.py
1 #!/usr/bin/env python
2
3 import wx
4
5 class FilterFrame(wx.Frame):
6 def init(self, *args, **kwds):
7 kwds[“style”] = wx.DEFAULT_FRAME_STYLE
8 self.from_row_choices = kwds[“from_row_choices”]
9 del(kwds[“from_row_choices”])
10 wx.Frame.init(self, *args, **kwds)
11
12 self.find_what = “”
13 self.from_row_index = 0
14
15 self.find_what = wx.StaticText(self, -1, “Find what:”)
16
17 self.find_what_text_ctrl = wx.TextCtrl(self, -1, “”, style=wx.TE_PROCESS_ENTER|wx.TE_PROCESS_TAB|wx.TE_LINEWRAP|wx.TE_WORDWRAP)
18 self.find_button = wx.Button(self, wx.ID_FIND, “”)
19 self.from_row = wx.StaticText(self, -1, “From row:”)
20 self.from_row_combo_box = wx.ComboBox(self, -1, “1”, choices=self.from_row_choices, style=wx.CB_READONLY)
21 self.cancel_button = wx.Button(self, wx.ID_CANCEL, “”)
22
23 self.__set_properties()
24 self.__do_layout()
25
26 def __set_properties(self):
27 self.SetSize((360, 100))
28 self.find_what.SetMinSize((51, 13))
29 self.find_what_text_ctrl.SetMinSize((180, -1))
30 self.find_button.SetDefault()
31 self.from_row_combo_box.SetMinSize((-1, -1))
32 self.from_row_combo_box.SetSelection(self.from_row_index)
33
34 def __do_layout(self):
35 sizer_1 = wx.BoxSizer(wx.VERTICAL)
36 sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
37 sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
38 sizer_2.Add(self.find_what, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 10)
39 sizer_2.Add(self.find_what_text_ctrl, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 10)
40 sizer_2.Add(self.find_button, 0, wx.LEFT|wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, 15)
41 sizer_1.Add(sizer_2, 1, wx.EXPAND, 0)
42 sizer_3.Add(self.from_row, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 10)
43 sizer_3.Add(self.from_row_combo_box, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 12)
44 sizer_3.Add(self.cancel_button, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 15)
45 sizer_1.Add(sizer_3, 1, wx.EXPAND, 0)
46 self.SetSizer(sizer_1)
47 self.Layout()
48
49 # end of class FilterFrame
50
51 if name == “main”:
52 app = wx.App(redirect=False)
53 from_row_choices=[“0”, “1”, “2”, “3”, “4”]
54 Filter = FilterFrame(None, -1, “”, from_row_choices=from_row_choices)
55 Filter.Show()
56 app.MainLoop()

tmp.py (2.23 KB)

Ron Barak wrote:

Hi,

It's my first time to use sizers manually (based on code
generated by wxGlage).
Alas, I'm not able to set a button to a fixed distance from
the right edge of a frame.

I don't know if this is the best way, but this seems to work -

    def __do_layout(self):
        sizer_1 = wx.BoxSizer(wx.VERTICAL)
        sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_2.Add(self.find_what, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 10)
        sizer_2.Add(self.find_what_text_ctrl, 0,
wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 10)
        sizer_2.AddStretchSpacer(1) # this line added
# sizer_2.Add(self.find_button, 0,
wx.LEFT|wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, 15)
        sizer_2.Add(self.find_button, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL,
15)
        sizer_1.Add(sizer_2, 1, wx.EXPAND, 0)
        sizer_3.Add(self.from_row, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 10)
        sizer_3.Add(self.from_row_combo_box, 0,
wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 12)
        sizer_3.AddStretchSpacer(1) # this line added
        sizer_3.Add(self.cancel_button, 0,
wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 15)
        sizer_1.Add(sizer_3, 1, wx.EXPAND, 0)
        self.SetSizer(sizer_1)
        self.Layout()

I added spacers before the buttons, and set both the buttons' borders to
wx.RIGHT.

HTH

Frank Millman

Barak, Ron wrote:

Hi,

It's my first time to use sizers manually (based on code generated by wxGlage).
Alas, I'm not able to set a button to a fixed distance from the right edge of a frame.
I have the below frame, where I want the "Cancel" button to appear exactly below the "Find" button.
("Cancel" needs to be relative to the right edge, because the width of from_row_combo_box changes in my real application).

However, even after reading wxPython API Documentation — wxPython Phoenix 4.2.2 documentation and various examples on the web, I still am unable to find the right combination of flags that will place the "Cancel" button under the "Find" button.

Has anyone experience with sizers, and can point me in the right direction ?

Thanks,
Ron.

I usually create a spacer for this sort of thing. You usually have to experiment a little, but I got it to work on yours as follows:

<code>

sizer_3.Add(self.from_row_combo_box, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 12)
sizer_3.Add((160, 10)) # my spacer
sizer_3.Add(self.cancel_button, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 15)

</code>

Notice the tuple...I know I've done this another way so that it resized correctly, but I'm not finding my example at the moment...

···

-------------------
Mike Driscoll

Blog: http://blog.pythonlibrary.org

Mike Driscoll wrote:

Barak, Ron wrote:

Hi,

It's my first time to use sizers manually (based on code generated by wxGlage).
Alas, I'm not able to set a button to a fixed distance from the right edge of a frame.
I have the below frame, where I want the "Cancel" button to appear exactly below the "Find" button.
("Cancel" needs to be relative to the right edge, because the width of from_row_combo_box changes in my real application).

However, even after reading wxPython API Documentation — wxPython Phoenix 4.2.2 documentation and various examples on the web, I still am unable to find the right combination of flags that will place the "Cancel" button under the "Find" button.

Has anyone experience with sizers, and can point me in the right direction ?

Thanks,
Ron.

I usually create a spacer for this sort of thing. You usually have to experiment a little, but I got it to work on yours as follows:

<code>

sizer_3.Add(self.from_row_combo_box, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 12)
sizer_3.Add((160, 10)) # my spacer
sizer_3.Add(self.cancel_button, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 15)

</code>

Notice the tuple...I know I've done this another way so that it resized correctly, but I'm not finding my example at the moment...

-------------------
Mike Driscoll

It looks like I can just treat my tuple like a widget, so this works:

sizer_3.Add((160, 10), 1, wx.EXPAND)

Hopefully one of these ideas (or Frank's) will help.

Mike

Thanks for your solution Frank. It works perfectly and elegantly.
Bye,
Ron.

P.S.: After going through the "Placing widgets with sizers" chapter in "wxPython in Action" book,
I think I might have had an easier time if I had used a Grid bag sizer ;-(
However, then I would have missed the opportunity to learn about wxSizer::AddStretchSpacer :slight_smile:

···

-----Original Message-----
From: Frank Millman [mailto:frank@chagford.com]
Sent: Monday, March 23, 2009 16:53
To: wxpython-users@lists.wxwidgets.org
Subject: RE: [wxpython-users] How to use sizer's flags to
place button rightjustified in a frame ?

Ron Barak wrote:
>
> Hi,
>
> It's my first time to use sizers manually (based on code
generated by
> wxGlage).
> Alas, I'm not able to set a button to a fixed distance from
the right
> edge of a frame.

I don't know if this is the best way, but this seems to work -

    def __do_layout(self):
        sizer_1 = wx.BoxSizer(wx.VERTICAL)
        sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_2.Add(self.find_what, 0,
wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 10)
        sizer_2.Add(self.find_what_text_ctrl, 0,
wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 10)
        sizer_2.AddStretchSpacer(1) # this line added
# sizer_2.Add(self.find_button, 0,
wx.LEFT|wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, 15)
        sizer_2.Add(self.find_button, 0,
wx.RIGHT|wx.ALIGN_CENTER_VERTICAL,
15)
        sizer_1.Add(sizer_2, 1, wx.EXPAND, 0)
        sizer_3.Add(self.from_row, 0,
wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 10)
        sizer_3.Add(self.from_row_combo_box, 0,
wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 12)
        sizer_3.AddStretchSpacer(1) # this line added
        sizer_3.Add(self.cancel_button, 0,
wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 15)
        sizer_1.Add(sizer_3, 1, wx.EXPAND, 0)
        self.SetSizer(sizer_1)
        self.Layout()

I added spacers before the buttons, and set both the buttons'
borders to wx.RIGHT.

HTH

Frank Millman