CS 3230 - Chap 7 Notes

Graphics Programming

In this week's installment, we enter the world of GUI programming and learn how to write graphical apps.

Graphics programming in Java has changed significantly since its inception. I'll call attention to a few historical notes, but I'll direct your attention to the current way of doing things, so as to not introduce a lot of clutter into your brain.

Also, we'll touch on some of the material in Chapter 9, but not a whole lot of it.

Vocabulary Terms

Control: A little GUI thing that you can twiddle with the mouse, like a button, a scrollbar, a list box, etc.

Toolkit: Basically means a set of GUI controls. Sometimes called a "widget set".

Container: GUI thing that can hold one or more controls.

Component: Refers to a set of GUI classes, both components, and containers.

The Swing Toolkit (p.235)

Historical note: AWT vs. Swing (p.235)

As we learned, "portability" was one of the design goals of Java; "Write Once Run Anywhere". For console programming, this problem was largely solved by making a virtual machine. GUI programming presented a new challenge, though: how to make a portable graphics library?

The first approach was to make a toolkit that would just instantiate the "native" controls on whatever platform it was running on. The idea here was that Java apps could just "blend in" with the native apps because they would use the same, native controls. However, with this approach came a number of problems:

In 1996, Netscape made a new toolkit called "IFC" (Internet Foundation Classes) which just drew bare windows and painted various GUI controls on top of them. Hence, controls looked the same on all platforms and you were not limited to any single platform's set of available controls. Sun quickly adopted this toolkit and renamed it "JFC" (Java Foundation Classes).

One problem remained though, Java apps did not "blend in" nicely with native apps. To solve this, the Sun folks added Pluggable Look And Feel (or "PLAF", p.237-8) or "themes" that would make JFC components look like native components. Have a look at j2sdk1.4.1_01/demo/jfc/SwingSet2/SwingSet2.jar (or something similar -- they move it around with different releases of the JDK). You can run it by typing:

java -jar SwingSet2.jar
Play around with the "Look & Feel" menu. Note that for copyright reasons, not all Look & Feels are available on all platforms. When this demo app was first demonstrated, the Sun folks played Swing music in the background, so they've called this toolkit "Swing" ever since. (The terms "Swing" and "JFC" can be used interchangably.)

One other thing: You will notice that all the Swing components have cute little letter 'J's in front of them. The original, AWT components did not have these, but when the Swing components were released, the Java designers wanted to distinguish the Swing components from the AWT ones, while still giving developers a hint as to which Swing components correspond to the AWT ones. Additionally, it allows developers to import AWT and Swing classes into the same namespace.

Frame: Where It All Starts (p.239)

All GUI apps in Java start with a Frame. More specifically, in Swing, they start with a JFrame (this will be a test question).

Source Code: SwingFrame.java - Very basic code for a frame, heavily commented.

Introduction to Layout Managers (Ch9, p.341)

When discussing GUI programming in Java, a discussion of "layout managers" is unavoidable.

What the heck is a layout manager? In a nutshell, a layout manager is a pre-defined way to arrange components within a container (such as a Frame). The Java designers made these in an effort to make Java apps more cross-platform by making them less dependant on screen resolution or screen coordinate systems. ('Nother test question)

FlowLayout (p.342)

This is the default layout manager for the Panel (JPanel). Components just flow into it, left to right, top to bottom.

Source Code: FlowExample.java - Makes a panel, puts a bunch of buttons in it and adds it to the frame. Note how the layout manager repositions the buttons when you resize the frame.

Historical Note: It used to be that you would just call frame.add(...) to add components to a frame. With Swing, you're supposed to say frame.getContentPane().add(...) to add stuff.

BorderLayout (p.343)

This is the default layout manager for the Frame (JFrame). North, South, East, West, Center sections. Look at the picture on p.343.

Source Code: BorderExample.java - Makes a frame and adds 5 buttons to each section. Note how the layout manager resizes the buttons as you resize the frame.

The Useful Panel (Ch9, p.344; also Ch7, p.246)

The alert student will note that, per the previous explanation of the BorderLayout, you cannot put more than 5 components (GUI controls) in a Frame. This is a little limiting. How do you get around this?

Source Code: UsefulPanel.java shows how you can use a panel to add more than one button to more than one section of a BorderLayout.

Historical Note: The Canvas was originally used for drawing in AWT. Nowadays, you can just use a JPanel and call paintComponent() to draw on it. (Seamless segue into...)

Drawing Stuff (p.251)

Here's some skeleton code for drawing: (p.248)

class DrawProg {
    public static void main(String[] args){
        JFrame frame = new JFrame();
		frame.getContentPane().add(BorderLayout.NORTH, new MyPanel());
	}
}

class MyPanel extends JPanel {
	public void paintComponent(Graphics g) {
		// you probably want to do this first
		super.paintComponent(g);
		// then do your own drawing using the Graphics2D class
		Graphics2D g2 = (Graphics2D)g;
		g2.draw(...);
		...
	}
}

Historical Note: In AWT, you used the Graphics class with a variety of methods (such as drawLine(), drawPolyLine(), drawRect(), drawRoundRect(), etc.).

Nowadays, you should use Graphics2D and just call its draw() method which takes a shape that knows how to draw itself. (Mmmm... That's good polymorphism.) See Listing 7-3 p.251, p.256 for an example. (Another seamless segue into a discussion of...)

Shapes (p.253)

Construct one of the following shapes, pass it to Graphics2D.draw() and watch it draw itself.

Note on floating-point literals: (p.252) You might think that 0.35 is the literal for a float type. It's not, it's a double literal. To make it a float literal, append a little 'f' (upper or lower case) to the end.

Source Code DrawTest.java This is Listing 7-4 on p.256 in your book.

Colors (p.258)

Color class: Note that there are some predefined constants in the table on p.258 (which should be in lower case) as well as a constructor for creating a custom color.

Graphics2D.setPaint() method: (p.258) Pass an instance of Color (or a predefined constant) to this method to set the color that will be used to paint everything thereafter.

System Colors: (p.259, 260) Swing gives you the ability to use the native system colors (AWT didn't let you do this). See the table on p.260 and the line of example code toward the top of page 259.

The Graphics2D.fill() method: Use this as an alternative to draw() to draw a shape filled with a particular color.

Source Code: FillTest.java This is Listing 7-5 on p.261 in your book.

Text / Fonts (p.262)

Font class: (p.263 bottom) Shows how to construct a Font object. The pages that follow give numerous complicated examples that you are probably not interested in.

Drawing text: Graphics2D.setFont(): (p.264) Pass your Font instance to this method to set the font for all text that will be painted thereafter.

Drawing text: Graphics2D.drawString(): (p.264) Pass a string and an x,y coordinate to this method to draw text on the screen using a font.

Source Code: FontTest.java This is Listing 7-6 on p.266 in your book.

Images (p.270 bottom)

Loading an image from a file with ImageIO: (p.271 top) This is the easiest way to load an image from a file. Note that this is a blocking call, meaning it will not return until the image is completely loaded. This is nice because it prevents you from attempting to draw the image before it is completely loaded.

Displaying an image with Graphics2D.drawImage(): (p.271) Pass your image along with an x,y coordinate to the drawImage() method. (Just pass null for the 'ImageObserver' argument.

Source Code: ImageExample.java - Displays everyone's favorite Dr. Who companion.