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

     About      FAQ      User Guide      Reference documentation

Layout widgets with Sizers

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

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:

screenshot1

Creating a wxRuby Sizer

The steps for creating a basic Sizer are fairly simple.

  1. First, create the Sizer you want.
  2. Create a few widgets.
  3. 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).

wxRuby BoxSizer

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:

screenshot2

wxRuby StaticBoxSizer

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:

screenshot3

wxRuby GridSizer

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:

screenshot4

wxRuby FlexGridSizer

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:

screenshot5

wxRuby GridBagSizer

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:

screenshot6

wxRuby WrapSizer

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:

screenshot7

⚠️ **GitHub.com Fallback** ⚠️