Page 1 of 1

Swing, Top-Down (with GridBagLayout) Rate Topic: ***** 2 Votes

#1 andrewsw  Icon User is online

  • Fire giant boob nipple gun!
  • member icon

Reputation: 3354
  • View blog
  • Posts: 11,349
  • Joined: 12-December 12

Posted 04 February 2014 - 11:40 AM

*
POPULAR

Please note that this tutorial is not intended for a beginner programmer. However, if you have completed a Swing tutorial, and are not sure how to proceed from there, then this may be suitable as a follow-up project.

Beginner resources:

Spoiler


My intended audience is a fairly experienced programmer who either:

Has experience of building GUIs (GUI - Graphical User Interface) in another language and wants a rapid introduction to (an overview of) Swing; or,
has gone through a first steps Swing tutorial but has become frustrated at the pace or the approach.

Here is where we are heading..

Posted Image

I became a little frustrated with standard tutorials, which prompted me to write this one. For example, a typical first program is something like this:

Spoiler

This is fine for a beginner. In particular, it is important to get something up and running very quickly. If the beginner gets through the first chapter without anything appearing on screen they might not read chapter 2. It is also a useful mechanism to persuade the reader that Swing isn't as complicated as they may have thought.

For the more experienced programmer, though, it can become a little frustrating because the next chapter or two will then unravel this code and we will never use it again:

  • The UI should be designed and built separately from the (main) application;
  • The main method should do as little as possible, merely providing a gateway into the application.


A typical second example would be:

Spoiler

Again, this is perfectly acceptable for a beginner, and an improvement on the first example. However, for all but the simplest of examples, the GUI should be completely separate from the static main-method.

Start to Swing

Disclaimer: I am providing a top-down view of Swing, a run-through. I am not suggesting the following as a template for Swing-GUIs. In particular, I recommend follow-up reading of this tutorial:

How To Approach Swing For Beginners

which briefly discusses the benefits of inheriting Swing Components.

Here is a first attempt at our driver-application:

public class MyApplication {
    
    public static void main(String[] args) {
        new MyGui();
    }
}


Simples. Well, it would be, except that Swing event handling code runs on a special thread known as the Event Dispatch Thread, whereas the main-method runs in a special "main" or application thread.

So, instead, here is our driver:

import javax.swing.SwingUtilities;

public class MyApplication {
    
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new MyGui();
            }
        });
    }
}


invokeLater

javamex said:

This method allows us to post a "job" to Swing, which it will then run on the event dispatch thread at its next convenience.


This looks a little odd; we are asking to invokeLater but the application immediately finishes?! Let's just say that when the closing-brace of main() is reached there is nothing happening that would delay Swing from running.

The javamex page just linked uses the following in the run method:

        MyApplication app = new MyApplication();    // I'm using MyGui()
        app.setVisible(true);


This is an interesting point: should the GUI show itself, or should the main-application decide whether, and when, to show it? It seems sensible that the application should decide whether to show or not. Others would argue that there is little point in building a GUI if it is not shown. There are circumstances, though, when it is useful to load the GUI but not yet show it. So.. it depends. Let's move on.

We have our driver. Before we build our GUI let's get a quick overview. The Swing Object Model is huge and convoluted, so let's cut to the chase:

  • It's all about Swing Components.
  • The main, primary, component is a JFrame. This is our GUI - our frame, or form, or window if you prefer.
  • We can add one or more JPanel components to our frame.
  • A panel can contain a number of other components (or controls, if you are coming from another language) such as JLabel, JButton, JTextField, etc..
  • A panel can also contain another panel, or panels; a panel is also a Component.
  • Frames and panels have a LayoutManager which controls how components are arranged on the frame or panel.
  • Listeners are used to respond to events.
  • The most important is the ActionListener which responds to button-clicks, but also doubles-up to respond to changing the selected item of, for example, a JComboBox.
  • There are also Mouse and Key Listeners to respond to mouse and keyboard-events, and a few more.


Detailed forms are created from a combination of different panels and layout-managers.

A Little About AWT

Spoiler


The Pencil Toolkit

So shall we begin to build the GUI? No, not yet.

Standard tutorials introduce the simpler components (JLabel, JButton, etc.) by adding them one-by-one to a JPanel (and then add this panel to a JFrame). JPanels use FlowLayout as their default LayoutManager. This adds controls centred in the panel, from left to right, dropping to a second row when the first is full. This is actually one of the less-useful managers. Have a quick look here:

A Visual Guide to Layout Managers

The most useful manager, and the one we will use, is the GridBagLayout. This is described as 'flexible and sophisticated'. Many tutorials put off this till the very end, but:

  • You will need to understand it.
  • When you understand this manager the others will be simple.
  • It isn't that complicated, just requires a little planning!


Get a pencil and paper and plan your frame/form. You can use software if you like; I'm using Excel but you can use anything that you're comfortable with. You might have a quick search on the internet as there are a number of free online tools. Search something like "online form designer".

Posted Image

Notice that the top-left grid (cell) is at (0, 0). Components can span multiple rows and/or columns, and the components can be aligned at different positions inside the cells, and be given padding. To put more than one component in a cell we can use a panel, then insert the panel in the cell.

Let Us Code

Create the following framework for your new MyGui class.

Spoiler

You can now save and run your application, but it won't do much yet. In particular, the frame will have no height. You could try adding the following temporarily as line 11 (delete it afterwards) and run it again - but it still has no size:
 
        this.setSize(200, 200);


This is significant. When using a LayoutManager setSize() has no effect. The manager is responsible for sizing and laying-out the components. We could use setPreferredSize() and setMinimumSize() (once we've added some components!). However, I suggest that it is better to not size anything at all, especially initially. Let the LayoutManager do its job.

Line 6. We are extending (inheriting/sub-classing) the JFrame component. The JFrame-class itself will do most of the work for us, we just need to tweak it a bit - mainly adding components to it. We implement ActionListener so that we can respond to click (and other) events of the frame.

Line 8. Our default constructor for our specialized JFrame.

Line 10. Closing the frame will exit our application.

Line 13. The default manager for a panel is FlowLayout. Notice that we don't specify a size, or number of rows or columns, for the GridBagLayout; these will be determined for us as we add components to the panel.

Line 15. The sine qua non, we must add the panel to the frame.

the docs said:

The pack method sizes the frame so that all its contents are at or above their preferred sizes. An alternative to pack is to establish a frame size explicitly by calling setSize or setBounds (which also sets the frame location). In general, using pack is preferable to calling setSize, since pack leaves the frame layout manager in charge of the frame size, and layout managers are good at adjusting to platform dependencies and other factors that affect component size.


From How to Make Frames :tutoracles

Constrain Away

Add the following helper-method.

Spoiler

(I've borrowed this code from Java All-In-One for Dummies.)

Look at line 14. For simpler LayoutManagers we might just create a component and add() it to the panel. For a GridBagLayout we need to use a GridBagConstraints object. With this we specify the x, y position to add the component (see the picture above) and the width and height; that is, how many rows or columns the component spans.

Lines 8 & 9 are about apportioning space. You can study this afterwards. Their value is between 0.0 and 1.0.

Line 10. The insets are padding around the component (why didn't they call this padding?). Without setting this the component will have no (external) padding.

Line 12. By default components will fill the cell. This is not usually what we want. We also need to disable fill in order to align (anchor) components within the cell.




Instead of this helper method we could create, and configure, a GridBagConstraints object for each component. This sounds like hard work. Alternatively, we could create and re-use a single constraints object. We woud still have to configure x, y each time, but this approach does offer more scope than our standardized helper-method.

How to Use GridBagLayout :tutoracles

Building, with Constraints

Spoiler

Lines 3+. Any components that need to be referenced outside of the constructor are declared as member-variables.

I am not a full-time Java programmer so perhaps am playing a little fast-and-loose with naming conventions. Components whose value (generally, their text) represents a data-value (within the application) I am naming without any prefix or suffix. I use a suffix for components which are strictly UI-elements. Study Java naming conventions.

Lines 15+. Using our helper-method to add, position and align, our components. These are simple labels and we don't need to retain any references for them.

JTextField, JTextArea, JScrollPane

Spoiler

Lines 1 to 4. We specify the number of characters (columns) for the text-fields. We also need to set minimum sizes otherwise, when we make the frame/window smaller, they just collapse.

Line 6. We specify the number of rows and columns of the text-area.

Line 12. Adding scrollbars to a JTextArea (and other components) is a little odd. We create the text-area first, then construct the scrollbar, passing the text-area as first argument to the scrollbar's constructor. Essentially, wrapping the scrollbar around the text-area. Notice, however that in line 19 it is the scrollbar that is added to the panel. This is a little counter-intuitive but, if we think about it, does make some sense. After all, it is the text-area that sits inside the scrollbars.

Box, JRadioButton, ButtonGroup and Border

Spoiler

There are a few components involved with the gender radio-buttons. We could create another JPanel, add various components to this, and then add this panel (which is also a Component) to our main panel. We would use BoxLayout for this new panel to position the radio-buttons vertically (or horizontally).

Instead we use the Box Class. This is, essentially, a panel (or, more accurately, a container) which uses BoxLayout as its layout manager.

In order for the radio-buttons to feature as a mutually-exclusive group (we can only select one) we need to add them to a ButtonGroup. This is a non-visual element (notice that we don't add it to the panel) whose sole purpose is to group buttons logically.

We can create a border around our Box. To do so we need a Border object; the BorderFactory helps us to create this.

JButtons and ActionListeners

Spoiler

We use another Box to contain the OK and Exit buttons. Between adding the OK and Exit buttons to the Box we add a strut, creating a gap between them.

  • To each button we add an ActionListener.
  • The ActionListener is provided by the context this.
  • this refers to our frame, which implements ActionListener.

When either button is clicked the following ActionListener method is executed.

Spoiler

The ActionEvent e essentially provides information for the context of the current event. Importantly, we can use e.getSource() to determine which button was clicked (what triggered the event). The remaining code provides a little bit of error checking, and uses System.exit(0) to exit the application on clicking the Exit button.

It is possible to use an anonymous inner class listener to respond to clicking an individual button:

Spoiler

This can be convenient but quickly becomes unwieldy for more than two or three components. Having event-code scattered throughout the class is not convenient.

The Full GUI Code

Spoiler





Other important components are JCheckBox (similar to JRadioButton), JComboBox, JFormattedText, JTable and JTree. There are many others.

I ran out of space, but you might have a go at adding the combo-box in this screenshot:

Posted Image

There is a label on the right as well. When 'United States' is selected in the combo-box the label says 'US', otherwise the label is not shown.

Here is the tutorial I mentioned earlier:

How To Approach Swing For Beginners

Another topic to consider is input validation:

The Focus Subsystem - Input Verification :tutoracles




ComboBox Code

I'll add the combo-box code here, in case anyone wants it now or in the future. First we need to add member-variables for the label and combo-box, as we need to refer to them in the ActionListener.

Spoiler

Insert the following code in our frame's constructor to add the label and combo-box.

Spoiler

Lastly, we need another else-if block in the ActionListener:

Spoiler

You still have a challenge though. When the frame is first shown it will display "US" even though the currently selected item in the combo-box may not be "United States". Good luck!

This post has been edited by andrewsw: 04 February 2014 - 02:03 PM


Is This A Good Question/Topic? 5
  • +

Replies To: Swing, Top-Down (with GridBagLayout)

#2 cfoley  Icon User is offline

  • Cabbage
  • member icon

Reputation: 1949
  • View blog
  • Posts: 4,048
  • Joined: 11-December 07

Posted 04 February 2014 - 03:16 PM

Very nice tutorial there, particularly the GridBagLayout section. I gave up on it as being too complex years ago but after reading your tutorial, I might give it another go.

With event handling, I feel you are missing out on a little OO fun if you use e.getSource(). The anonymous inner classes aren't ideal either so for the past few years, I've been using anonymous inner classes to call another method, usually in the same class. They look a bit like this:

someButton.addActionListener(new ActionListener(){
  @Override
  public void actionPerformed(ActionEvent e) {
    doWhateverThatButtonDoes(); // just a method call.
  }
});


If you are programming with the future in mind, this is the way to go since in Java 8, you will be able to replace it with this:

someButton.addActionListener(e -> {doWhateverThatButtonDoes();});

Was This Post Helpful? 0
  • +
  • -

#3 andrewsw  Icon User is online

  • Fire giant boob nipple gun!
  • member icon

Reputation: 3354
  • View blog
  • Posts: 11,349
  • Joined: 12-December 12

Posted 04 February 2014 - 03:37 PM

Thank you @cfoley.

Concerning the method call though, I'm missing something as I can't see the benefit?

If doWhateverThatButtonDoes() is specific to the button then the code could just be within the anonymous class.

If it were a common (shared) method then we would still have to pass along e to distinguish which button was clicked?

I can see, however, that passing e along to a ButtonsDo() method would help us separate button-click events from, say, combo-box selections. (Why did they lump these together anyway?)



It just this second occurred to me: does e already include information to distinguish a button-click from another type of event? Mmm probably not :dozingoff: Edited: Na, nuffink.

This post has been edited by andrewsw: 04 February 2014 - 03:47 PM

Was This Post Helpful? 0
  • +
  • -

#4 cfoley  Icon User is offline

  • Cabbage
  • member icon

Reputation: 1949
  • View blog
  • Posts: 4,048
  • Joined: 11-December 07

Posted 04 February 2014 - 04:23 PM

I guess it's how I like to think of it. The method describes what I want to happen. Adding an event listener describes when I want it to happen.

Sometimes it's useful to share methods with different kinds of listener. Double clicking on a list or activating a key binding could both be shortcuts for selecting from the list and then clicking on a button beside it. That's three different kinds of event listener for the same effect.

I also think that any time you use a large if statement to determine which object class or instance relates to another something has gone wrong with the OO design.
Was This Post Helpful? 0
  • +
  • -

#5 andrewsw  Icon User is online

  • Fire giant boob nipple gun!
  • member icon

Reputation: 3354
  • View blog
  • Posts: 11,349
  • Joined: 12-December 12

Posted 04 February 2014 - 04:52 PM

cfoley said:

Sometimes it's useful to share methods with different kinds of listener.


I can see how this might be useful ;)

cfoley said:

I also think that any time you use a large if statement to determine which object class or instance relates to another something has gone wrong with the OO design.


I agree although there doesn't seem an obvious, clear, way around this with Java. For example, we cannot use an ActionListener with a JPanel, which I think would be a good, or at least partial, solution.

We can create our own Listeners, typically as private inner classes:

private class MyActionListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
        // do stuff
    }
}

someButton.addActionListener(new MyActionListener());

I had a vague notion of creating a dictionary to store the object references as keys and methods (delegates, in other languages) as values. I'm not sure that Java can do this(?) but perhaps it is not a great idea after all.

As you say, the large else-ifs grate :whatsthat:
Was This Post Helpful? 0
  • +
  • -

#6 cfoley  Icon User is offline

  • Cabbage
  • member icon

Reputation: 1949
  • View blog
  • Posts: 4,048
  • Joined: 11-December 07

Posted 05 February 2014 - 02:48 AM

What would constitute an "action" on a JPanel? A click or keypress would make sense but it would vary by application. Fortunately, JPanel does allow different kinds of listener. The most useful are: MouseListener, MouseMotionListener, MouseWheelListener, KeyListener and FocusListener. I guess you could extend JPanel to translate some of these events into actions.

You certainly could use a Map to go from getSource() to a method. In Java 8 you will be able to use lambdas but in java 7 and earlier it would have to be anonymous inner classes which puts you back at square one. You might as well have had an anonymous inner ActionLiatener.

I feel like I've hijacked your tutorial when all I really wanted to say was I liked your GridBagLayout section. :)
Was This Post Helpful? 0
  • +
  • -

#7 andrewsw  Icon User is online

  • Fire giant boob nipple gun!
  • member icon

Reputation: 3354
  • View blog
  • Posts: 11,349
  • Joined: 12-December 12

Posted 05 February 2014 - 06:14 AM

View Postcfoley, on 05 February 2014 - 09:48 AM, said:

What would constitute an "action" on a JPanel? A click or keypress would make sense but it would vary by application. Fortunately, JPanel does allow different kinds of listener. The most useful are: MouseListener, MouseMotionListener, MouseWheelListener, KeyListener and FocusListener. I guess you could extend JPanel to translate some of these events into actions.

Well, I'm just speculating ;). But it is unnecessary really, because we can create inner classes that implement ActionListener. We can create more than one of these so this is a way to at least separate the button-clicks, or item-selections, into logical groups.

MultiListener :tutoracles

PS I still consider these comments relevant, as my tutorial is about Swing not specifically the GridBagLayout ;)
Was This Post Helpful? 0
  • +
  • -

#8 farrell2k  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 823
  • View blog
  • Posts: 2,533
  • Joined: 29-July 11

Posted 05 February 2014 - 07:23 AM

View Postcfoley, on 05 February 2014 - 09:48 AM, said:

I feel like I've hijacked your tutorial when all I really wanted to say was I liked your GridBagLayout section. :)/>


Stop complaining. :P
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1