Principles of the Swing Framework
What this lecture covers
- Learn the principles behind the Swing framework so you can build GUIs in Java
- Lecture will cover key principles, you fill in the details.
- Swing is a large framework; increase knowledge of frameworks by studying it
- Many useful examples of good object-oriented design sit inside Swing and we can study them.
Swing Overview
Here are the main components we will coverJFrame- the window, which contains a set of components in different parts of the window.JComponent- each component within a window is aJComponent; either- a built-in Swing component such as a
JButton (extends JComponent),JTextInputField, etc. which already has all low-level GUI operations built-in, or - a custom component
MyFancyGraphThing extends JPanel (extends JComponent): you decide directly how to draw and deal with mouse input
- a built-in Swing component such as a
- Event system - how all input is handled, including mouse, keyboard, and even internal requests to redraw windows
Swing Windows: the JFrame class
Here are some key points about Swing windows
JFrameis the abstract window class- Subclass your concrete
MyDeliciousFrame extends JFrame - Each window you see on the screen has exactly one
JFrameobject associated with it. - Use
frame.show()to open the window. show()spawns a thread which- opens the window;
- starts an event handling loop for the window.
- All programming relative to the window is then in event-driven style. (more later on events)
- Window event-handling threads terminate upon close of window.
The Component Structure of Windows
(You don't really need to know this, it is a detour into Swing design choices)- The internal structure of a window is as follows:
its a
JFramethat has aJRootwhich in turn contains a menu bar, content pane, and glass pane. - This is more complex than you would first expect. Were the
designers overgeneralizing? No: its all there for a good reason
- Multiple different kinds of window share underlying
JRootstructure (inApplet,JFrame, andJDialog) - The
menuBaris common to most windows and deserves special treatment glassPanesupports painting on the whole window and not just a component
- Multiple different kinds of window share underlying
- The Important Bit is the
contentPanewhich is aContaineryou canadd()multiple graphical components (e.g. buttons, input fields) to. - The window displays all of its
contentPanecomponents when redrawing
Installing Components in a window
- Components are added to the
JFrame'scontentPaneContainer. - You can specify the 2-D layout of the components in the window at the time they are installed
- Note a
Containeris also aComponent(via subclass relationship) so the component structure of a window can be nested for reuse of groups of widgets.
(This is a clever design that is useful in many other contexts: its a design pattern, the Composite pattern.)
Creating a custom Swing component
See the NotHelloWorld.java example.- Subclass your custom panel from
JPanel, e.g.NotHelloWorldPanel extends JPanelin this example - Override
NotHelloWorldPanelmethodpaintComponent(Graphics g)to do the drawing you desire - If your component needs to respond to mouse/keyboard input, set up an event listener (see below).
- Argument
gis passed to you -- its the graphical canvas you draw on. - The window manager is smart to relativize
gto the location of your component within the window. - The actual drawing/painting is directly performed by methods of the
Graphics g. In this particular example it is simplyg.drawString("Not a Hello, World program", 75, 100)
- Your first line of
paintComponentmethod should besuper.paintComponent(g);to make sure the enclosing context is also painted. This is part of the Swing library contract.
The event-driven nature of component painting
- 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 blow up all over you.
The Event Manager
See the Sun Tutorial for more information on this topic. Note the event manager is in packagejava.awt.event.
Swing programming is event-driven (a.k.a. reactive) programming
- All sorts of events are generated that must be dealt with: keypresses, mouse clicks, window resizings, etc.
- With each window is associated an event manager running in its own thread, to deal with all these random events.
- This thread starts up when the window opens, and dies when the window is closed.
- The thread sits idle until it gets an event (mouse, keyboard, 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
- All of the computing your window application does is as
part of this thread, for example:
"SAVE" button pressed --> event generated --> event queued --> ... --> event at top of queue --> your code gets called to react --> you save the file to disk --> return from processing this event --> next event processed or idle
The different sorts of Events
Different events are embodied in different classes- Class
AWTEventis the superclass of all Swing events. AWTEventis itself a subclass ofEventObject: you can use events in contexts besides Swing.InputEvent extends AWTEventhas subclassesMouseEventandKeyEventfor mouse and keyboard input events, respectively.WindowEvent extends AWTEventhandles resize, close, etc. events- Swing built-in buttons generate an
ActionEventwhen pressed - Swing itself generates events:
repaint()as described above generates aPaintEvent.
The handling of events
- A
Listenerobject is listening for particular events - For a given window there are many listeners registered with the
event manager for that window; each listener is listening
for different sorts of events.
- The
Listenerwill take action if the event happens. For example, a window with two buttons has two listeners, each listening for a press on their respective buttons. - The event manager manages the
Listeners and invokes an indicated method if appropriate (e.g. invokingactionPerformed()for a button press listener). - YOU create the actual listener object, to do whatever your
application needs to do on e.g. button press.
For example, youractionPerformed()method for a SAVE button could invokesaveFile(). - When your listener code is finished executing, control returns to the event manager who starts processing the next event.
- COROLLARY: if your listener method never returns, no further events will be processed and the application will freeze. If your listener code takes too long the GUI will freeze temporarily. GUI programming is real-time programming.
The event programming model in more detail
Consider the simple ButtonTest.java.- This example has an
ActionListenerwhich is listening to presses on aJButton, which makes a kind of event called anActionEventwhen it is pressed. - You write an object to listen for the
ActionEvent, in this example the classColorAction implements ActionListener; - You register your
ColorActionlistener either with the windowJFrameor with a particularJComponentwithin the frame; here it isColorAction yellowAction = new ColorAction(Color.YELLOW); ... yellowButton.addActionListener(yellowAction);
so it is registering with theJButton yellowButton, which is aJComponentby inheritance. - The
yellowAction.actionPerformed()method will then get invoked when anActionEventis generated for that button. - Summary course of events:
button clicked -->
ActionEventgenerated and put on event manager queue --> .. --> event comes to the top of queue --> its listener method,yellowAction.actionPerformed(), is invoked. - All of the other events and listeners are similar, but the information packaged with the event and the message of the listener are different in each case.
How a low-level mouse click is handled
Here is another example of an event and listener, in this case a custom component listening to mouse clicks- User clicks mouse on custom
JPanel. - This gets packaged as a
MouseEventobject by the system and put on the event manager queue. - When that event comes to top of queue, event manager delegates that mouse event to the button component by looking at what component sits on the x,y position of the click.
- That component has a listener, a
MouseListener, attached to it - Method
mousePressed()on thatMouseListeneris invoked MouseListeneris in fact just an interface: the user wrote their own class implementingMouseListenerthat has methodMousePressed().
Mousetest.java
class MouseHandler for such a listener.
- This
MouseHandlerclass sure enough implements theMouseListnerinterface and implements amousePressed()method so its sounds like it is an example of the above - But, it in fact inherits from
MouseAdapter(which in turn implementsMouseListener) - huh? - Answer:
MouseAdapterhas dummy methods for all the listener methods, meaning users don't have to write empty methods for kinds of actions they are not listening to. See the MouseListener API to see that you also need to implementmouseEntered()etc to implement the full interface.
MouseMotionListener.
The Built-in Swing Components
We briefly cover some principles of the built-in Swing components.
The Model-View-Controller (MVC) design pattern
The built-in Swing components are all based on MVC
- Model: the underlying data object (e.g. data of a text field or editor, piece position information for a board game etc.)
- View: output GUI (a
JComponentin Swing) - Controller: input event processor (a
Listenerin Swing)
- Put model-view-controller in separate class(es) to factor functionality
- In particular, none of the underying logic (model) is mixing with display (view) or input (controller) code in a single class
- Every good GUI should be factorable along these lines
Use of MVC in built-in Swing components
Let us consider the case of a JButton here.
- The
JButtonmodel needs to carefully track the mouse state- if the mouse is down the GUI needs to show the pressed-button view to the user
- if the mouse is positined over the button, the button edges may be highlighted
- the model also must generate the action events.
JButtonscome with a default modelDefaultButtonModelthat probably always does what you need. But if not, you can install your own.- There is a separate
ButtonMouseListenerfor the underlying mouse events the button interprets; but, since users never deal with this, it is private and not shown in the API documentation. - Thus, even a
JButtonhas an MVC triangle of its own:ButtonModel-JButton-ButtonMouseListener
The Template for a Built-In Swing Component
Now we will go through details of the built-in Swing component types. Here is the approximate pattern.- The built-in components inherit from
JComponent - There is some listener interface we must implement to get notification of changes
- There is an underlying model for which there is a nice default that can be used most of the time (so, you can often be blissfully ignorant of the MVC).
Swing Text Components
We will look at these in a bit more detail as a case study of the built-in Swing compnents; the rest are similar.JTextFieldis a single-line text fieldDocumentis theJTextField's model interface, andPlainDocumentis the concrete default model- This model holds the actual string being typed in as it is incrementally updated
- Special document events are generated, and programmers code to
the
DocumentListenerinterface to write a listener.
TextTest.java
example for the details.
Customizing the model
- Its possible to write your own
Documentmodel insertStringis the method called by controller to insert new strings in the model- You could override this method to e.g. allow only integer characters to be inserted into the text field
Particular Components
Here is a very brief listing of the other built-in components and examples of their use.TextArea
- Like a
TextFieldbut for 2-d, not 1-d - Also allows scrollbars to be added, and text may or may not automatically wrap.
- See
TextAreaTest.java.
JScrollPaneis a subclass ofJComponent.- it "wraps" a
JTextAreaComponent(or any other component)
---this adds scrollbar functionality to the component. - The
JScrollPane(holding aJTextArea) is what is added to the window content pane - The
JTextAreais in fact held by aJViewPortwhich is held by theJScrollPane
Labels
Labels are simple string labels in windows; seeJLabel.
Check Boxes
JCheckBox is the class.
- All checkboxes come with a label
- to listen, install an
ActionListenerinterface, which only needs to implmenetactionPerformed - An example is
CheckBoxTest.java.
Buttons
JButton
- The
ButtonTest.javaexample above covered the basics - See
Calculator.javafor a larger example
Radio Buttons
JRadioButton
- Only one of a group should be selected at once
- So, make a
ButtonGroupandaddeach radio button to the group - If one radio button in a group is selected, any other ones deselected
- See
RadioButtonTest.java.
Borders
Border class.
ButtonGroup's may have aBorderwith them.- Many varieties: titles, etched, line, beveled, etc
Bordersmay wrap otherBorders to get multiple effects- See
BorderTest.java
Other Built-In Components
JMenufor menus; seeMenuTest.java.JListfor lists that items may be selected fromJComboBoxfor combo boxes; seeComboBoxTest.java.JFileChooserfor choosing files; seeFileChooserTest.java.JSliderfor sliders; seeSliderTest.java.JToolBarfor toolbars; seeToolBarTest.java.- Many others!
Dialogs
Dialogs are transient windows.- Modal: can't do anything else when its open
- Modeless: can do other things
- Dialog.show doesn't return until the dialog is closed or made visible: has a response. In other words, a separate thread is not spawned for a dialog.
JoptionPane.
Making your own dialog
- Extend
JDialog - pretty much like a
JPanelotherwise: it has aJRootPaneas well. - See
DialogTest.java.