Reputation: 332866
I am trying to create a dialog in which there are a few long descriptions, each followed by a short question with radio button answers. I'm laying my controls out with a GridBagSizer
(wxWidgets docs, wxPython docs), in which the long description spans all three columns, and the question and two radio button answers are each in their own columns.
I would like the answers to be aligned to the right, so I've tried passing flag=wx.EXPAND
when adding the StaticText
for the question to the layout. This doesn't seem to have the desired effect, however; the first column remains just large enough to fit the longest question, rather than filling the available space and pushing the radio buttons to the right.
import wx
class MyDialog(wx.Dialog):
def __init__(self, *args, **kwargs):
wx.Dialog.__init__(self, *args, **kwargs)
sizer = wx.GridBagSizer(5, 5)
sizer.SetEmptyCellSize((0,0))
sizer.AddGrowableCol(0)
for i in range(5):
description = wx.StaticText(self, -1, "This is a long description \
that may span several lines. Filler filler filler filler filler. More filler \
filler filler filler filler.")
description.Wrap(500)
question = wx.StaticText(self, -1, "Are you sure?")
yes = wx.RadioButton(self, -1, "Yes", style = wx.RB_GROUP)
no = wx.RadioButton(self, -1, "No")
sizer.Add(description, (i*3, 0), (1, 3))
sizer.Add(question, (i*3+1, 0), flag=wx.EXPAND)
sizer.Add(yes, (i*3+1, 1))
sizer.Add(no, (i*3+1, 2))
self.SetSizerAndFit(sizer)
self.Show()
app = wx.App(False)
dialog = MyDialog(None)
app.MainLoop()
I've also tried adding an extra spacer column, and setting wx.EXPAND
on that, but that doesn't help either. I've also tried setting wx.ALIGN_RIGHT
on the radio buttons, but as expected, that just causes the "No" button to be aligned to the right, as it's the third column that is taking up the rest of the available space.
Am I missing something here? Is it not possible to have one column in a GridBagSizer
expand to fill the available space, or am I doing it wrong? And if I'm doing it wrong, is it documented anywhere? References to appropriate documentation would be helpful.
Upvotes: 3
Views: 2424
Reputation: 3113
I tried to solve your problem using wx.Sizer.AddStretchSpacer() to fill in the gap. http://wxpython.org/docs/api/wx.Sizer-class.html#AddStretchSpacer
I got it to work but StretchSpacers appear to behave oddly in wx.GridBagSizers
sizer.Add(description, (i*3, 0), (1, 3))
sizer.Add(question, (i*3+1, 0), flag=wx.EXPAND)
sizer.AddStretchSpacer((i*3+1,1))
sizer.Add(yes, (i*3+1, 2), flag=wx.ALIGN_RIGHT)
sizer.Add(no, (i*3+1, 3))
Note how I need to align the Yes button to the right. I don't know why this is. No matter what column I insert the stretch spacer into I had to align the Yes button to the right (even if the spacer was inserted into column 0!). Also, the No button appears a bit too far to the right. I don't understand why the code behaves like this and it all seems a bit hackish so I strongly suggest you don't use this soltuion.
However, using a stretch spacer should allow you to create wx.BoxSizers with width relative to the width of the window. This would allow you to line up your buttons (since they are all the same width and the stretch spacer pushes them to the right side). So, just like @Mike Discoll breifly suggested, I refactored your code to use wx.BoxSizers
class MyDialog(wx.Dialog):
def __init__(self, *args, **kwargs):
wx.Dialog.__init__(self, *args, **kwargs)
sizer = wx.BoxSizer(wx.VERTICAL)
for i in range(5):
description = wx.StaticText(self, -1, "This is a long description \
that may span several lines. Filler filler filler filler filler. More filler \
filler filler filler filler.")
description.Wrap(500)
questionSizer = wx.BoxSizer(wx.HORIZONTAL)
question = wx.StaticText(self, -1, "Are you sure?")
yes = wx.RadioButton(self, -1, "Yes", style = wx.RB_GROUP)
no = wx.RadioButton(self, -1, "No")
sizer.Add(description)
questionSizer.Add(question)
questionSizer.AddStretchSpacer()
questionSizer.Add(yes)
questionSizer.Add(no)
sizer.Add(questionSizer, flag=wx.EXPAND)
self.SetSizerAndFit(sizer)
self.Show()
Which I think you'll find gives you exactly the result you wanted:
Note that you must add questionSizer with the wx.EXPAND flag because stretch spacers expand to fill te unused area. If you call sizer.Add() without wx.EXPAND then the width is set be default to just the length of the text and buttons (i.e. with no extra space for the stretch spacer to fill). Using wx.Expand sets the width to the width of sizer (which, because of description, we know will be around 500 pixels)
You can play round with the borders to get the spacing between items the way you like it.
---EDIT---
I just tried an experiment where I changed the description text to be a very short string (much less than 500 pixels) and due to the call self.SetSizerAndFit() call, the resulting window is very very small and visually unpleasing:
I think it would be better if you explictly set the size of the sizer to ensure a consistent minium width.
[...]
width = 500 #the desired minimum width
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.SetMinSize((width,1)) #ensures sizer will be minimum width
"""NOTE: the minimum size gets recalculated when new items are added.
i.e. if height exceeds 1 pixel or if width exceeds wdith, the sizer
will recalculate the minimum size"""
for i in range(5):
description = wx.StaticText(self, -1, "Short Description") #description is less than 500 pixels, Wrap() will have no effect.
description.Wrap(width)
[...]
Which results in this:
Upvotes: 2
Reputation: 33071
Part of the problem is that you're using SetSizerAndFit(). Try using just SetSizer(). That helps a lot. Personally, I prefer to nest BoxSizers as it gives me more granular control over the appearance of my widgets.
Upvotes: 1