Per John
Per John

Reputation: 63

How to break this program into several classes

I have found this implementation of a simple calculator in Java, using the Java Swing framework.

The source code is here:

//Imports are listed in full to show what's being used
//could just import javax.swing.* and java.awt.* etc..
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.BorderLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.JButton;
import java.awt.Container;

public class SimpleCalc implements ActionListener{

    JFrame guiFrame;
    JPanel buttonPanel;
    JTextField numberCalc;
    int calcOperation = 0;
    int currentCalc;

    //Note: Typically the main method will be in a
    //separate class. As this is a simple one class
    //example it's all in the one class.
    public static void main(String[] args) {

         //Use the event dispatch thread for Swing components
         EventQueue.invokeLater(new Runnable()
         {

            @Override
             public void run()
             {

                 new SimpleCalc();         
             }
         });

    }

    public SimpleCalc()
    {
        guiFrame = new JFrame();

        //make sure the program exits when the frame closes
        guiFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        guiFrame.setTitle("Simple Calculator");
        guiFrame.setSize(300,300);

        //This will center the JFrame in the middle of the screen
        guiFrame.setLocationRelativeTo(null);

        numberCalc = new JTextField();
        numberCalc.setHorizontalAlignment(JTextField.RIGHT);
        numberCalc.setEditable(false);

        guiFrame.add(numberCalc, BorderLayout.NORTH);

        buttonPanel = new JPanel();

        //Make a Grid that has three rows and four columns
        buttonPanel.setLayout(new GridLayout(4,3));   
        guiFrame.add(buttonPanel, BorderLayout.CENTER);

        //Add the number buttons
        for (int i=1;i<10;i++)
        {
            addButton(buttonPanel, String.valueOf(i));
        }

        JButton addButton = new JButton("+");
        addButton.setActionCommand("+");

        OperatorAction subAction = new OperatorAction(1);
        addButton.addActionListener(subAction);

        JButton subButton = new JButton("-");
        subButton.setActionCommand("-");

        OperatorAction addAction = new OperatorAction(2);
        subButton.addActionListener(addAction);

        JButton equalsButton = new JButton("=");
        equalsButton.setActionCommand("=");
        equalsButton.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent event)
            {
                if (!numberCalc.getText().isEmpty())
                {
                    int number = Integer.parseInt(numberCalc.getText()); 
                    if (calcOperation == 1)
                    {
                        int calculate = currentCalc  + number;
                        numberCalc.setText(Integer.toString(calculate));
                    }
                    else if (calcOperation == 2)
                    {
                        int calculate = currentCalc  - number;
                        numberCalc.setText(Integer.toString(calculate));
                    }
                }
            }
        });

        buttonPanel.add(addButton);
        buttonPanel.add(subButton);
        buttonPanel.add(equalsButton);
        guiFrame.setVisible(true);  
    }

    //All the buttons are following the same pattern
    //so create them all in one place.
    private void addButton(Container parent, String name)
    {
        JButton but = new JButton(name);
        but.setActionCommand(name);
        but.addActionListener(this);
        parent.add(but);
    }

    //As all the buttons are doing the same thing it's
    //easier to make the class implement the ActionListener
    //interface and control the button clicks from one place
    @Override
    public void actionPerformed(ActionEvent event)
    {
        //get the Action Command text from the button
        String action = event.getActionCommand();

        //set the text using the Action Command text
        numberCalc.setText(action);       
    }

    private class OperatorAction implements ActionListener
    {
        private int operator;

        public OperatorAction(int operation)
        {
            operator = operation;
        }

        public void actionPerformed(ActionEvent event)
        {
            currentCalc = Integer.parseInt(numberCalc.getText()); 
            calcOperation = operator;
        }
    }
}

I would like to put the OperatorAction class into to a separate class, which I have tried, but then there is a problem getting text from the JTextField, as that is not available in that new class. So how would one do that?

Upvotes: 0

Views: 232

Answers (2)

Marko Topolnik
Marko Topolnik

Reputation: 200168

All you need is another constructor argument (and a matching instance field):

class OperatorAction implements ActionListener
{
    private int operator;
    private SimpleCalc calc;

    public OperatorAction(SimpleCalc c, int operation)
    {
        calc = c;
        operator = operation;
    }

    public void actionPerformed(ActionEvent event) {
      calc.setCurrentCalc(Integer.parseInt( 
          ((JTextField)event.getSource()).getText()));
      calcOperation = operator;
    }
}

And expose the SimpleCalc#currentCalc property through a setter.

This is not very clean design, though, because you still have tight coupling between OperatorAction and SimpleCalc, but it could be a start for you.

Upvotes: 2

Rembrandt Q. Einstein
Rembrandt Q. Einstein

Reputation: 1121

Looks like you need to be using the Model View Controller (MVC) pattern! MVC is integral to many languages and systems, so it's very important to learn! What you'll want to do is break the program into 3 layers of classes, *M*odels, *V*iews, and *C*ontrollers (in this case, the project is likely simple enough to use just one of each.)

Models are going to store your data, these can be a few classes, or a whole database depending on the size of your project.

Views are going to display your data.

Controllers are going to manage the rest.

So what you'd do here is have a Model that merely stores the input to the calculator, a Controller that takes the input, does the actual math, and pushes the output to the View.

Upvotes: -1

Related Questions