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 aJFramesubclass) controlling it.JComponent- each component within a window is aJComponentsubclass; 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 classDicePaneland 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
JFrameobject 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(aContainerof 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 aJFramewith 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
returnwhen 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
AWTEventis the superclass of all Swing events. InputEvent extends AWTEventhas subclassesMouseEventandKeyEventfor mouse and keyboard input events, respectively.WindowEvent extends AWTEventhandles resize, close, etc. events- Swing buttons etc generate
ActionEvents when pressed - Swing generates internal events: for example a window resize generates a
PaintEventwhich 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
Listeneris an object listening for particular events; different kinds of Listeners listen to different types of events. - The
Listenerwill 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
JButtongenerates anActionEventevery time it is pressed. - Here your
LabelButtonListenerimplements the Swing interfaceActionListenerto listen for theseActionEvents. - the line
labelButton.addActionListener(new LabelButtonListener());registers yourLabelButtonListenerwith the button, meaning it will be notified when the button is pressed. - Refinement of above order of events:
- Mouse clicked on "Change label" button -->
MouseEventgenerated and queued up -->- ... -->
MouseEventgets to top of event queue -->Button's listener responds, generating a newActionEvent- This
ActionEventis queued up - ... -->
- this
ActionEventobject 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
MySimplePanelpaintComponent(Graphics g)method to do the drawing you desire - Your first line of
paintComponentmethod 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
gis passed to you -- its the graphical canvas you draw on. - The
Graphicsclass contains methods to draw on the canvas, eg. theg.fillOval()used here. - (The window manager is smart to relativize
gto 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
paintComponentare 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 gin 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
MouseHandlerimplements theMouseListenerinterface so "can hear" mouse click events. - All the methods are empty (no action) except
mousePressedwhich is the combination of a click and a release. - In the comments below is an alternate implementation: instead of implementing the
MouseListenerinterface, extend an adapterMouseAdapter. - Use of
MouseAdaptermeans 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 forJPanels.BoxLayout-- LikeFlowLayoutbut 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 forJFrames.TwoButtons.java is a basic
BorderLayoutexample 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/JPaneletc is-aJComponentis-aContaineris-aComponent(yes there is a J and a non-J Component, it is a historical oddity) -
Componentsare what can be added to theJFramesContainer - Since
JComponentis 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 howJPanels (subclasses ofJComponent) can containJPanelswhich can containJButton/JLabels.
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
JComponentand 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,
JComponents in Swing - Controller: input event processor,
Listeners 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.