CPSC 329 Software Development Fall 2017

CPSC 329 Lab 6: Swing

The goal of this lab is to make sure that everyone is comfortable with the basics of GUI programming in Java using Swing, and to provide some direction for extending that knowledge into more advanced aspects of working with Swing. The focus is on creating a GUI by hand rather than using a GUI builder tool in order to better understand what is going on in the program and how the different elements work.

Objectives

Successful completion of this lab means that you:

Collaboration

Work in pairs (and one group of three) to complete this lab. Only one person needs to carry out the steps in the lab but everyone in the group should make sure they understand what is going on. There is no limit on collaboration with others, but you need to make sure that you understand for yourself how (and why) to do things.

Due Date and Deliverables

due Tue Oct 17 at the start of class

One handin per group.

For full credit, you should complete the calculator application covered in the "Try It" section of "Creating a GUI with Swing" and should explore something from the "More Advanced Elements" section.

To hand in the lab, create a handin tag as directed. Make sure that you also have a readme.txt file (as described in "Setup" below) and that you've described what you did/investigated for this lab.


Setup

Create a project for this lab:

Reference Information

There are two main official sources of information: the Swing Tutorial and the Java API. The tutorial is a better place to start for an introduction to a particular type of component or layout manager; use the API once you have a basic familiarity with a thing and need more specifics about its methods.

You can Google "java 8 classname" to access the API for a given class (replace "classname" with the actual class name) and "using swing components" or "using layout managers" for the relevant section of the Swing tutorial. (If you are looking for a particular thing within the tutorial, you can add that to your search e.g. "using swing components jtextfield" or "using layout managers gridlayout". Note that the desired link may not be the first one in the search results, though it will usually be close to the top - look for a page title involving "The Java Tutorials" and/or a URL involving docs.oracle.com for the official Java reference.)


Creating a GUI with Swing

GUI Programming

GUI programs (of any sort, not just Java programs) are typically event-driven. In a traditional console-based imperative programming paradigm, execution of the program starts in main and can be traced all the way to the end of the program just by reading through the statements in order. By contrast, event-driven programs contain a main loop that listens for events and a collection of event handlers that are triggered when an event occurs. Each event handler does some small task which is quickly done.

In Java, the main loop is handled by the system so you only need to worry about the initial setup of the GUI and the event handlers.

Note: the "small task which is quickly done" aspect of event handlers is very important - events are handled one at a time in order, so while one event handler is running, the program does not respond to any other events (or repaint requests). This has important consequences for the design of the methods in a GUI program - you do not want a playGame method that carries out the entire sequence of player turns or a runSimulation method which contains a loop to carry out many steps of the simulation, for example. Instead, the program's execution is divided into chunks based on user interactions - the event handler for the "start" button handles setting up the game but only goes as far as the next user interaction, not through the entire game. In the latter case, where there is a long computation that takes place without user interaction, the task needs to be backgrounded. Timers can be used in the case of a simulation where there is a short task (one step) that happens periodically. Threads are needed in other situations. (More on threads later in the course.)


Basic Components and Layout

With Swing, everything you see on the screen (windows, text, images, buttons, menus, etc) is represented by an object in the program. The Swing tutorial used to include a nice visual guide to all of the components; it has disappeared from the official tutorial but you can still find older versions of it if you Google "visual guide to swing components". (The tutorial now contains a list of the various kinds of components, which you can find by searching "swing tutorial how to use various components".)

Containers are special kinds of components that can contain other components. Top-level containers (such as JFrame) do not need to be contained - they can just be created and used.

The position and size of the components within a container can be specified manually, but is more commonly determined by a layout manager. Using layout managers simplifies the programmer's task and also allows the window to be resized gracefully. The Swing tutorial does still provide a visual guide to layout managers (Google "swing tutorial visual guide to layout managers") to aid in selecting a layout manager. Complex layouts can be created from just a few of the simpler layout managers (BorderLayout, BoxLayout, and GridLayout) by nesting containers (typically JPanels).

Putting It All Together

There are six basic steps for creating a GUI in Swing:

Swing components come from the javax.swing package. Some elements from the older AWT are also still used, so you will generally also need the java.awt package. You can let Eclipse prompt you for the imports as needed but you should be aware of the correct package in case you need to choose between several suggested choices.

SimpleGUIDemo provides an example. It also demonstrates nesting components to achieve a more complex layout - the buttons are contained in a panel and laid out in a row using BoxLayout, then the window itself is laid out with a BorderLayout (buttons at the top, CirclePanel in the center).


Handling Events

GUI programs actually do things in response to events - these are typically user-generated (mouse movement, mouse clicks, key presses, and other manipulations of GUI controls) but may also be generated by the system (such as from timers). Event handlers contain the code to handle the event i.e. to do whatever the program should do to respond to an event.

Putting It All Together

Event handling adds two more steps to the six steps already given above:

Event-related elements (event classes and event listener interfaces) come from the java.awt.event package.

SimpleGUIDemo2 adds event listener registration to the example in the previous section; ColorChanger contains the event listener for the buttons.


Code Organization

The examples above show one way to organize the setup and event handler code - the setup code is in main and event listeners are in separate classes - but that is not the only (or even necessarily the best) way.

Setup Code

An alternative to putting the setup code in main (like in the example) is to create a subclass of JFrame and to put the setup code in the constructor of the subclass. main then just creates an instance of that subclass.

While a little more complex (there's another class), this organization is preferred because it allows for greater flexibility and reuse - a program can easily have two or more circle windows by creating more instances of the frame subclass, and another program can easily use the frame subclass without having to cut and paste code.

Event Listeners

In keeping with single purpose and the potential for reuse, there should be only one behavior per event handler method. This means that you shouldn't generally have an if statement that checks which component generated the event in order to determine what to do - create separate classes (inner or public) for each case, and register the appropriate listener object with each component. (If the difference is the value rather than the behavior itself - such as in the example above where ColorChanger's constructor takes the color to use - parameterize one class so the value can be configured instead of having separate classes with different hardcoded values.)

There are several choices for where to put event listener code:

The first two options are generally preferable - while they are a little more complex (more classes), they do a better job of separating components and layout from event handling. The first option (separate public/package classes) is the best solution if the event handler could be used in other situations, as it separates how events are handled from the particular components and how they are arranged. If, however, the event handlers are highly specific and won't be reused (either within the current program or elsewhere), the second option (inner classes) better encapsulates the GUI elements.

The third option is OK in simple cases but is not modular or single purpose, is not reusable, and isn't suitable if there are different behaviors for the same kind of event because there can only be one method with a given name in a class and thus there will need to be an if statement to determine which component generated the event so it can be handled correctly.


Try It

Your goal is to implement a basic calculator program. The calculator functionality is already provided for you in the Calculator class that you imported; you'll just be adding the GUI.

To see a demo of how the program should operate, run

   java -jar /classes/cs329/lab6/guicalc.jar

To input a number, click on the appropriate digit buttons or type it directly into the input box (the second text field). When you click an operator button, the corresponding calculator method is invoked using the value in the input box and the calculator display (the first text field) is updated to show the result of the calculation.

The "Z" button invokes the calculator's zero method. On the "File" menu, "Clear", "Store", and "Load" each invoke the corresponding calculator method. "Store" prompts the user for the name to use; "Load" lets the user select the name from a list of those which have been defined. "Quit" quits the program.

Note that the operation of this calculator is a little different from most calculators. This is due in part to how Calculator's operator methods are defined (each only takes one parameter because the other operand is the calculator's current value) and in part to an attempt to keep the implementation of the calculator interface as simple as possible. To use the calculator successfully, it is necessary to keep two things in mind:

Thus, for example, computing 8*3+2 means that the calculation is really 0+8*3+2 and is entered as Z 8 + 3 * 2 +.


More Advanced Elements

Explore something from this section. Which topic(s) you explore and how far you go with them are up to you. You are encouraged to consider things that might be useful for the project and use this lab as an opportunity to figure them out.

Standard Components

Swing provides many types of components, including buttons, checkboxes, radio buttons, lists, combo boxes, text fields and editors, sliders, spinners, menus,tool bars, progress bars, scroll panes, color choosers, file choosers, and dialog boxes. Browse the list of available components (search for "using swing components") and explore how to use one or more of them.

Events Other Than ActionEvents

Many components generate various kinds of events that can be handled. Google "listeners supported by swing components" for an overview. Writing listeners for other kinds of events is similar to writing ActionListeners - the difference that you are implementing a different interface with a different name for the handler method. Look up "writing event listeners" in the Swing tutorial for more information.


Custom Components

If the standard GUI components aren't sufficient for your application, you'll need to create a custom component. Typically this is done by subclassing JPanel (a basic lightweight component), but it is possible to subclass other components.

Custom Painting

The most common reason to need to create your own component is for painting.

This is done by subclassing the desired component (e.g. JPanel) and then extending its paintComponent(g) method to do the desired painting. CirclePanel provides an example.

The upper left corner of the component is always (0,0) regardless of where the component is on the screen.

Note: Be sure to call super.paintComponent(g) (substitute the actual name of the Graphics parameter for g as needed) as the first thing in the body of your paintComponent. Your paintComponent should add on to the parent component's painting behavior, not completely replace it.

Note: paintComponent is called by the system any time a component needs to be drawn (e.g. when a window is revealed or when requested by a call to repaint()). Never call it directly (only call repaint) and also don't put non-painting code there (because you don't fully controlled when paintComponent may be called).

Note: Since the size of the component is controlled by a layout manager, it is important to take into account the size of the component when positioning and sizing the elements being painted. For example, if you want a component to display a 20x20 grid of fish and sharks, compute the size of the grid cell based on the size of the component rather than always making a cell a fixed number of pixels on a side. (See CirclePanel for an example.) Be careful to distinguish between things which should have fixed sizes/positions and those which should be sized/positioned relative to the component.

Events on Custom Components

You may also be interested in handling events on your custom component. What events can be generated depends on the component type that you extended; JPanel supports the event types that all Swing components support but does not have any special ones of its own. Look up "listeners supported by Swing components" in the Swing tutorial for more information on what those listeners are.


Layout and Sizing

Swing provides several layout managers. (Look up "visual guide to layout managers" in the Swing tutorial for an overview.) You can create quite complex layouts with just a few of the simpler layout managers by nesting JPanels so you will likely not ever need any more than that.

Layout managers both position and size the components within a container. Look up "solving common layout problems" in the Swing tutorial for information about how to influence the size of a component.

If you have special layout needs that cannot be solved with the standard layout managers, it is possible to write your own. Look up "creating a custom layout manager" in the Swing tutorial for more information.

Doing without a layout manager and manually specifying sizes and positions of components is generally not recommended because it does not allow for resizing. However, it is sometimes appropriate and you can look up "absolute positioning" in the Swing tutorial for more information.


Java 2D

The Java 2D API provides support for all sorts of 2D graphics, including drawing geometric primitives and arbitrary shapes, changing fill and stroke patterns, and working with text and images. Google "java tutorial 2D graphics".


Drag and Drop

Locate the lesson on "Drag and Drop and Data Transfer" in the Swing tutorial. Try out drag and drop from components where it is already fully supported (such as dragging from a JList to another JList or into a JTextField). If you want to go farther, investigate how to do drag and drop for other components. (For this, considering a particular application - perhaps something useful for the project - would give you something concrete to focus on.)


Look and Feel

"Look and feel" refers to the appearance and behavior of the various components in an application. Locate and explore the lesson "Modifying the Look and Feel" in the Swing tutorial - determine what look and feel options are available and try selecting one. If you want to go farther, can you find third-party look and feel implementations that you can download and try? Creating your own look and feel is also a possibility if you are feeling ambitious.


Handin


Valid HTML 4.01!