Java: Example - Raise.java

This program program was inspired by a Gore-Bush ballots in Florida. The paintComponent method looks too complicated and could be improved. Also, there's no need to redraw all the fixed elements; these could be drawn only once and saved in a BufferedImage.

The main program / applet

  1 
  2 
  3 
  4 
  5 
  6 
  7 
  8 
  9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
// File: wantRaise/Raise.java
// Description: Applet+application to ask employee if they want a raise.
//              Example of mouse listeners, borderlayout, ...
// Author: Fred Swartz
// Date:   2005-02-03 2000-12-01 ... 2002-02-19

package wantraise;

import javax.swing.*;

////////////////////////////////////////////////////////////////////// Raise
public class Raise extends JApplet {
    
    //=================================================== applet constructor
    public Raise() {
        add(new RaiseGUI());
    }
    
    //================================================================= main
    public static void main(String[] args) {
        JFrame w = new JFrame("Employee Survey");
        w.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        w.setContentPane(new RaiseGUI());
        w.setResizable(false);
        w.pack();
        w.setVisible(true);
    }
}

The GUI panel

  1 
  2 
  3 
  4 
  5 
  6 
  7 
  8 
  9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
 38 
 39 
 40 
 41 
 42 
 43 
 44 
 45 
// File: wantRaise/RaiseGUI.java
// Description: Panel to display the raise info
// Author: Fred Swartz
// Date:   2005-02-03 2000-12-01 ... 2002-02-19

package wantraise;

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

//////////////////////////////////////////////////////////////// RaiseGUI
class RaiseGUI extends JPanel {
    private SurveyForm survey = new SurveyForm();

    //======================================================== constructor
    public RaiseGUI() {
        //... Create components
        JButton resetButton = new JButton("Reset");
        // To make label background blue, put it on a blue panel.
        JLabel title = new JLabel("Want a Raise?", JLabel.CENTER);
        title.setFont(new Font("Serif", Font.BOLD, 48));
        title.setForeground(Color.white);
        JPanel titlePanel = new JPanel();
        titlePanel.setBackground(Color.blue);
        titlePanel.add(title);
        
        //... Add listener to button
        resetButton.addActionListener(new ResetListener());
        
        //... Layout components
        this.setLayout(new BorderLayout());
        this.add(titlePanel , BorderLayout.NORTH); 
        this.add(survey     , BorderLayout.CENTER);
        this.add(resetButton, BorderLayout.SOUTH);
    }
    
    //================================================ inner class listener
    private class ResetListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            survey.reset(false);
        }
    }
}

The Graphics panel that draws the "buttons"

  1 
  2 
  3 
  4 
  5 
  6 
  7 
  8 
  9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
 38 
 39 
 40 
 41 
 42 
 43 
 44 
 45 
 46 
 47 
 48 
 49 
 50 
 51 
 52 
 53 
 54 
 55 
 56 
 57 
 58 
 59 
 60 
 61 
 62 
 63 
 64 
 65 
 66 
 67 
 68 
 69 
 70 
 71 
 72 
 73 
 74 
 75 
 76 
 77 
 78 
 79 
 80 
 81 
 82 
 83 
 84 
 85 
 86 
 87 
 88 
 89 
 90 
 91 
 92 
 93 
 94 
 95 
 96 
 97 
 98 
 99 
100 
101 
102 
103 
104 
105 
106 
107 
108 
109 
110 
111 
112 
113 
114 
115 
116 
// File: wantRaise/SurveyForm.java
// Description: Panel draws form, uses mouse listeners.
// Author: Fred Swartz
// Date:   2005-02-03 2000-12-01 ... 2002-02-19

package wantraise;

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

/////////////////////////////////////////////////////////// class SurveyForm
class SurveyForm extends JPanel implements MouseMotionListener {
    private final int RADIUS     = 16;  // Radius of both buttons
    private final int DIAM       = 2* RADIUS;

    private boolean m_isNoRaiseSelected = false; // set true after button selected
    private int     m_buttonX;  // x-coord of movable button.
    private int     m_buttonY;
    private int m_x = 0; // The mouse coords set by mouse listeners.
    private int m_y = 0; // paintComponent uses them to calc No Raise pos.

    //========================================================== constructor
    public SurveyForm() {
        this.setBackground(Color.white);
        this.setPreferredSize(new Dimension(300, 230));
        this.setFont(new Font("Serif", Font.BOLD, 48));
        this.addMouseMotionListener(this);
    }
    
    //================================================================ reset
    public void reset(boolean isNoRaiseSelected) {
        // Called from "outside" to clear the status..
        m_isNoRaiseSelected = isNoRaiseSelected;
        this.repaint();       // Repaint to show change.
    }

    //======================================================= paintComponent
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        
        //... Use constants to make changes+debugging easier.
        final int LABEL_X   = 20;    // x coord of both labels
        final int BUTTON_X  = 240;   // x coord of both buttons
        final int CRITICAL_DIST = 3 * RADIUS;
        final int SIDE      = 6 * RADIUS; 
        final int LEFT      = BUTTON_X - CRITICAL_DIST;
        
        //... No Raise button info
        final int NORAISE_Y = 80;  // y coord of NoRaise button
        
        //... Top and bottom of area that affects  Raise button
        final int RAISE_Y   = NORAISE_Y + 100;
        final int CENTER_Y  =   RAISE_Y - RADIUS; // Default y coord of Raise
        
        final Rectangle NR_BOUNDS = new Rectangle(LEFT, NORAISE_Y-CRITICAL_DIST, SIDE, SIDE);
        final Rectangle  R_BOUNDS = new Rectangle(LEFT,   RAISE_Y-CRITICAL_DIST, SIDE, SIDE);
        
        //... Draw button labels.
        g.setColor(Color.black);
        g.drawString("No Raise", LABEL_X, NORAISE_Y);
        g.drawString("Raise"   , LABEL_X,   RAISE_Y);

        //... Check if near "No Raise" button, and "select" it if so.
        if (m_isNoRaiseSelected || NR_BOUNDS.contains(m_x, m_y)) {
            //... Draw selected No Raise button and unselected Raise button
            g.fillOval(BUTTON_X-RADIUS, NORAISE_Y-DIAM, DIAM, DIAM);
            g.drawOval(BUTTON_X-RADIUS,   RAISE_Y-DIAM, DIAM, DIAM);
            m_isNoRaiseSelected = true; // "Select" No Raise button.
            
        } else {
            //... Draw empty No Raise button (doesn't depend on mouse position)
            g.drawOval(BUTTON_X-RADIUS, NORAISE_Y-DIAM, DIAM, DIAM);

            //... Draw Raise button (depends on mouse position)
            m_buttonX = BUTTON_X;// Assume default position; may change.
            m_buttonY = CENTER_Y;
            
            if (R_BOUNDS.contains(m_x, m_y)) {
                //... Mouse is near the Raise button, so we may move it
                int xDisplacement = BUTTON_X - m_x;
                int yDisplacement = CENTER_Y - m_y;
                
                //... Compute distance of mouse from center.
                double mouseDist = Math.sqrt(xDisplacement * xDisplacement 
                                           + yDisplacement * yDisplacement);
                if (mouseDist < CRITICAL_DIST) {
                    // ... It's within the critical radius.
                    double bdist = CRITICAL_DIST - mouseDist;
                    double ratio = 1.0;
                    if (mouseDist > 1.0) {
                        ratio = bdist / mouseDist; // Avoid div by 0.0
                    }

                    m_buttonX = BUTTON_X + (int)(ratio * xDisplacement);
                    m_buttonY = CENTER_Y + (int)(ratio * yDisplacement);
                }
            }
            g.drawOval(m_buttonX-RADIUS, m_buttonY - RADIUS, DIAM, DIAM);
        }
    }

    //================================================== mouseMoved listener
    public void mouseMoved(MouseEvent e) {
        this.m_x = e.getX();
        this.m_y = e.getY();
        this.repaint();
    }  
    
    //================================================== mouseMoved listener
    /* Drag listener to prevent sneaking onto Raise button. */
    public void mouseDragged(MouseEvent e) {
        mouseMoved(e);
    }
}