Principles of Swing
Goals
- Learn Swing so you can build UIs in Java
- Swing is a large framework; learn how to better use frameworks by using Swing
- Many useful examples of good object-oriented design sit inside Swing that we can study.
The main parts of Swing
Swing is very large, and you can drown in detail if you are not careful. Here is the 10,000 foot view.JFrame
- each open window has aJFrame
(or aJFrame
subclass) controlling it.JComponent
- each component within a window is aJComponent
subclass; either- a built-in Swing component such as a
JButton extends JComponent
,JTextInputField
, etc. - a custom component
DicePanel extends JPanel (extends JComponent)
: you code the classDicePanel
and decide directly how to draw the dice and deal with mouse clicks on the dice
- a built-in Swing component such as a
- Layout Manager - dictates how the different components are laid out in the window.
- Event system - how all input is handled, including mouse, keyboard, and even internal requests to redraw windows
Swing Windows: the JFrame
class
Key points
- There is a single
JFrame
object associated with each Swing window frame.add(aComponent)
will add a component (button, text field, compound component, etc) to theJFrame
.- Use
frame.setVisible(true)
to open the window; this method also spawns a thread which starts an event handling loop for the window. - The window's event-handling thread terminates upon close of the window.
FrameOnly.java is a bare-bones JFrame
that just opens a window.
Installing Components in a window
- Swing components are added to the
JFrame
'scontentPane
(aContainer
of window components) and they then appear in the window. - You can specify the layout of the components in the window at the time they are installed (more later on that)
FrameAndLabel.java is aJFrame
with a label added to itscontentPane
.
The Event Manager
Swing programming is event-driven
- All sorts of events are generated that must be dealt with: keypresses, mouse clicks,
window resizings, etc.
-- Well, in fact these events are what drives the program: deal with every key/mouse input and the user is happy! - With each window is associated an event manager running in its own thread, to deal with all these random events.
- The event thread sits idle until it gets an event (mouse click, keypress, resize, repaint, etc), at which point it reacts to it
- If too many events show up at once they go into an event queue and wait their turn to be processed
- Key observation: YOUR CODE IS NOT IN CHARGE, SWING IS -- you wait to be called by the event manager, do your little thing, and
return
when done!
- "SAVE" button pressed -->
- event generated -->
- event queued -->
- ... -->
- event eventually gets to top of event queue -->
- your code gets called to react -->
- you save the file to disk -->
- your code returns, relinquishing control back to event thread -->
- next event processed or idle if the queue is empty
The different types of Events
Different event types are embodied in different classes- Class
AWTEvent
is the superclass of all Swing events. InputEvent extends AWTEvent
has subclassesMouseEvent
andKeyEvent
for mouse and keyboard input events, respectively.WindowEvent extends AWTEvent
handles resize, close, etc. events- Swing buttons etc generate
ActionEvent
s when pressed - Swing generates internal events: for example a window resize generates a
PaintEvent
which will cause the window to be re-drawn at the new size.
The handling of events
- Recall for the SAVE button example above that your code needs to be called to handle the event: your code needs to listen for the requisite events.
- A
Listener
is an object listening for particular events; different kinds of Listeners listen to different types of events. - The
Listener
will be invoked if/when the event it is listening for happens. - When your listener code is finished executing, control returns to the event manager to process the next event.
- COROLLARY: if your listener method never returns, no further events will be processed and the application will freeze.
The details of event programming by example
LabelAndButton.java is a JFrame
with a label and button which can be pressed to change the label.
- A
JButton
generates anActionEvent
every time it is pressed. - Here your
LabelButtonListener
implements the Swing interfaceActionListener
to listen for theseActionEvent
s. - the line
labelButton.addActionListener(new LabelButtonListener());
registers yourLabelButtonListener
with the button, meaning it will be notified when the button is pressed. - Refinement of above order of events:
- Mouse clicked on "Change label" button -->
MouseEvent
generated and queued up -->- ... -->
MouseEvent
gets to top of event queue -->Button
's listener responds, generating a newActionEvent
- This
ActionEvent
is queued up - ... -->
- this
ActionEvent
object comes to the top of queue --> - the event manager invokes its listener method,
actionPerformed()
.
- All of the other events and listeners are similar; there is a mouse listener example below.
Making Swing Components
- We have covered the hard part of UI programming, the component and event-based aspect
- Now we do the (relatively) easy part, how to build up the visual structures.
- First we describe custom components, then we briefly review the library of built-in Swing widgets.
- We conclude with the topic of layout, how multiple components are placed in a window.
Creating a custom Swing component
A custom component is a non-built-in widget.
CustomPanel.java has a MySimplePanel
which does some simple circle drawing.
Here is how custom components work in Swing.
- Subclass your custom panel from
JPanel
, e.g.MySimplePanel extends JPanel
- Override the
MySimplePanel
paintComponent(Graphics g)
method to do the drawing you desire - Your first line of
paintComponent
method should besuper.paintComponent(g);
because in general the superclass could also be drawing on this surface (in this example it is not necessary). This is part of the Swing library contract. - Argument
g
is passed to you -- its the graphical canvas you draw on. - The
Graphics
class contains methods to draw on the canvas, eg. theg.fillOval()
used here. - (The window manager is smart to relativize
g
to the location of your component within the window, and to clip if you draw out of bounds.)
Component painting also uses the event manager
- Calls to
paintComponent
are event-driven: called whenever repainting is called for - Either system can call for repainting, or you can explicitly send
repaint()
message to a component or a window - NEVER stash
Graphics g
in your own field and paint when you are not inside methodpaintComponent
: you broke the Swing contract and your application is going to barf on you.
Custom components receiving mouse/keyboard input
If your component needs to respond to mouse/keyboard input, set up a mouse event listener.
SimpleSquaresUI.java has a custom component SquaresPanel
that can respond to mouse clicks
- The class
MouseHandler
implements theMouseListener
interface so "can hear" mouse click events. - All the methods are empty (no action) except
mousePressed
which is the combination of a click and a release. - In the comments below is an alternate implementation: instead of implementing the
MouseListener
interface, extend an adapterMouseAdapter
. - Use of
MouseAdapter
means we don't need to write all the empty methods for events we don't care about.
Layouts: making it look pretty
- Deciding how to lay out multiple buttons, fields, etc in a single window is complex, in particular when windows can be resized.
- Swing comes with several different Layout Managers to choose from, each one useful in a different context.
- The layout manager is in charge of the layout, you are basically only giving it your requests/preferences.
- For any composite component, you can specify which layout manager it is going to use for the sub-components added to it.
Here are the most common layout managers you will be using.
FlowLayout
-- Each component is like a word in a word processor document: put left to right and move to next line if no more room. This is the default forJPanel
s.BoxLayout
-- LikeFlowLayout
but forces components to line up vertically or horizontally.FlowAndBoxLayouts.java covers the two layouts above
BorderLayout
-- Component is divided into five regions you can put sub-components:NORTH
,SOUTH
,CENTER
,LEFT
, andRIGHT
. There is no background space in aBorderLayout
, the component's preferred size may be overridden to make it fit the whole area. The default forJFrame
s.TwoButtons.java is a basic
BorderLayout
example we can fiddle with.GridLayout
-- Components are organized in a rectangular grid
The Composite Design Pattern in Swing
Complex layouts often need nested layouts- The subclass relationship in Swing is:
JButton
/JLabel
/JPanel
etc is-aJComponent
is-aContainer
is-aComponent
(yes there is a J and a non-J Component, it is a historical oddity) -
Components
are what can be added to theJFrame
sContainer
- Since
JComponent
is aContainer
, it is possible to add components to any component -- the component structure of a window can be nested. - this is a clever design that is useful because you can put a whole window-in-a-window (like frames in html), making complex UI designs easier.
- This is an instance of a design pattern, the Composite pattern.
CompositePatternInSwing.java shows howJPanel
s (subclasses ofJComponent
) can containJPanels
which can containJButton
/JLabel
s.
The Built-in Swing Components
- There are a large number of standard Swing widgets.
- They are relatively easy to figure out how to use on your own so we are not covering them in detail here.
- Most of these inherit from
JComponent
and are found in packagejavax.swing
. - The most common ones are covered in more detail in the Head First Java reference we are following.
- See the Swing tutorial visual guide to Swing Components for a more complete visual list.
Component decorators
- Since components are built using the Composite design pattern, components can contain other components.
- There are several built-in Swing decorators that are containers for other components, modifying the component put in them in some way.
- A key to their flexibility is wrapped components are themselves components (i.e. they inherit from
Component
), and can be installed similarly, wrapped by something else, etc. - Component decorators are an instance of the Decorator design pattern.
JScrollPane
: adds scrollbar functionality to the underlying component.JLayer
: a new feature of Java 7 which allows many forms of decoration of components with one tool.
The Model-View-Controller (MVC) design pattern
- Now that we have the tools, we need to think about how to cleanly code it.
- For the simple examples up to now, there is not much total code so its not a big problem
- However with larger programs (such as Assignment 1) if one class is doing everything there are too many responsibilities and things get confusing
- Solution: factor UI code into three independent components: Model, View, and Controller.
- Model: the underlying logical structure (e.g. for chess the model would include the pieces on the board and the legal move logic)
- View: output UI,
JComponent
s in Swing - Controller: input event processor,
Listener
s in Swing
- Put model-view-controller in separate class(es) to factor functionality
- None of the underying logic (model) should mix with display (view) or input (controller) code in a single class
- Model only notifies the view of chnages, it doesn't invoke the view
- Nearly every UI benefits from being factored into M-V-C
Here is a summary illustration from the Oracle Swing docs which shows who does what:
Simple MVC Examples
Squares
We presented a simple mouse event example above,SimpleSquaresUI.java
. The underlying data is a set of squares but it is so simple we do not make a separate model class. If this example was extended to additionally allow deletions/movement/etc of squares there starts to get enough functionality that we want to make a separate model and view.
SquaresUI.java and SquaresModel.java refactors SimpleSquaresUI
into a separate model and view, and adds additional functionality.
BeatBox
The Head First Java book had a larger UI example of a beat box which munged together the underlying data for which sounds trigger when with the display of that data.BeatBox.java Beat box example with no MVC - the model and view are all in one class.
BeatBoxUI.java and BeatBoxModel.java pulls out the underlying MIDI processing into its own model class, making it easier to understand and change these two components.
More Swing
While the above notes cover the key features, Swing is a massive beast.- The best place to get more information is in the Oracle Swing Tutorial.
- And of course for further details read the Swing API Javadocs.