Home  Contents

Layout management in JRuby Swing

In this part of the JRuby Swing programming tutorial, we will introduce layout managers.

When we design the GUI of our application, we decide what components we will use and how we will organise those components in the application. To organise our components, we use specialised non visible objects called layout managers. The Swing toolkit has two kind of components. Containers and children. The containers group children into suitable layouts. To create layouts, we use layout managers.

Absolute positioning

In most cases, programmers should use layout managers. There are a few situations, where we can use absolute positioning. In absolute positioning, the programmer specifies the position and the size of each component in pixels. The size and the position of a component do not change if you resize a window. Applications look different on various platforms, and what looks OK on Linux, might not look OK on Mac OS. Changing fonts in your application might spoil the layout. If you translate your application into another language, you must redo your layout. For all these issues, use the absolute positioning only when you have a reason to do so.

#!/usr/local/bin/jruby

# ZetCode JRuby Swing tutorial
#
# In this program, we lay out three images
# using absolute positioning.
#
# author: Jan Bodnar
# website: www.zetcode.com
# last modified: December 2010

include Java

import java.awt.Color
import javax.swing.ImageIcon
import javax.swing.JLabel
import javax.swing.JPanel
import javax.swing.JFrame


class Example < JFrame
  
  def initialize
      super "Absolute"
      
      self.initUI
  end
    
  def initUI
    
      panel = JPanel.new
      panel.setLayout nil
      panel.setBackground Color.new 66, 66, 66
      self.getContentPane.add panel

      rot = ImageIcon.new "rotunda.jpg"
      rotLabel = JLabel.new rot
      rotLabel.setBounds 20, 20, rot.getIconWidth, rot.getIconHeight

      min = ImageIcon.new "mincol.jpg"
      minLabel = JLabel.new min
      minLabel.setBounds 40, 160, min.getIconWidth, min.getIconHeight

      bar = ImageIcon.new "bardejov.jpg"
      barLabel = JLabel.new bar
      barLabel.setBounds 170, 50, bar.getIconWidth, bar.getIconHeight

      panel.add rotLabel
      panel.add minLabel
      panel.add barLabel
    
      self.setDefaultCloseOperation JFrame::EXIT_ON_CLOSE
      self.setSize 350, 300
      self.setLocationRelativeTo nil
      self.setVisible true
  end
  
end

Example.new

In this example, we show three images using absolute positioning.

panel.setLayout nil

Containers in Swing already have a default layout manager. JPanel has a FlowLayout manager as its default layout manager. We use the setLayout method with a nil parameter to remove the default layout manager and use absolute positioning instead.

rot = ImageIcon.new "rotunda.jpg"
rotLabel = JLabel.new rot
rotLabel.setBounds 20, 20, rot.getIconWidth, rot.getIconHeight

We create an ImageIcon object. We put the icon into the JLabel component to display it. Then we use the setBounds method to position the label on the panel. The first two parameters are the x, y positions of the label. The 3th and 4th parameters are the width and the height of the icon.

panel.add rotLabel

We add the label to the panel container.

Absolute
Figure: Absolute positioning

Buttons example

In the following example, we will position two buttons in the bottom right corner of the window.

#!/usr/local/bin/jruby

# ZetCode JRuby Swing tutorial
#
# In this program, we use the BoxLayout
# manager to position two buttons in the
# bottom right corner of the window.
#
# author: Jan Bodnar
# website: www.zetcode.com
# last modified: December 2010

include Java

import java.awt.Dimension
import javax.swing.JButton
import javax.swing.JPanel
import javax.swing.JFrame
import javax.swing.BoxLayout
import javax.swing.Box


class Example < JFrame
  
  def initialize
      super "Buttons"
      
      self.initUI
  end
    
  def initUI
    
      basic = JPanel.new
      basic.setLayout BoxLayout.new basic, BoxLayout::Y_AXIS
      self.add basic

      basic.add Box.createVerticalGlue

      bottom = JPanel.new
      bottom.setLayout BoxLayout.new bottom, BoxLayout::X_AXIS
      bottom.setAlignmentX 1.0
      

      okButton = JButton.new "OK"
      closeButton = JButton.new "Close"

      bottom.add okButton
      bottom.add Box.createRigidArea Dimension.new 5, 0
      bottom.add closeButton
      bottom.add Box.createRigidArea Dimension.new 15, 0

      basic.add bottom
      basic.add Box.createRigidArea Dimension.new 0, 15
    
      self.setDefaultCloseOperation JFrame::EXIT_ON_CLOSE
      self.setSize 300, 200
      self.setLocationRelativeTo nil
      self.setVisible true
  end
  
end

Example.new

We will create two panels. The basic panel has a vertical box layout. The bottom panel has a horizontal one. We will put a bottom panel into the basic panel. We will right align the bottom panel. The space between the top of the window and the bottom panel is expandable. It is done by the vertical glue.

basic = JPanel.new
basic.setLayout BoxLayout.new basic, BoxLayout::Y_AXIS
...
bottom = JPanel.new
bottom.setLayout BoxLayout.new bottom, BoxLayout::X_AXIS

The basic panel has a vertical box layout. The bottom panel has a horizontal box layout.

bottom.setAlignmentX 1.0

The bottom panel is right aligned.

basic.add Box.createVerticalGlue

We create a vertical glue. The glue is vertically expandable white space, which will push the horizontal box with the buttons to the bottom.

okButton = JButton.new "OK"
closeButton = JButton.new "Close"

These are the two buttons that will go into the bottom right corner of the window.

bottom.add okButton
bottom.add Box.createRigidArea Dimension.new 5, 0

We put the OK button into the horizontal box. We put some rigid space next to the button. So that there is some space between the two buttons.

basic.add Box.createRigidArea Dimension.new 0, 15

We put some space between the buttons and the border of the window.

Buttons example
Figure: Buttons example

Windows example

The following example creates the windows dialog using the GroupLayout manager. The dialog comes from the JDeveloper application.

The GroupLayout manager divides the creation of the layout into two steps. In one step, we lay out components alongside the horizontal axis. In the second step, we lay out components along the vertical axis. This is an unusual idea within layout managers, but it works well.

There are two types of arrangements: sequential and parallel. In both kinds of layouts we can arrange components sequentially or in parallel. In a horizontal layout, a row of components is called a sequential group. A column of components is called a parallel group. In a vertical layout, a column of components is called a sequential group. And a row of components is called a parallel group. You must understand these definitions right in order to work with the GroupLayout manager.

#!/usr/local/bin/jruby

# ZetCode JRuby Swing tutorial
#
# In this program, GroupLayout
# manager to create a Windows 
# example.
#
# author: Jan Bodnar
# website: www.zetcode.com
# last modified: December 2010


include Java

import java.awt.Dimension
import java.awt.Color
import javax.swing.JButton
import javax.swing.SwingConstants
import javax.swing.JFrame
import javax.swing.JLabel
import javax.swing.JTextArea
import javax.swing.BorderFactory
import javax.swing.GroupLayout


class Example < JFrame
  
  def initialize
      super "Windows"
      
      self.initUI
  end
    
  def initUI
    
      layout = GroupLayout.new self.getContentPane
      self.getContentPane.setLayout layout
      layout.setAutoCreateGaps true
      layout.setAutoCreateContainerGaps true

      self.setPreferredSize Dimension.new 350, 300

      windows = JLabel.new "Windows"
      area = JTextArea.new 
      area.setEditable false
      area.setBorder BorderFactory.createLineBorder Color.gray
      activateButton = JButton.new "Activate"
      closeButton = JButton.new "Close"
      helpButton = JButton.new "Help"
      okButton = JButton.new "OK"
       
      
      sg = layout.createSequentialGroup
      pg1 = layout.createParallelGroup
      pg2 = layout.createParallelGroup
      pg1.addComponent windows
      pg1.addComponent area
      pg1.addComponent helpButton
      sg.addGroup pg1
      pg2.addComponent activateButton
      pg2.addComponent closeButton      
      pg2.addComponent okButton
      sg.addGroup pg2
      layout.setHorizontalGroup sg
      
      sg1 = layout.createSequentialGroup
      sg2 = layout.createSequentialGroup
      pg1 = layout.createParallelGroup
      pg2 = layout.createParallelGroup      
      sg1.addComponent windows
      pg1.addComponent area
      sg2.addComponent activateButton
      sg2.addComponent closeButton
      pg1.addGroup sg2
      sg1.addGroup pg1
      pg2.addComponent helpButton
      pg2.addComponent okButton
      sg1.addGroup pg2
      layout.setVerticalGroup sg1
      

      layout.linkSize SwingConstants::HORIZONTAL, 
          okButton, helpButton, closeButton, activateButton

      self.pack
    
      self.setDefaultCloseOperation JFrame::EXIT_ON_CLOSE
      self.setLocationRelativeTo nil
      self.setVisible true
  end
  
end

Example.new

We use GroupLayout manager to create a layout which consists of six components. Groups of components are formed along both axes.

sg = layout.createSequentialGroup
pg1 = layout.createParallelGroup
pg2 = layout.createParallelGroup
pg1.addComponent windows
pg1.addComponent area
pg1.addComponent helpButton
sg.addGroup pg1
pg2.addComponent activateButton
pg2.addComponent closeButton      
pg2.addComponent okButton
sg.addGroup pg2
layout.setHorizontalGroup sg

In the first step, we have a horizontal layout. It consists of two parallel groups of three components.

sg1 = layout.createSequentialGroup
sg2 = layout.createSequentialGroup
pg1 = layout.createParallelGroup
pg2 = layout.createParallelGroup      
sg1.addComponent windows
pg1.addComponent area
sg2.addComponent activateButton
sg2.addComponent closeButton
pg1.addGroup sg2
sg1.addGroup pg1
pg2.addComponent helpButton
pg2.addComponent okButton
sg1.addGroup pg2
layout.setVerticalGroup sg1

Vertical layout is a bit more complex. First, we add a single component. Then we add a parallel group of a single component and a sequential group of two components. Finally, we add a parallel group of two components.

layout.linkSize SwingConstants::HORIZONTAL, 
    okButton, helpButton, closeButton, activateButton

This code makes all buttons the same size. We only need to set their width, because their height is already the same by default.

Windows example
Figure: Windows example

Look at the screenshot of the example. Notice that components can be grouped into vertical and horizontal sets of components. For example, the label, the area and the Help button components can form a vertical group of components. This is exactly what the GroupLayout manager does. It lays out components by forming vertical and horizontal groups of components.

In this part of the JRuby Swing tutorial, we mentioned layout management of components.