6
\$\begingroup\$

I am new to Java Swing and have decided to create a calculator to learn some of the basic. I would like someone to look over my code to see if they can give me any improvements.

I have 6 classes and 2 interfaces. I have chosen to split the communication of both operators and digits. The mainframe is the controller and actually creates the objects. The other classes are the different components.

MainFrame (creates all objects):

package calculator;
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.ScriptEngine;
public class MainFrame extends JFrame {
 private FormArea formpanel;
 private OutputArea outputText;
 private WorkoutExpression workingOutMathExpression;
 private static String mathmaticalExpression = "";
 public MainFrame() {
 super("Calculator");
 setVisible(true);
 setSize(800, 600);
 setDefaultCloseOperation(EXIT_ON_CLOSE);
 formpanel = new FormArea();
 outputText = new OutputArea();
 workingOutMathExpression = new WorkoutExpression();
 setLayout(new BorderLayout());
 formpanel.setStringListener(new DigitListener() {
 public void StringEmmiter(String text) {
 outputText.addText(text);
 mathmaticalExpression = mathmaticalExpression + text;
 //System.out.println(mathmaticalExpression);
 WorkoutExpression.setMathExpression(mathmaticalExpression);
 }
 });
 formpanel.setOperatorListener(new MathOperatorListener() {
 public void OperatorEmitter(String text2a) {
 if (text2a.equals("CLEAR")) {
 outputText.refreshTextArea();
 mathmaticalExpression = "";
 workingOutMathExpression.resetMathExpression();
 } else if (text2a.equals("CLEAR") == false) {
 outputText.addText(text2a);
 if (text2a.equals("=")) {
 try {
 outputText.addText(workingOutMathExpression.getCalculationOfExpression());
 } catch (ScriptException e) {
 e.printStackTrace();
 }
 } else {
 mathmaticalExpression = mathmaticalExpression + text2a;
 //System.out.println(mathmaticalExpression);
 WorkoutExpression.setMathExpression(mathmaticalExpression);
 }
 }
 }
 });
 add(formpanel, BorderLayout.WEST);
 add(outputText, BorderLayout.CENTER);
 }
}

Formpanel is the panel which contains all the buttons:

package calculator;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Arrays;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class FormArea extends JPanel implements ActionListener {
 private ButtonTemplate No1;
 private ButtonTemplate No2;
 private ButtonTemplate No3;
 private ButtonTemplate No4;
 private ButtonTemplate No5;
 private ButtonTemplate No6;
 private ButtonTemplate No7;
 private ButtonTemplate No8;
 private ButtonTemplate No9;
 private ButtonTemplate No0;
 private ButtonTemplate addition;
 private ButtonTemplate substraction;
 private ButtonTemplate division;
 private ButtonTemplate total;
 private ButtonTemplate multiplication;
 private JButton clearButton;
 private ButtonTemplate decimalPoint;
 private DigitListener digitListener;
 private MathOperatorListener operatorListener;
 public FormArea() {
 // SetSize
 setPreferredSize(new Dimension(300, 500));
 // Create all Objects
 No1 = new ButtonTemplate("1");
 No2 = new ButtonTemplate("2");
 No3 = new ButtonTemplate("3");
 No4 = new ButtonTemplate("4");
 No5 = new ButtonTemplate("5");
 No6 = new ButtonTemplate("6");
 No7 = new ButtonTemplate("7");
 No8 = new ButtonTemplate("8");
 No9 = new ButtonTemplate("9");
 No0 = new ButtonTemplate("0");
 addition = new ButtonTemplate("+");
 substraction = new ButtonTemplate("-");
 division = new ButtonTemplate("/");
 total = new ButtonTemplate("=");
 multiplication = new ButtonTemplate("*");
 clearButton = new JButton("CLEAR");
 decimalPoint = new ButtonTemplate(".");
 clearButton.setPreferredSize(new Dimension(100, 60));
 setLayout(new GridBagLayout());
 GridBagConstraints gc = new GridBagConstraints();
 // Layout
 // Column 1
 gc.gridx = 0;
 gc.gridy = 0;
 gc.weightx = 0.1;
 gc.weighty = 0.1;
 add(No1, gc);
 gc.gridx = 0;
 gc.gridy = 1;
 gc.weightx = 0.1;
 gc.weighty = 0.1;
 add(No4, gc);
 gc.gridx = 0;
 gc.gridy = 2;
 gc.weightx = 0.1;
 gc.weighty = 0.1;
 add(No7, gc);
 // Column 2
 gc.gridx = 1;
 gc.gridy = 0;
 gc.weightx = 0.1;
 gc.weighty = 0.1;
 add(No2, gc);
 gc.gridx = 1;
 gc.gridy = 1;
 gc.weightx = 0.1;
 gc.weighty = 0.1;
 add(No5, gc);
 gc.gridx = 1;
 gc.gridy = 2;
 gc.weightx = 0.1;
 gc.weighty = 0.1;
 add(No8, gc);
 // Column3
 gc.gridx = 2;
 gc.gridy = 0;
 gc.weightx = 0.1;
 gc.weighty = 0.1;
 add(No3, gc);
 gc.gridx = 2;
 gc.gridy = 1;
 gc.weightx = 0.1;
 gc.weighty = 0.1;
 add(No6, gc);
 gc.gridx = 2;
 gc.gridy = 2;
 gc.weightx = 0.1;
 gc.weighty = 0.1;
 add(No9, gc);
 // Operators
 gc.gridx = 0;
 gc.gridy = 3;
 gc.weightx = 0.1;
 gc.weighty = 0.1;
 add(addition, gc);
 gc.gridx = 1;
 gc.gridy = 3;
 gc.weightx = 0.1;
 gc.weighty = 0.1;
 add(No0, gc);
 gc.gridx = 2;
 gc.gridy = 3;
 gc.weightx = 0.1;
 gc.weighty = 0.1;
 add(substraction, gc);
 // Operator 2
 gc.gridx = 0;
 gc.gridy = 4;
 gc.weightx = 0.1;
 gc.weighty = 0.1;
 add(division, gc);
 gc.gridx = 1;
 gc.gridy = 4;
 gc.weightx = 0.1;
 gc.weighty = 0.1;
 add(multiplication, gc);
 gc.gridx = 2;
 gc.gridy = 4;
 gc.weightx = 0.1;
 gc.weighty = 0.1;
 add(total, gc);
 gc.gridx = 1;
 gc.gridy = 5;
 gc.weightx = 0.1;
 gc.weighty = 5;
 add(clearButton, gc);
 gc.gridx = 0;
 gc.gridy = 5;
 gc.weightx = 0.1;
 gc.weighty = 0.1;
 add(decimalPoint, gc);
 // ActionButton
 No1.addActionListener(this);
 No2.addActionListener(this);
 No3.addActionListener(this);
 No4.addActionListener(this);
 No5.addActionListener(this);
 No6.addActionListener(this);
 No7.addActionListener(this);
 No8.addActionListener(this);
 No9.addActionListener(this);
 No0.addActionListener(this);
 ArrayList<ButtonTemplate> operatorsArrayList = 
 new ArrayList<ButtonTemplate>(Arrays.asList(iterateThroughOperators()));
 for (ButtonTemplate btn : operatorsArrayList) {
 btn.addActionListener(new ActionListener() {
 @Override
 public void actionPerformed(ActionEvent e) {
 ButtonTemplate source1 = (ButtonTemplate) e.getSource();
 if (source1 == btn) {
 operatorListener.OperatorEmitter(btn.getText());
 }
 }
 });
 }
 clearButton.addActionListener(new ActionListener() {
 public void actionPerformed(ActionEvent e) {
 JButton s1 = (JButton) e.getSource();
 operatorListener.OperatorEmitter(s1.getText());
 }
 });
 }
 public void setStringListener(DigitListener digitlistener) {
 this.digitListener = digitlistener;
 }
 public void setOperatorListener(MathOperatorListener operatorListener) {
 this.operatorListener = operatorListener;
 }
 public ButtonTemplate[] iterateThroughButton() {
 ButtonTemplate btn[] = { No1, No2, No3, No4, No5, No6, No7, No8, No9, No0 };
 return btn;
 }
 public ButtonTemplate[] iterateThroughOperators() {
 ButtonTemplate operatorBtn[] = { addition, substraction, division, total, multiplication,decimalPoint
 };
 return operatorBtn;
 }
 public void actionPerformed(ActionEvent e) {
 JButton source = (JButton) e.getSource();
 for (ButtonTemplate SingleButton : iterateThroughButton()) {
 if (source == SingleButton) {
 digitListener.StringEmmiter(SingleButton.getText());
 }
 }
 }
}

Button Template is just a standard button with a specified size:

package calculator;
import java.awt.Dimension;
import javax.swing.JButton;
public class ButtonTemplate extends JButton{
 private String nameOfTheButton;
 public ButtonTemplate(String nameOfButton){
 this.nameOfTheButton = nameOfButton;
 this.setText(nameOfTheButton);
 this.setPreferredSize(new Dimension(70,50));
 }
}

DigitListener listens for the digits and sends them to the mainframe:

package calculator;
public interface DigitListener {
 public void StringEmmiter(String text1);
}

Operator listener listens to the operators and sends them to the mainframe:

package calculator;
public interface MathOperatorListener {
 public void OperatorEmitter(String text2);
}

MathExpression works out the mathematical expression using scriptengine:

package calculator;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.ScriptEngine;
public class WorkoutExpression {
 private static String mathExpression;
 public static void setMathExpression(String mathExpression) {
 WorkoutExpression.mathExpression = mathExpression;
 }
 public String getCalculationOfExpression() throws ScriptException{
 ScriptEngineManager mgr = new ScriptEngineManager();
 ScriptEngine engine = mgr.getEngineByName("JavaScript");
 return engine.eval(mathExpression).toString();
 }
 public void resetMathExpression(){
 mathExpression = "0";
 }
}

Output area is whether the calculation is displayed:

package calculator;
import java.awt.BorderLayout;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class OutputArea extends JPanel {
 private JTextArea textarea;
 public OutputArea() {
 textarea = new JTextArea();
 setLayout(new BorderLayout());
 add(new JScrollPane(textarea));
 }
 public void addText(String text){
 textarea.append(text);
 }
 public void refreshTextArea(){
 textarea.setText(null);
 }
}
Legato
9,9294 gold badges50 silver badges118 bronze badges
asked Aug 27, 2015 at 11:12
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Welcome to CodeReview! A Github link to your project, while not needed, would make testing easier for the reviewers allowing better quality reviews. \$\endgroup\$ Commented Aug 27, 2015 at 12:39

1 Answer 1

3
\$\begingroup\$

Use Arrays

At a glance, your creating and instantiating the ButtonTemplate objects could be done as an array.

e.g.

private ButtonTemplate[] buttons = new ButtonTemplate[10];

It would allow you to use a simple loop to instantiate, and add the ActionListener, e.g.

for (int i = 0; i < buttons.length; i++) {
 buttons[i] = new ButtonTemplate(Integer.toString(i));
 buttons[i].addActionListener(this);
}

Employ Lambda Expressions

If you have access to Java 8, You can use lambda expressions to simply the code where you use Functional Interfaces, e.g.

instead of:

btn.addActionListener(new ActionListener() {
 @Override
 public void actionPerformed(ActionEvent e) {
 ButtonTemplate source1 = (ButtonTemplate) e.getSource();
 if (source1 == btn) {
 operatorListener.OperatorEmitter(btn.getText());
 }
 }
 });

You can simply write:

btn.addActionListener(e -> {
 if ((ButtonTemplate)e.getSource() == btn) {
 operatorListener.OperatorEmitter(btn.getText());
 }
});

I also use e.getSource() directly here rather than storing it as a variable since we're only doing one thing with it anyway, but feel free to use it your way if you find it makes it more understandable/readable.

Read up on what I linked, but just as an additional example, your MathOperatorListener is a functional interface. So this section where you call setOperatorListener

formpanel.setOperatorListener(new MathOperatorListener() {
 public void OperatorEmitter(String text2a) {

Can be replaced with:

formpanel.setOperatorListener(e -> {
 // content
});

The e is just a variable used to refer to the text2a that is passed. You can name it anything. Same deal of course for your DigitListener interface. You may start using the @FunctionalInterface annotation so the compiler would check and confirm for you, albeit Functional Interfaces are easily identifiable since they only have a single method).

answered Aug 27, 2015 at 21:43
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.