Skip to content

Instantly share code, notes, and snippets.

@joelgallant
Created November 20, 2012 21:43
Show Gist options
  • Save joelgallant/4121387 to your computer and use it in GitHub Desktop.
Save joelgallant/4121387 to your computer and use it in GitHub Desktop.
package calculator;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
/**
* Main class of the program. There is only one class in this program.
*
* <p>This class does what is called "extending" a different class. This means
* that it inherits all of the 'qualities' of the class. Basically
* {@link MainClass} is a custom type of {@link JFrame}, just as a mountain bike
* is a 'type' of bicycle. In this case, it extends {@link JFrame}.
* {@link JFrame} is the base for graphic windows.</p>
*
* <p>More information about inheritance and subclasses is available here :
* http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html</p>
*
* @author joel
*/
public class MainClass extends JFrame {
final JTextField textArea = new JTextField();
/**
* This is the main method. This is the only thing called by the execution.
* Everything must start from here.
*
* @param args The arguments given in the command-line. This isn't needed,
* but is a default property of main methods.
*/
public static void main(String[] args) {
// Here we call what is called the Event Dispatch Thread to open up the window.
// This is a Java specific way of creating and showing GUI (Graphical User Interfaces)
SwingUtilities.invokeLater(new Runnable() {
/**
* This is what is called an overriding method. It is run
* automatically by the SwingUtilities#invokeLater().
*/
@Override
public void run() {
// This is creating what is called a new 'instance' of the main class.
// Because this is a static method (static void main()), there is no instances of the main class yet.
// (This isn't really important for now)
MainClass m = new MainClass();
// This is setting the properties of the window. Without a size or location, it would show up as small as possible
m.setSize(400, 300);
// This is the way to set the window to go in the middle of the screen
m.setLocationRelativeTo(null);
// This sets the window as visible to the user. By default it is not visible
m.setVisible(true);
// This makes sure that the program will quit when the window is closed
m.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
});
}
/**
* This is what is called a 'constructor'. It is run every time a new
* instance of the class ({@link MainClass}) is made.
*/
public MainClass() {
// This sets the title of the window. It uses what is called a 'super' constructor, meaning
// that it is calling the constructor from the class it extends (JFrame)
super("Calculator");
// Sets the GUI layout. This isn't too important to understand.
setLayout(new GridBagLayout());
GridBagConstraints constraints = new GridBagConstraints();
// Here, we create an array of all of the number buttons. Because it is
// 2 dimensional (Rows and columns), it is a 2 dimensional array.
JButton[][] numbers = new JButton[3][4];
// All constraints.whatever going on is layout manager things on the GUI.
// This isn't important to understand, but if you wanted to look into it,
// check out http://docs.oracle.com/javase/tutorial/uiswing/layout/using.html
constraints.fill = GridBagConstraints.BOTH;
constraints.weightx = 1;
constraints.weighty = 1;
constraints.gridy = 0;
constraints.gridx = 0;
constraints.gridwidth = 3;
add(textArea, constraints);
constraints.gridwidth = 1;
// This is a for loop going through all of the number buttons (The rows)
for (int x = 0; x < numbers.length; x++) {
// This is a second for loop that runs inside of the other one that goes through
// all of the columns of the buttons
for (int y = 0; y < numbers[x].length; y++) {
// If Y is 3, that means that there are already 3 lines of numbers
// (Arrays ALWAYS start at 0. This is a rule that applies everywhere)
if (y == 3) {
// If X is 1, that means it is the spot for the zero button
if (x == 1) {
// Creates the zero button
numbers[x][y] = new JButton("0");
constraints.gridx = x;
constraints.gridy = y + 1;
add(numbers[x][y], constraints);
} else {
// Creates other buttons just to avoid debugging problems
numbers[x][y] = new JButton();
}
} // Does everything indside if there is still room for numbers (row < 3)
else {
// Creates the button with a number written within. +10 points if
// you understand why (x + 1) + (y * 3) would give you the number
// of the button. (Tip: Think about how the row relates to the number)
numbers[x][y] = new JButton((x + 1) + (y * 3) + "");
constraints.gridx = x;
constraints.gridy = y + 1;
add(numbers[x][y], constraints);
}
// This adds what is called an action listener. The method within is
// called whenever the button in question is pressed by the user.
numbers[x][y].addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// Uses a custom method to make something happen when the button is pressed
// The "Integer.parseInt(((JButton) e.getSource()).getText())" is more
// complicated than you need to understand. +15 points if you can figure out. :)
// Custom method, find lower down
pressButton(Integer.parseInt(((JButton) e.getSource()).getText()));
}
});
}
}
// Creates the decimal point button
JButton decimal = new JButton(".");
// Adds a listener to the decimal button that adds a . to the text area.
decimal.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
textArea.setText(textArea.getText() + '.');
}
});
constraints.gridx = 0;
constraints.gridy = 4;
add(decimal, constraints);
// Creates the equals button
JButton equals = new JButton("=");
// Adds a listener that uses a custom method to set the text area to display the result
equals.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// Custom method, find lower down
pressOperator('=');
}
});
constraints.gridx = 2;
constraints.gridy = 4;
add(equals, constraints);
// From here on all you need to know is that it is creating buttons and setting them do
// their actions when pressed. Scroll down to #pressButton() to learn more.
JButton clear = new JButton("CE");
clear.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
textArea.setText(null);
}
});
constraints.gridx = 3;
constraints.gridy = 0;
add(clear, constraints);
JButton add = new JButton("+");
add.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
pressOperator('+');
}
});
constraints.gridy = 1;
add(add, constraints);
JButton substract = new JButton("-");
substract.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
pressOperator('-');
}
});
constraints.gridy = 2;
add(substract, constraints);
JButton multiply = new JButton("x");
multiply.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
pressOperator('x');
}
});
constraints.gridy = 3;
add(multiply, constraints);
JButton divide = new JButton("/");
divide.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
pressOperator('/');
}
});
constraints.gridy = 4;
add(divide, constraints);
}
// This is a "Global Variable". It is usable anywhere in any methods.
// It signifies whether a new number being pressed should automatically clear
// the old result. (After a result has been found)
boolean clearable = false;
/**
* Virtually presses the button. Adds the number to the end of the text in
* the text box.
*
* @param button this parameter of the method is the number that was pressed
* (ex. 1, 3, 9, etc.)
*/
void pressButton(int button) {
if (clearable) {
textArea.setText(null);
clearable = false;
}
textArea.setText(textArea.getText() + button);
}
/**
* Virtually presses an operator. This include addition, multiplication,
* equals, etc.
*
* @param operator this parameter is the symbol of the operator, in
* Character form
*/
void pressOperator(final char operator) {
// This sets "clearable" to false because an equation is already being
// written, and should not be overriden
clearable = false;
// This is what is called a switch-case logic statement.
// it will test if the "operator" parameter matches any of the given 'cases'
switch (operator) {
// If operator is equal to '=', it will do the following things
case ('='):
try {
// Sets the text to the results of the "calculate()" method
textArea.setText(calculate() + "");
} catch (Exception ex) {
// This 'catches' an exception, meaning that if something goes wrong
// in the try {} statement, this code is run. Displays that an error occured.
textArea.setText("ERROR - " + ex.getMessage());
ex.printStackTrace(System.err);
}
// Escapes the switch-case statement. This is done so it runs faster.
break;
// Again, if the operator is equal to '+', it will do the following things.
case ('+'):
// Adds an addition sign with spaces on each side
textArea.setText(textArea.getText() + " + ");
break;
case ('-'):
// Adds a substraction sign with spaces on each side
textArea.setText(textArea.getText() + " - ");
break;
case ('x'):
// Adds a multiplication sign with spaces on each side
textArea.setText(textArea.getText() + " x ");
break;
case ('/'):
// Adds a division sign with spaces on each side
textArea.setText(textArea.getText() + " / ");
break;
}
}
/**
* This method is the heart of the calculator. It calculates the answer to
* the question asked in the text box.
*
* @return answer to the question
* @throws NumberFormatException this exception is thrown when an error
* occurs while calculating. This usually happens when things like two
* operator signs are put beside each other.
*/
double calculate() throws NumberFormatException {
// Sets clearable to be true, since the answer has already been calculated
clearable = true;
// Creates the variable 'text' based on the text area.
String text = textArea.getText();
// Splits the text into a bunch of different parts seperated by spaces.
String[] texts = text.split(" ");
// This goes through all of the parts, and removes spaces (to prevent errors)
for (int x = 0; x < texts.length; x++) {
texts[x] = texts[x].replace(" ", "");
}
// This variable is used to store the current value of the equation
double currentValue = Double.MAX_VALUE;
// This variable is used to store the previously used operation
String prevOperation = null;
// This variable is used to tell if there was an operation sign before the current number
boolean operation = false;
// This for loop goes through every part of the equation seperately
for (int x = 0; x < texts.length; x++) {
// Tests to see if the current text is an operation
if (texts[x].equals("+") || texts[x].equals("-") || texts[x].equals("x") || texts[x].equals("/")) {
// Makes sure that the current value has been inputed (The first number in the equation)
if (currentValue != Double.MAX_VALUE) {
// Sets the operation variable to be true because there was an operator in the previous position
operation = true;
// Sets the previous operation as well
prevOperation = texts[x];
}
}
// Does this if it is not an operator, and the previous part was an operator
else if (operation) {
// Uses a switch statement on the previous operation
switch (prevOperation) {
// Does the appropriate equation depending on operation
case ("+"):
currentValue += Double.parseDouble(texts[x]);
break;
case ("-"):
currentValue -= Double.parseDouble(texts[x]);
break;
case ("x"):
currentValue *= Double.parseDouble(texts[x]);
break;
case ("/"):
currentValue /= Double.parseDouble(texts[x]);
break;
}
// Sets operation to false, because now the previous part was a number
operation = false;
}
// Does this if there was no operation beforehand, and the part is a number
// This should only happen on the first number in the equation
else {
// Sets the current value to the first part
currentValue = Double.parseDouble(texts[x]);
}
}
// "Returns" the value of the equation to the method. This is used to be
// put on the text area, rather than just outputing to the text area here.
return currentValue;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment