File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
The moose likes Swing / AWT / SWT and the fly likes TwoButtons App From Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » Swing / AWT / SWT
Bookmark "TwoButtons App From "HeadFirst Java" Book" Watch "TwoButtons App From "HeadFirst Java" Book" New topic

TwoButtons App From "HeadFirst Java" Book

Bob Nedwor
Ranch Hand

Joined: Aug 17, 2005
Posts: 215

For some reason I am not getting the same result from running the TwoButtons program K&B have on p. 379 of their "HeadFirst Java" book. When I run the app, I see no difference in the background of the "I'm a label" JLabel and the drawPanel. It is almost as if the line isn't working that reads: frame.getContentPane().add(BorderLayout.WEST, label);

Thanks for any hints as to what I might be doing wrong. I am a serious newbie at AWT/Swing, so I really appreciate it.

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class TwoButtons {

JFrame frame;
JLabel label;

public static void main (String [] args) {
TwoButtons gui = new TwoButtons();

public void go() {
frame = new JFrame();

JButton labelButton = new JButton("Change Label");
labelButton.addActionListener(new LabelListener());

JButton colorButton = new JButton("Change Circle");
colorButton.addActionListener(new ColorListener());

label = new JLabel("I'm a label");
MyDrawPanel drawPanel = new MyDrawPanel();

frame.getContentPane().add(BorderLayout.SOUTH, colorButton);
frame.getContentPane().add(BorderLayout.CENTER, drawPanel);
frame.getContentPane().add(BorderLayout.EAST, labelButton);
frame.getContentPane().add(BorderLayout.WEST, label);

class LabelListener implements ActionListener {
public void actionPerformed (ActionEvent event) {

class ColorListener implements ActionListener {
public void actionPerformed (ActionEvent event) {


class MyDrawPanel extends JPanel {
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;

int red = (int) (Math.random() * 255);
int green = (int) (Math.random() * 255);
int blue = (int) (Math.random() * 255);
Color startColor = new Color(red, green, blue);

red = (int) (Math.random() * 255);
green = (int) (Math.random() * 255);
blue = (int) (Math.random() * 255);
Color endColor = new Color(red, green, blue);

GradientPaint gradient = new GradientPaint(70,70,startColor, 150,150, endColor);

[ October 26, 2005: Message edited by: Bob Nedwor ]
[ October 26, 2005: Message edited by: Bob Nedwor ]

Bob N
SCJP - 1.4
SCJD - (B&S) Used 1.5 And It Runs On Solaris10
SCWCD - Thanks to HFSJ!!
Brian Cole
Ranch Hand

Joined: Sep 20, 2005
Posts: 878
Well if you can read the text "I'm a label" (or "Ouch") then
the frame.getContentPane().add(BorderLayout.WEST, label) line
is indeed working.

There are two reasons you see no difference in the backgrounds
of the JLabel and the drawPanel. The first is that the JLabel
defaults to isOpaque()==false, so it doesn't paint its background
and the background color of the frame's contentPane shows through.
You can change this by calling label.setOpaque(true).

The second reason is that (at least in my LnF) that the background
of the opaque JLabel happens to be the same color as the apparent
background of the drawPanel, so there is no visible difference.
You can change this by calling label.setBackground(

I say the "apparent" background of the drawPanel because the
drawPanel isn't opaque either, so the background you see is
that of the contentPane showing through.
Theoretically, you should be able to call drawPanel.setOpaque(true)
and drawPanel.setBackground(Color.yellow), but this won't work because
the author of this code has overridden paintComponent() in such a
way that the value of isOpaque() is ignored. The drawPanel is
effectively always transparent.

This was not wise on the author's part, IMHO, as the javadocs for
paintComponent() say "Further, if you do not invoker super's
implementation you must honor the opaque property, that is if this
component is opaque, you must completely fill in the background in
a non-opaque color. If you do not honor the opaque property you will
likely see visual artifacts."
As they hint, an easy way to fix this is to add a call to super.paintComponent(g) as the first line of drawPanel's paintComponent().

If I were the author if this code, I would probably also change
frame.getContentPane().add(BorderLayout.xxxx, yyyy);
frame.getContentPane().add(yyyy, BorderLayout.xxxx);

It will work as written, but the javadocs for add(String, Component)
say "This method is obsolete as of 1.1. Please use the method
add(Component, Object) instead."

bitguru blog
Bob Nedwor
Ranch Hand

Joined: Aug 17, 2005
Posts: 215

Brian, Thanks for the explanation. I just realized that it works better using the paintComponent method that was 14 pages back on p. 365, rather than the one that was only 12 pages back on 367. Unless I missed something else, this was not entirely clear..

But the new one does have the line:
g.fillRect(0,0,this.getWidth(), this.getHeight());

and works much better. Thanks so much.
Brian Cole
Ranch Hand

Joined: Sep 20, 2005
Posts: 878
I can't look at the code on page 367 because I don't have the book.
In fact, I had never heard of "HeadFirst Java" before your posting
yesterday. Looking it up on the web, I see that it is an O'Reilly
book with a nontraditional approach. I'll have to check it out next
time I have some free time in a book store.

Anyway, a plain g.fillRect(0,0,this.getWidth(), this.getHeight())
is not necessarily what you want because (in the absence of an
enclosing if clause) the panel will be permanently opaque.

If I were to rewrite MyDrawPanel, I might do it like this:

But if I were the author of "HeadFirst Java" I wouldn't necessarily
do it this way. It would depend on what the I was trying to do with
this example.
I agree. Here's the link:
subject: TwoButtons App From "HeadFirst Java" Book
It's not a secret anymore!