HowTo : Layout widgets with Sizers - mcorino/wxRuby3 GitHub Wiki

In this HowTo we will take a look at Layout Management in wxRuby, and explain how we can use advanced features and sizers to correctly position widgets inside a wxRuby window.
Instead of "Absolute Positioning", we will use wxRuby’s Sizers, which were designed to help place widgets in a specific manner/layout. There are various sizer classes in wxRuby, each discussed briefly here with an example.
Absolute positioning, also known as fixed positioning, uses explicit coordinates when placing widgets. This results in a “fixed position” of the widget, which will not adapt to any changes in the screen size.
Furthermore, making changes to the layout with absolute positioning is trickier once you have a lot of widgets in your window. On the other hand, with Sizers you can change the Sizer’s settings, and all the widgets in it will be effected as well.
Another major advantage of Sizers, is that you can place a Sizer within another, allowing for complex layout patterns.
A small example using absolute positioning.
require 'wx'
class MyWindow < Wx::Frame
def initialize(title)
super(nil, title: title)
@panel = Wx::Panel.new(self)
text = Wx::StaticText.new(@panel, label: 'Hello World', pos: [50, 50])
button = Wx::Button.new(@panel, label: 'Press Me', pos: [200, 50])
rb = Wx::RadioButton.new(@panel, label: 'Pizza', pos: [50, 120])
cb = Wx::ComboBox.new(@panel, value: 'Kittens', pos: [200, 120])
centre
end
end
Wx::App.run do
window = MyWindow.new("wxRuby Sizer Guide")
window.show
end
Output of the above code:
The steps for creating a basic Sizer are fairly simple.
- First, create the Sizer you want.
- Create a few widgets.
- Insert them into the Sizer using the #add method.
Remember, you can create "nested sizers" by simply creating (a) sizer(s) and inserting into another sizer. This allows for greater flexibility and customizability in widget layouts. The below example will demonstrate this.
Furthermore, the #add method has three common arguments
which you’ll find on almost all Sizers.
The first is proportion
, which controls how much the widgets grows if the window
is re-sized. If the proportion is zero, then it won’t change. If it’s 1 or above, it will. Values above 1 are used to
decide the ratio with which the widget will grow, relative to the others.
The flag
parameter is used to enable certain options, whereas the border
parameter is used to define the padding
between widgets/rows/columns in the sizers. The border requires the flag parameter to have certain flags enabled to actually
work (such as Wx::Direction::ALL, Wx::Dirtection::BOTTOM etc).
An example on how to use the wxRuby BoxSizer (follow the link for full tutorial and explanation).
require 'wx'
class MyWindow < Wx::Frame
def initialize(title)
super(nil, title: title)
@panel = Wx::Panel.new(self)
sizer = Wx::BoxSizer.new(Wx::VERTICAL) # or Wx::VBoxSizer.new
#-----------------------
sub_sizer1 = Wx::BoxSizer.new(Wx::HORIZONTAL) # or Wx::HBoxSizer.new
text1 = Wx::StaticText.new(@panel, label: 'Username: ')
sub_sizer1.add(text1, Wx::SizerFlags.new.border(Wx::ALL, 5))
text2 = Wx::TextCtrl.new(@panel)
sub_sizer1.add(text2, Wx::SizerFlags.new(1).border(Wx::ALL, 5))
#-----------------------
#-----------------------
sub_sizer2 = Wx::HBoxSizer.new
text3 = Wx::StaticText.new(@panel, label: 'Password: ')
sub_sizer2.add(text3, Wx::SizerFlags.new.border(Wx::ALL, 5))
text4 = Wx::TextCtrl.new(@panel)
sub_sizer2.add(text4, Wx::SizerFlags.new(1).border(Wx::ALL, 5))
#-----------------------
sizer.add(sub_sizer1, Wx::SizerFlags.new.expand.border(Wx::TOP|Wx::LEFT, 10))
sizer.add(sub_sizer2, Wx::SizerFlags.new.expand.border(Wx::TOP|Wx::LEFT, 10))
@panel.sizer = sizer
centre
end
end
Wx::App.run do
window = MyWindow.new("wxRuby Sizer Guide")
window.show
end
Output of the above code:
An example on how to use the wxRuby StaticBoxSizer (follow the link for full tutorial).
require 'wx'
class MyWindow < Wx::Frame
def initialize(title)
super(nil, title: title)
@panel = Wx::Panel.new(self)
sizer = Wx::BoxSizer.new(Wx::VERTICAL) # or Wx::VBoxSizer.new
sbsizer = Wx::StaticBoxSizer.new(Wx::StaticBox.new(@panel, label: 'Box'), Wx::VERTICAL)
button1 = Wx::Button.new(@panel, label: 'Button 1')
sbsizer.add(button1, Wx::SizerFlags.new.border(Wx::LEFT|Wx::RIGHT|Wx::TOP, 5))
button2 = Wx::Button.new(@panel, label: 'Button 2')
sbsizer.add(button2, Wx::SizerFlags.new.border(Wx::LEFT|Wx::RIGHT|Wx::BOTTOM, 5))
sizer.add(sbsizer, Wx::SizerFlags.new.border(Wx::ALL, 10))
@panel.sizer = sizer
centre
end
end
Wx::App.run do
window = MyWindow.new("wxRuby Sizer Guide")
window.show
end
Output of the above code:
An example on how to use the wxRuby GridSizer (Follow link for full tutorial).
require 'wx'
class MyWindow < Wx::Frame
def initialize(title)
super(nil, title: title)
@panel = Wx::Panel.new(self)
grid = Wx::GridSizer.new(3, 3, 5, 5)
[ [Wx::Button.new(@panel, label: "1"), 0, Wx::EXPAND],
[Wx::Button.new(@panel, label: "2"), 0, Wx::EXPAND],
[Wx::Button.new(@panel, label: "3"), 0, Wx::EXPAND],
[Wx::Button.new(@panel, label: "4"), 0, Wx::EXPAND],
[Wx::Button.new(@panel, label: "5"), 0, Wx::EXPAND],
[Wx::Button.new(@panel, label: "6"), 0, Wx::EXPAND],
[Wx::Button.new(@panel, label: "7"), 0, Wx::EXPAND],
[Wx::Button.new(@panel, label: "8"), 0, Wx::EXPAND],
[Wx::Button.new(@panel, label: "9"), 0, Wx::EXPAND]
].each { |btn, prop, f| grid.add(btn, prop, f) }
@panel.sizer = grid
centre
end
end
Wx::App.run do
window = MyWindow.new("wxRuby Sizer Guide")
window.show
end
Output of the above code:
An example on how to use the wxRuby FlexGridSizer (Follow link for full tutorial).
require 'wx'
class MyWindow < Wx::Frame
def initialize(title)
super(nil, title: title)
@panel = Wx::Panel.new(self)
wrapper = Wx::HBoxSizer.new
sizer = Wx::FlexGridSizer.new(3, 2, 5, 5)
[[Wx::StaticText.new(@panel, label: 'Username')],
[Wx::TextCtrl.new(@panel), 0, Wx::EXPAND],
[Wx::StaticText.new(@panel, label: 'Password')],
[Wx::TextCtrl.new(@panel), 0, Wx::EXPAND],
[Wx::StaticText.new(@panel, label: 'Address')],
[Wx::TextCtrl.new(@panel, style: Wx::TE_MULTILINE|Wx::TE_NO_VSCROLL), 0, Wx::EXPAND]
].each { |args| sizer.add(*args) }
sizer.add_growable_row(2, 1)
sizer.add_growable_col(1, 1)
wrapper.add(sizer, Wx::SizerFlags.new(1).expand.border(Wx::ALL, 15))
@panel.sizer = wrapper
centre
end
end
Wx::App.run do
window = MyWindow.new("wxRuby Sizer Guide")
window.show
end
Output of the above code:
An example on how to use the wxRuby GridBagSizer (Follow link for full tutorial).
require 'wx'
class MyWindow < Wx::Frame
def initialize(title)
super(nil, title: title)
@panel = Wx::Panel.new(self)
wrapper = Wx::HBoxSizer.new
sizer = Wx::GridBagSizer.new(5, 5)
sizer.add(Wx::StaticText.new(@panel, label: 'A Keypad'), [0,1], flag: Wx::ALIGN_CENTRE)
sizer.add(Wx::Button.new(@panel, label: "1"), [1, 0], flag: Wx::EXPAND)
sizer.add(Wx::Button.new(@panel, label: "2"), [1, 1], flag: Wx::EXPAND)
sizer.add(Wx::Button.new(@panel, label: "3"), [1, 2], flag: Wx::EXPAND)
sizer.add(Wx::Button.new(@panel, label: "4"), [2, 0], flag: Wx::EXPAND)
sizer.add(Wx::Button.new(@panel, label: "5"), [2, 1], flag: Wx::EXPAND)
sizer.add(Wx::Button.new(@panel, label: "6"), [2, 2], flag: Wx::EXPAND)
sizer.add(Wx::Button.new(@panel, label: "7"), [3, 0], flag: Wx::EXPAND)
sizer.add(Wx::Button.new(@panel, label: "8"), [3, 1], flag: Wx::EXPAND)
sizer.add(Wx::Button.new(@panel, label: "9"), [3, 2], flag: Wx::EXPAND)
sizer.add_growable_row(1)
sizer.add_growable_row(2)
sizer.add_growable_row(3)
sizer.add_growable_col(0)
sizer.add_growable_col(1)
sizer.add_growable_col(2)
wrapper.add(sizer, proportion: 1, flag: Wx::EXPAND | Wx::ALL, border: 10)
@panel.sizer = wrapper
centre
end
end
Wx::App.run do
window = MyWindow.new("wxRuby Sizer Guide")
window.show
end
Output of the above code:
An example on how to use the wxRuby WrapSizer (Follow link for full tutorial).
require 'wx'
class MyWindow < Wx::Frame
def initialize(title)
super(nil, title: title)
@panel = Wx::Panel.new(self)
sizer = Wx::WrapSizer.new(Wx::HORIZONTAL, 0) # or Wx::HWrapSizer.new(0)
15.times do |i|
sizer.add(Wx::CheckBox.new(@panel, label: "Option #{'%.2i' % (i+1)}"), 0, Wx::ALL, 12)
end
@panel.sizer = sizer
centre
end
end
Wx::App.run do
window = MyWindow.new("wxRuby Sizer Guide")
window.show
end
Output of the above code: