0

I am trying to practice my OOP skills along with Java Swing but I am currently stuck. I am trying to make a calculator gui kind of like the one you'd see on a phone. I don't know how I should be implementing the functions of each button press. For now I am just trying to display the number on the screen (JLabel object) when I press a button. I have also attached a picture of the GUI that I have so far.

Should I be implementing the functions in a separate .java file? Or should they be implemented in the Calculator.java or Keyboard.java file?

Also how are they implemented because I don't know how to display on the JLabel object in the Calculator.java file if my button objects are in the Keyboard.java file.

Calculator.java

package calculator;

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

public class Calculator extends JFrame
{
    public static void main(String[] args)
    {
        new Calculator();
    }

    public Calculator() //Calculator constructor??
    {
        setLayout(new GridLayout(2,1));
        this.setSize(400,600);
        this.setLocationRelativeTo(null); //center the window
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JLabel display = new JLabel();
        this.add(display);

        Keyboard kb = new Keyboard();
        this.add(kb);

        this.setVisible(true);
    }

}

Keyboard.java

package calculator;
import javax.swing.JPanel;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;

public class Keyboard extends JPanel implements ActionListener
{
    public Keyboard()
    {
        setLayout(new GridLayout(4,4));

        JButton one = new JButton("1");
        this.add(one);
        JButton two = new JButton("2");
        this.add(two);
        JButton three = new JButton("3");
        this.add(three);
        JButton plus = new JButton("+");
        this.add(plus);
        JButton four = new JButton("4");
        this.add(four);
        JButton five = new JButton("5");
        this.add(five);
        JButton six = new JButton("6");
        this.add(six);
        JButton minus = new JButton("-");
        this.add(minus);
        JButton seven = new JButton("7");
        this.add(seven);
        JButton eight = new JButton("8");
        this.add(eight);
        JButton nine = new JButton("9");
        this.add(nine);
        JButton times = new JButton("x");
        this.add(times);
        JButton zero = new JButton("0");
        this.add(zero);
        JButton clear = new JButton("clear");
        this.add(clear);
        JButton equals = new JButton("=");
        this.add(equals);
        JButton divide = new JButton("/");
        this.add(divide);
    }

    public void actionPerformed(ActionEvent e) {

    }
}

enter image description here

  • What does pressing the buttons do? If you're just constructing an expression to be evaluated later and displaying it to the user, then handling the `[0-9x/-+]` buttons will be the same, append the button's symbol to the expression and update the string displayed. The rest of the buttons obviously serve a different purpose and need custom action listeners. – dramzy Dec 28 '16 at 01:40
  • See also this [calculator example](http://stackoverflow.com/a/7441804/418556). It uses `ScriptEngine` to evaluate the expression in the text field. – Andrew Thompson Dec 28 '16 at 15:06

2 Answers2

1

You should write actionPerformed() methods in the 'Keyboard.java' file itself

Keyboard.java

one.addActionListener(new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            jButton1ActionPerformed(evt);
        }
    });
    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
    {
        displaystring = displaystring + "1";
        display.setText (displaystring);`
    }

You have to pass display's reference through the constructor of Keyboard class and assign it to some instance variable of that class so that you can update the display Label in Keyboard class too!!

1

Use the MVC pattern and put the logic code that would go into the actionPerformed(...) method (Or any logic code for that matter) into a corresponding method in the controller class.


The MVC pattern consists of three classes, the Model, View, and Control, that work together to make a GUI.

A brief summary of the MVC pattern, taken originally from this answer, but slightly modified:

  1. You’re the user — you interact with the view. The controller takes your actions and interprets them. If you click on a button, it’s the controller’s job to figure out what that means and how the model should be manipulated based on that action.
  2. The controller asks the model to change its state. When the controller receives an action from the view, it may need to tell the view to change as a result. For example, the controller could enable or disable certain buttons or menu items in the interface.
  3. The model notifies the view when its state has changed. When something changes in the model, based either on some action you took (like clicking a button) or some other internal change (like the next song in the playlist has started), the model notifies the view that its state has changed.
  4. The controller may also ask the view to change.
  5. The view asks the model for its state. The view gets the state it displays directly from the model. For instance, when the model notifies the view that a new song has started playing, the view requests the song name from the model and displays it. The view might also ask the model for state as the result of the controller requesting some change in the view.

A more detailed and in-depth explanation of the MVC pattern can be found in the link above, on Oracle's website, and with a simple Google search.


I choose to use the observer pattern for my model-view interaction.

A example of a program using the MVC structure:

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Observable;
import java.util.Observer;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.WindowConstants;

class Test {

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                final Model model = new Model();
                final Control control = new Control(model);
                final View view = new View(model, control);

                final JFrame frame = new JFrame("MVC Example");
                frame.getContentPane().add(view);
                frame.pack();
                frame.setLocationByPlatform(true);
                frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
                frame.setVisible(true);
            }

        });
    }

    static class Model extends Observable {

        private int number;

        void setNumber(int newValue) {
            number = newValue;
            setChanged();
            notifyObservers(number);
        }

        int getNumber() {
            return number;
        }

    }

    static class View extends JPanel {

        View(Model model, Control control) {
            final JLabel label = new JLabel(Integer.toString(model.getNumber()));
            final JButton button = new JButton("Click me!");
            button.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    control.buttonPressed();
                }

            });

            setLayout(new BorderLayout());
            add(label);
            add(button, BorderLayout.SOUTH);

            model.addObserver(new Observer() {

                @Override
                public void update(Observable o, Object arg) {
                    label.setText(Integer.toString((int) arg));
                }

            });
        }

    }

    static class Control {

        private Model model;

        Control(Model model) {
            this.model = model;
        }

        void buttonPressed() {
            model.setNumber(model.getNumber() + 1);
        }

    }

}

Notes on your code:

  • Take a look at arrays and the for loop to help you to simplify the declaration of your buttons.
  • Instead of setting your JFrames size, call pack() on your JFrame after you have added all your components to fit your JFrame to its children's size.
  • Don't extend JFrame, instead create an instance of one and make the necessary modifications.
  • Run your code on the EDT (Event Dispatch Thread) to avoid "freezing" in your GUI. For more information take a look at The Java™ Tutorials - Concurrency in Swing
  • Next time you post consider posting, for better help sooner, post a MCVE.
Community
  • 1
  • 1
MasterBlaster
  • 948
  • 2
  • 12
  • 26