Chitika

Showing posts with label layout. Show all posts
Showing posts with label layout. Show all posts

Saturday, June 16, 2007

Sample Calculator GUI in Java Swing

Recently, I was giving my 1st-year IT students several Swing GUI exercises on OOP with Java lab sessions. One of the exercises was to create a simplified Calculator GUI that looks like the Calculator on standard Windows OS. The objective of the exercise was to make the students familiar with the basic Swing layout managers (note: I haven't thought them GridBag, Spring, or JGoodies Forms layouts), and the basic event-handling mechanism in Swing. The exercise was also meant for the students to learn more about the OOP concept in practice.




Here's the code that I gave the students at the end of the session:








public class Calculator {

  // constant values
  public static final int NONE = -1;
  public static final int ADD = 0;
  public static final int SUBTRACT = 1;
  public static final int MULTIPLY = 2;
  public static final int DIVIDE = 3;

  // values to be stored in the calculator memory
  private double leftValue = 0.0;
  private double rightValue = 0.0;
  private int lastOperation = NONE;
  private double multiplier = 1;
  private boolean DOT = false;

  // the user hits the + button
  public double add () {
    lastOperation = ADD;
    resetDOT();
    return leftValue;
  }

  // the user hits the - button
  public double subtract () {
    lastOperation = SUBTRACT;
    resetDOT();
    return leftValue;
  }

  // the user hits the * button
  public double multiply () {
    lastOperation = MULTIPLY;
    resetDOT();
    return leftValue;
  }

  // the user hits the / button
  public double divide () {
    lastOperation = DIVIDE;
    resetDOT();
    return leftValue;
  }

  // the user hits the = button
  public double equate () {
    switch (lastOperation) {
      case NONE: break;
      case ADD: leftValue = leftValue + rightValue; break;
      case SUBTRACT: leftValue = leftValue - rightValue; break;
      case MULTIPLY: leftValue = leftValue * rightValue; break;
      case DIVIDE: leftValue = leftValue / rightValue; break;
    }
    rightValue = 0;
    resetDOT();
    return leftValue;
  }

  // the user hits the 0-9 button
  public double number (int i) {
    double j = i * multiplier;
    if (DOT) {
      multiplier = multiplier / 10;
    }
    if (lastOperation == NONE) {
      leftValue = leftValue * (DOT ? 10(leftValue < (-j: j);
      return leftValue;
    else {
      rightValue = rightValue * (DOT ? 10(rightValue < (-j: j);
      return rightValue;
    }
  }

  // the user hits the +/- button
  public double plusMinus () {
    if (lastOperation == NONE) {
      leftValue = -leftValue;
      return leftValue;
    else {
      rightValue = -rightValue;
      return rightValue;
    }
  }

  // the user hits the C button
  public double reset () {
    lastOperation = NONE;
    leftValue = rightValue = 0;
    resetDOT();
    return leftValue;
  }

  // the user hits the sqrt button
  public double sqrt () {
    resetDOT();
    if (lastOperation == NONE) {
      leftValue = Math.sqrt (leftValue);
      return leftValue;
    else {
      rightValue = Math.sqrt (rightValue);
      return rightValue;
    }
  }

  // to reset the DOT & multiplier
  private void resetDOT() {
    DOT = false;
    multiplier = 1;
  }

  // the user hits the . button
  public double dot () {
    if (!DOT) {
      DOT = true;
      multiplier = 0.1;
    }
    return lastOperation == NONE ? leftValue : rightValue;
  }
}




I divided this small application into two different classes. The Calculator class above will act as the model for the application, and is responsible to maintain the state of the Calculator and to handle the user actions. Having a minimum amount of time duration for the lab session, many of the Calculator features were not implemented. Many exceptions were not caught nor handled properly, and there's a slightly different behavior with the sqrt button (when you compare it with the Windows OS version).

The whole point of this Calendar application was not to make a copycat of Windows OS version, rather it was to illustrate to the students what they can do with OOP and Swing.

Here's the second part of the application:








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

public class CalculatorGUI implements ActionListener {

  private Calculator c = new Calculator ();

  private JFrame frame = new JFrame ("Calculator");
  private JPanel[] panels = new JPanel [6];
  private JTextField textField = new JTextField();
  private JButton resetButton = new JButton(" C ");
  private JButton[] numberButtons = new JButton[10];
  private JButton divideButton = new JButton ("/");
  private JButton multiplyButton = new JButton ("*");
  private JButton subtractButton = new JButton ("-");
  private JButton plusMinusButton = new JButton ("+/-");
  private JButton dotButton = new JButton (" . ");
  private JButton addButton = new JButton ("+");
  private JButton equateButton = new JButton (" = ");
  private JButton sqrtButton = new JButton ("sqrt");

  public void buildGUI () {

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    JPanel contentPane = (JPanelframe.getContentPane();

    // initialize panels
    for (int i = 0; i < panels.length; i++) {
      panels[inew JPanel ();
    }

    // initialize button 0-9
    for (int i = 0; i < numberButtons.length; i++) {
      numberButtons[inew JButton (" " + i + " ");
      numberButtons[i].setActionCommand (String.valueOf(i));
      numberButtons[i].addActionListener (this);
    }

    // default layout = BorderLayout.CENTER
    textField.setColumns(20);
    textField.setText ("0");
    textField.setHorizontalAlignment (JTextField.RIGHT);
    panels[0].add (textField);

    // layout = FlowLayout.RIGHT
    panels[1].setLayout (new FlowLayout (FlowLayout.RIGHT));
    panels[1].add (resetButton);
    resetButton.setActionCommand ("RESET");
    resetButton.addActionListener (this);

    // layout = FlowLayout.LEFT
    panels[2].setLayout (new FlowLayout (FlowLayout.LEFT));
    panels[2].add (numberButtons[7]);
    panels[2].add (numberButtons[8]);
    panels[2].add (numberButtons[9]);
    panels[2].add (divideButton);
    panels[2].add (sqrtButton);
    divideButton.setActionCommand ("DIVIDE");
    divideButton.addActionListener (this);
    sqrtButton.setActionCommand ("SQRT");
    sqrtButton.addActionListener (this);

    // layout = FlowLayout.LEFT
    panels[3].setLayout (new FlowLayout (FlowLayout.LEFT));
    panels[3].add (numberButtons[4]);
    panels[3].add (numberButtons[5]);
    panels[3].add (numberButtons[6]);
    panels[3].add (multiplyButton);
    multiplyButton.setActionCommand ("MULTIPLY");
    multiplyButton.addActionListener (this);

    // layout = FlowLayout.LEFT
    panels[4].setLayout (new FlowLayout (FlowLayout.LEFT));
    panels[4].add (numberButtons[1]);
    panels[4].add (numberButtons[2]);
    panels[4].add (numberButtons[3]);
    panels[4].add (subtractButton);
    subtractButton.setActionCommand ("SUBTRACT");
    subtractButton.addActionListener (this);

    // layout = FlowLayout.LEFT
    panels[5].setLayout (new FlowLayout (FlowLayout.LEFT));
    panels[5].add (numberButtons[0]);
    panels[5].add (plusMinusButton);
    panels[5].add (dotButton);
    panels[5].add (addButton);
    panels[5].add (equateButton);
    plusMinusButton.setActionCommand ("PLUSMINUS");
    plusMinusButton.addActionListener (this);
    dotButton.setActionCommand ("DOT");
    dotButton.addActionListener (this);
    addButton.setActionCommand ("ADD");
    addButton.addActionListener (this);
    equateButton.setActionCommand ("EQUATE");
    equateButton.addActionListener (this);

    contentPane.setLayout (new BoxLayout (contentPane, BoxLayout.Y_AXIS));
    for (JPanel jPanel : panels) {
      contentPane.add (jPanel);
    }

    frame.pack ();
    frame.setVisible (true);
  }

  public void actionPerformed (ActionEvent e) {
    String actionCommand = e.getActionCommand();
    if (actionCommand == null || actionCommand.trim().length() <= 0) {
      return;
    }

    int number = -1;
    try {
      number = Integer.parseInt (actionCommand);
    catch (NumberFormatException e1) {
    }

    if (number >= 0) {
      // this is a number
      textField.setText ("" (c.number (number)));
    else {
      // this is not a number
      if (actionCommand.equals ("RESET")) {
        textField.setText ("" (c.reset()));
      else if (actionCommand.equals ("DIVIDE")) {
        textField.setText ("" (c.divide()));
      else if (actionCommand.equals ("SQRT")) {
        textField.setText ("" (c.sqrt()));
      else if (actionCommand.equals ("MULTIPLY")) {
        textField.setText ("" (c.multiply()));
      else if (actionCommand.equals ("SUBTRACT")) {
        textField.setText ("" (c.subtract()));
      else if (actionCommand.equals ("PLUSMINUS")) {
        textField.setText ("" (c.plusMinus()));
      else if (actionCommand.equals ("DOT")) {
        textField.setText ("" (c.dot()));
      else if (actionCommand.equals ("ADD")) {
        textField.setText ("" (c.add()));
      else if (actionCommand.equals ("EQUATE")) {
        textField.setText ("" (c.equate()));
      }
    }
  }

  public static void main(String[] args) {
    CalculatorGUI gui = new CalculatorGUI();
    gui.buildGUI ();
  }
}




I'm pretty sure that there are many solution variants out there. By focusing on the layout managers that are easy to use and understand, such as FlowLayout, BorderLayout and BoxLayout, I think this exercise has nicely served its main objective.

If you have any suggestions on how to help the students to understand the OOP + Swing concepts better, please do let me know.

Thursday, October 07, 2004

login GUI sample source code

Referring to my previous post, here's the source code that I made..
I decided to separate the implementation into:
- a Screen class which will manage the event handling & business delegation
- a Builder class which will be responsible for laying out the components
- constant classes, such as Fonts, Colors & Dimensions, for consistency, reusability & efficiency throughout any number of GUIs we may have
I used GridBagLayout extensively in this example, it's still one of my favourite layout because it can lay the components in almost any layout

Now, after exploring more and more, I'm considering JGoodies FormLayout & its contributor, FormLayout Maker for any well structured forms. And, ExplicitLayout for other layout which may never be possible to create using any layout manager ever existed.

Anyway, as the sharing goes..
I'm interested if anyone can suggest an idea on how the responsibility for the classes involved in a GUI be divided..
You can find my approach in the attached file, let me know yours.. :D

Further Reading:
Swing Second Edition
Java Swing Second Edition

Tuesday, October 05, 2004

Swing layout comparisons

An interesting comparison..

GBL <= TableLayout < HIGLayout < FormLayout
GBL <= TableLayout < HIGLayout < ExplicitLayout
HIGLayout < SpringLayout
BorderLayout < TableLayout
GridLayout < HIGLayout
GridLayout < FormLayout


Read their arguments here

I'm trying FormLayout Maker, and let's see how well it goes.. :D

Further Reading:
Swing Second Edition
Java Swing Second Edition

Monday, October 04, 2004

Swing layouts

Developing GUI layout in Swing requires a considerable amount of time, especially if you just starting to learn how to Swing. The easy layouts, such as FlowLayout, BorderLayout, BoxLayout, and GridLayout does not really take you anywhere, especially in the case of creating complex GUI.

Luckily, we have the powerful GridBagLayout, which is a bit complex for a startup, but can be very efficient for an experienced Swing GUI developer. However, after looking at JGoodies Forms, it's very interesting to explore more on what the community has to offer.

First, we have SpringLayout which were added into the J2SE 1.4 distribution. Then, we have FormLayout which is contributed by JGoodies. FormLayout is a very good layout which allows us to create form layouts in 1-2 hours max. I'm trying to explore through ExplicitLayout & TableLayout, and see if they have some added values as well.

I hope I can get a chance to explore more on many other available layouts.. :D

Links:
JGoodies Forms
ExplicitLayout
TableLayout

Further Reading:
Swing Second Edition
Java Swing Second Edition