Button3 (no Button2)

Main.java  [download]

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

/**
 * Main program for Button3
 */
public class Main extends JFrame {
    /** The squares */
    private Square square1, square2;

    public static void main (String [] args) {
	java.awt.EventQueue.invokeLater (new Runnable() {
            public void run() {
		new Main ();
            }
        });
    }

    public Main () {
	// Window setup
	setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
	setSize (500, 500);
	Container content = getContentPane();
	content.setLayout (new BorderLayout());

	// Our canvas
	MyCanvas canvas = new MyCanvas (this);
	content.add (canvas, BorderLayout.CENTER);

	/*
	 * Now create the square and its associated buttons
	 */
	square1 = new Square (canvas); //*1 Square 1 and its buttons

	// Control panel for the square
	JPanel controls1 = new JPanel ();
	controls1.setBorder (new LineBorder(Color.BLUE));
	controls1.setLayout (new FlowLayout());

	// Create our buttons by instantiating them
	// turns out we don't need to remember them,
	// just to add() them to panel layout
	controls1.add (new ButtonLeft (square1)); //*1
	controls1.add (new ButtonRight (square1)); //*1
	controls1.add (new ButtonBigger (square1)); //*1
	controls1.add (new ButtonSmaller (square1)); //*1
	controls1.add (new ButtonFill (square1)); //*1

	/*
	 * Another square
	 */
	square2 = new Square (canvas); //*2 Ditto Square 2
	
	JPanel controls2 = new JPanel ();
	controls2.setBorder (new LineBorder(Color.BLUE));
	controls2.setLayout (new FlowLayout());
	
	// Create our buttons
	controls2.add (new ButtonLeft (square2)); //*2
	controls2.add (new ButtonRight (square2)); //*2
	controls2.add (new ButtonBigger (square2)); //*2
	controls2.add (new ButtonSmaller (square2)); //*2
	controls2.add (new ButtonFill (square2)); //*2

	// Need a grid container to hold our 2 panels
	JPanel controls = new JPanel ();
	controls.setLayout (new GridLayout(2, 1));
	controls.add (controls1);
	controls.add (controls2);
	content.add (controls, BorderLayout.SOUTH);

	setVisible (true);
    }

    public void drawSquares (Graphics g) { //*3 MyCanvas calls us to do the job
	// For each square (this could be an array)
	square1.draw (g); //*4 We call the Squares
	square2.draw (g); //*4
    }
}

MyCanvas.java  [download]

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

/**
 * Canvas object
 */
public class MyCanvas extends JPanel implements MouseListener {
    private Main parent; //*1 Save parent for use in callback

    public MyCanvas (Main parent) {
	this.parent = parent; //*1
	setBorder (new LineBorder(Color.BLUE));
	addMouseListener (this); //*2 Catch the callback
    }

    /** Tell parent to do the job */
    public void paintComponent (Graphics g) { //*2
	super.paintComponent(g);
	parent.drawSquares (g); //*3 And call parent to do the job
    }

    /** MouseListener callbacks */
    public void mousePressed (MouseEvent event) {	
	System.out.println ("Mouse down at " + event.getPoint().x + ", " + event.getPoint().y);
    }
    public void mouseClicked (MouseEvent event) {}
    public void mouseReleased (MouseEvent event) {}
    public void mouseEntered (MouseEvent event) {}
    public void mouseExited (MouseEvent event) {}
}

Square.java  [download]

import java.awt.*;

/**
 * Square holds the "model" data for one square
 */
public class Square {
    /** Enumerated type for which action to take */
    public enum ButtonAction {LEFT, RIGHT, BIGGER, SMALLER, FILL, EMPTY}; //*5 Java enumerated type

    /** The model data */
    private Rectangle loc = new Rectangle (100, 50, 50, 50); //*1 The model data
    private boolean filled = false; //*1

    private MyCanvas canvas;

    public Square (MyCanvas canvas) {
	this.canvas = canvas;
    }

    public void draw (Graphics g) { //*2 Draw the square
	Graphics2D g2 = (Graphics2D) g;

	if (filled) g2.fill (loc); //*2
	else g2.draw (loc); //*2
    }

    public void doAction (ButtonAction action) { //*3 Handle actions
	if (action==ButtonAction.LEFT) loc.x -= 10; //*3
	else if (action==ButtonAction.RIGHT) loc.x += 10; //*3
	else if (action==ButtonAction.BIGGER) { loc.width += 10; loc.height += 10; } //*3
	else if (action==ButtonAction.SMALLER) { loc.width -= 10; loc.height -= 10; } //*3
	else if (action==ButtonAction.FILL) filled = true; //*3
	else if (action==ButtonAction.EMPTY) filled = false; //*3

	canvas.repaint(); //*4 Need full repaint in case action exposed the other square
    }
}

ButtonLeft.java  [download]

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

public class ButtonLeft extends JButton implements ActionListener {
    private Square square; //*2 Keep pointer to square we control

    public ButtonLeft (Square square) {
	this.square = square; //*2
	setIcon (new ImageIcon ("leftArrow.gif")); //*1 Handle our own properties setup
	setBorder (new LineBorder(Color.GREEN, 2)); //*1
	addActionListener (this); //*3 Handle our own callback
    }

    public void actionPerformed (ActionEvent e) { //*3
        square.doAction (Square.ButtonAction.LEFT); //*4 Call square to do the job
    }
}

ButtonRight.java  [download]

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

public class ButtonRight extends JButton implements ActionListener {
    private Square square;
    
    public ButtonRight (Square square) {
	this.square = square;
	setIcon (new ImageIcon ("rightArrow.gif"));
	setBorder (new LineBorder(Color.GREEN, 2));
	addActionListener (this);
    }
    
    public void actionPerformed(ActionEvent e) {
        square.doAction (Square.ButtonAction.RIGHT);
    }
}

ButtonBigger.java  [download]

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

public class ButtonBigger extends JButton implements ActionListener {
    private Square square;

    public ButtonBigger (Square square) {
	this.square = square;
	setText ("Bigger");
	setFont (new Font("SansSerif", Font.ITALIC, 14));
	setForeground (Color.BLUE);
	setBorder (new LineBorder(Color.GREEN, 2));
	addActionListener (this);
    }

    public void actionPerformed(ActionEvent e) {
        square.doAction (Square.ButtonAction.BIGGER);
    }
}

ButtonSmaller.java  [download]

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

public class ButtonSmaller extends JButton implements ActionListener {
    private Square square;

    public ButtonSmaller (Square square) {
	this.square = square;
	setText ("Smaller");
	setFont (new Font("SansSerif", Font.ITALIC, 14));
	setForeground (Color.BLUE);
	setBorder (new LineBorder(Color.GREEN, 2));
	addActionListener (this);
    }

    public void actionPerformed(ActionEvent e) {
        square.doAction (Square.ButtonAction.SMALLER);
    }
}

ButtonFill.java  [download]

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

public class ButtonFill extends JButton implements ActionListener {
    private Square square;
    private boolean buttonState = false;
    
    public ButtonFill (Square square) {
	this.square = square;
	setText ("Filled");
	setFont (new Font("SansSerif", Font.ITALIC, 14));
	setForeground (Color.BLUE);
	setBorder (new LineBorder(Color.GREEN, 2));
	addActionListener (this);
    }

    public void actionPerformed (ActionEvent e) {
	buttonState = ! buttonState;
	if (buttonState) square.doAction (Square.ButtonAction.FILL);
	else square.doAction (Square.ButtonAction.EMPTY);

	// Also update button label
	if (buttonState) setText ("Empty");
	else setText ("Filled");
    }
}