2

This code for a basic calculator
I have 2 problems:

  1. How to get correct result for percentage calculation?
  2. And set limit for text field?

I need text field to only read 16 digits maximum.

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Font;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;

    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JTextField;
    import javax.swing.UIManager;
    import javax.swing.event.CaretEvent;
    import javax.swing.event.CaretListener;

    public class Calculator extends JFrame implements ActionListener {

    private static final long serialVersionUID = 4055065492318058414L;

    private JPanel northPanel;
    private JPanel centerPanel;

    private JTextField field;

    private JButton b1;
    private JButton b2;
    private JButton b3;
    private JButton b4;
    private JButton b5;
    private JButton b6;
    private JButton b7;
    private JButton b8;
    private JButton b9;
    private JButton b0;

    private JButton bPlus;
    private JButton bMine;
    private JButton bMultiple;
    private JButton bDivision;
    private JButton bEqual;
    private JButton bClear;
    private JButton bErase;
    private JButton bPercent;
    private JButton bPlusMine;
    private JButton bDot;

    private double fNum;
    private double sNum;
    private double result;
    private String operation;

    private static final Font fontButton = new Font("Consolas", Font.BOLD, 20);

    public static void main(String[] args) {

        new Calculator().setVisible(true);

    }

    public Calculator() {

        super("Calculator");

        try {

            UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");

            setSize(225, 300);
            setLocationRelativeTo(null);
            setResizable(false);
            setDefaultCloseOperation(EXIT_ON_CLOSE);

            setGUI();

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private void setGUI() {

        northPanel = new JPanel();
        add(northPanel, BorderLayout.NORTH);

        centerPanel = new JPanel();
        add(centerPanel, BorderLayout.CENTER);

        field = new JTextField(10);
        field.setEnabled(false);
        field.setHorizontalAlignment(JTextField.RIGHT);
        field.setDisabledTextColor(Color.BLACK);
        field.setBackground(Color.WHITE);
        field.setFont(new Font("Consolas", Font.BOLD, 32));

        northPanel.add(field);

        bErase = new JButton("<");
        bErase.setFont(fontButton);

        bPlus = new JButton("+");
        bPlus.setFont(fontButton);

        bPercent = new JButton("%");
        bPercent.setFont(fontButton);

        bMine = new JButton("-");
        bMine.setFont(fontButton);

        bMultiple = new JButton("\u00D7");
        bMultiple.setFont(fontButton);

        bDivision = new JButton("\u00F7");
        bDivision.setFont(fontButton);

        bEqual = new JButton("=");
        bEqual.setFont(fontButton);

        bClear = new JButton("c");
        bClear.setFont(fontButton);

        bPlusMine = new JButton("±");
        bPlusMine.setFont(fontButton);

        bDot = new JButton(".");
        bDot.setFont(fontButton);

        b1 = new JButton("1");
        b1.setFont(fontButton);

        b2 = new JButton("2");
        b2.setFont(fontButton);

        b3 = new JButton("3");
        b3.setFont(fontButton);

        b4 = new JButton("4");
        b4.setFont(fontButton);

        b5 = new JButton("5");
        b5.setFont(fontButton);

        b6 = new JButton("6");
        b6.setFont(fontButton);

        b7 = new JButton("7");
        b7.setFont(fontButton);

        b8 = new JButton("8");
        b8.setFont(fontButton);

        b9 = new JButton("9");
        b9.setFont(fontButton);

        bDot = new JButton(".");
        bDot.setFont(fontButton);

        b0 = new JButton("0");
        b0.setFont(fontButton);

        centerPanel.add(bErase);
        centerPanel.add(bClear);
        centerPanel.add(bPercent);
        centerPanel.add(bDivision);

        centerPanel.add(b1);
        centerPanel.add(b2);
        centerPanel.add(b3);
        centerPanel.add(bMultiple);

        centerPanel.add(b4);
        centerPanel.add(b5);
        centerPanel.add(b6);
        centerPanel.add(bMine);

        centerPanel.add(b7);
        centerPanel.add(b8);
        centerPanel.add(b9);
        centerPanel.add(bPlus);

        centerPanel.add(bPlusMine);
        centerPanel.add(b0);
        centerPanel.add(bDot);
        centerPanel.add(bEqual);

        b1.addActionListener(this);
        b2.addActionListener(this);
        b3.addActionListener(this);
        b4.addActionListener(this);
        b5.addActionListener(this);
        b6.addActionListener(this);
        b7.addActionListener(this);
        b8.addActionListener(this);
        b9.addActionListener(this);
        b0.addActionListener(this);
        bDot.addActionListener(this);

        bClear.addActionListener(this);
        bErase.addActionListener(this);

        bPlus.addActionListener(this);
        bMine.addActionListener(this);
        bMultiple.addActionListener(this);
        bDivision.addActionListener(this);

        bPlusMine.addActionListener(this);
        bPercent.addActionListener(this);
        bEqual.addActionListener(this);

        field.addCaretListener(new CaretListener() {

            public void caretUpdate(CaretEvent event) {

                if (field.getText().length() >= 10)
                    field.setFont(new Font("Consolas", Font.BOLD, 25));

                if (field.getText().length() >= 13)
                    field.setFont(new Font("Consolas", Font.BOLD, 20));

                if (field.getText().length() >= 15)
                    field.setFont(new Font("Consolas", Font.BOLD, 19));

            }
        });


    }



    public void actionPerformed(ActionEvent event) {

        if (event.getSource().equals(b1))
            field.setText(field.getText() + "1");

        if (event.getSource().equals(b2))
            field.setText(field.getText() + "2");

        if (event.getSource().equals(b3))
            field.setText(field.getText() + "3");

        if (event.getSource().equals(b4))
            field.setText(field.getText() + "4");

        if (event.getSource().equals(b5))
            field.setText(field.getText() + "5");

        if (event.getSource().equals(b6))
            field.setText(field.getText() + "6");

        if (event.getSource().equals(b7))
            field.setText(field.getText() + "7");

        if (event.getSource().equals(b8))
            field.setText(field.getText() + "8");

        if (event.getSource().equals(b9))
            field.setText(field.getText() + "9");

        if (event.getSource().equals(bDot)) {

            if (field.getText().indexOf(".") == -1 && !field.getText().isEmpty())
                field.setText(field.getText() + ".");

        }

        if (event.getSource().equals(b0)) {

            /*
             * if (field.getText().isEmpty()) field.setText("");
             * 
             * else
             */
            field.setText(field.getText() + "0");

        }

        if (event.getSource().equals(bClear)) {

            if (!field.getText().isEmpty()) {

                fNum = 0;
                sNum = 0;
                operation = null;
                field.setText(null);

            }

        }

        if (event.getSource().equals(bErase)) {

            if (!field.getText().isEmpty())
                field.setText(field.getText().substring(0, field.getText().length() - 1));

        }

        if (event.getSource().equals(bPlus)) {

            if (!field.getText().isEmpty()) {

                fNum = Double.valueOf(field.getText());
                field.setText(null);
                operation = "+";

            }

        }

        if (event.getSource().equals(bMine)) {

            if (!field.getText().isEmpty()) {

                fNum = Double.valueOf(field.getText());
                field.setText(null);
                operation = "-";
            }
        }

        if (event.getSource().equals(bMultiple)) {

            if (!field.getText().isEmpty()) {

                fNum = Double.valueOf(field.getText());
                field.setText(null);
                operation = "\u00D7";
            }
        }

        if (event.getSource().equals(bDivision)) {

            if (!field.getText().isEmpty()) {

                fNum = Double.valueOf(field.getText());
                field.setText(null);
                operation = "\u00F7";

            }

        }

        if (event.getSource().equals(bEqual)) {

            if (!field.getText().isEmpty() && operation != null) {

                sNum = Double.valueOf(field.getText());

                if (operation.equals("+"))
                    result = fNum + sNum;

                else if (operation.equals("-"))
                    result = fNum - sNum;

                else if (operation.equals("x"))
                    result = fNum * sNum;

                else if (operation.equals("\u00F7"))
                    result = fNum / sNum;

                else if (operation.equals("\u00D7"))
                    result = fNum * sNum;



                field.setText(String.valueOf(result));

            }

        }

        if (event.getSource().equals(bPlusMine)) {

            if (!field.getText().isEmpty()) {

                double num = Double.valueOf(field.getText());

                if (num > 0)
                    field.setText(String.valueOf(num - (num * 2)));

                else
                    field.setText(String.valueOf(Math.abs(num)));

            }

        }

    }

    }

For text field limit, I wrote this code in actionPerformed method

if (event.getSource().equals(bPlusMine)) {

    if (field.getText().length() > 16)
        field.setText(field.getText().substring(0, 16));
}

But the above code does not work and I can't use keyListener because textfield is disabled and can only get value from buttons

kiner_shah
  • 3,939
  • 7
  • 23
  • 37
  • 2
    to set a limit of 16 characters: `field.setDocument(new JTextFieldLimit(16));` – c0der Jul 28 '18 at 12:07
  • 1
    *"I have 2 problems:"* This is a Q&A site, not a help desk. Which is your one question for this thread? Given @c0der has already given an answer (albeit as a comment) to one, I suggest you focus on that one here, and break the other off into another question thread. – Andrew Thompson Jul 28 '18 at 12:23
  • main problem is percentage result – Pouria Mohseni Jul 28 '18 at 14:14
  • 1) *"main problem is percentage result"* [Edit] the question to reflect that! 2) Tip: Add @c0der (or whoever, the `@` is important) to *notify* the person of a new comment. – Andrew Thompson Jul 29 '18 at 03:03

1 Answers1

1

See the following code for a simple solution for calculating percent. It is meant for the output a result for the following sequence :
Enter a number followed by division operation
Enter a second number followed by percentage operation
If that is not the flow you have in mind (it was not explained in the post), you'll need to change the code.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.NumberFormat;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;

public class Calculator extends JFrame implements ActionListener {

    private JPanel northPanel, centerPanel;

    private JTextField field;

    private JButton b1, b2, b3, b4, b5, b6, b7, b8, b9, b0;

    private JButton bPlus,  bMine, bMultiple, bDivision, bEqual;
    private JButton bClear, bErase, bPercent, bPlusMine, bDot;

    private double fNum, sNum, result;
    private String operation;

    private static final Font fontButton = new Font("Consolas", Font.BOLD, 20);
    private static final NumberFormat percentageFormat = NumberFormat.getPercentInstance();

    public static void main(String[] args) {

        new Calculator().setVisible(true);
    }

    public Calculator() {

        super("Calculator");

        try {
            UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
            percentageFormat.setMinimumFractionDigits(2);
            setSize(225, 300);
            setLocationRelativeTo(null);
            setResizable(false);
            setDefaultCloseOperation(EXIT_ON_CLOSE);

            setGUI();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void setGUI() {

        northPanel = new JPanel();
        add(northPanel, BorderLayout.NORTH);

        centerPanel = new JPanel();
        add(centerPanel, BorderLayout.CENTER);

        field = new JTextField(10);
        //limit text field to 16 characters
        field.setDocument(new JTextFieldLimit(16));
        field.setEnabled(false);
        field.setHorizontalAlignment(JTextField.RIGHT);
        field.setDisabledTextColor(Color.BLACK);
        field.setBackground(Color.WHITE);
        field.setFont(new Font("Consolas", Font.BOLD, 32));

        northPanel.add(field);

        //a repeated code is an opportunity for a method
        //the method also adds buttons to JPanel
        bErase = makeButton("<");
        bClear = makeButton("c");
        bPercent = makeButton("%");
        bDivision = makeButton("\u00F7");

        b1 = makeButton("1");
        b2 = makeButton("2");
        b3 = makeButton("3");
        bMultiple = makeButton("\u00D7");

        b4 = makeButton("4");
        b5 = makeButton("5");
        b6 = makeButton("6");
        bMine = makeButton("-");

        b7 = makeButton("7");
        b8 = makeButton("8");
        b9 = makeButton("9");
        bPlus = makeButton("+");

        bPlusMine = makeButton("±");
        b0 = makeButton("0");
        bDot = makeButton(".");
        bEqual = makeButton("=");

        field.addCaretListener(new CaretListener() {

            @Override
            public void caretUpdate(CaretEvent event) {

                //use if - else for more efficient code

                if (field.getText().length() >= 15) {
                    field.setFont(new Font("Consolas", Font.BOLD, 19));
                }
                else if (field.getText().length() >= 13) {
                    field.setFont(new Font("Consolas", Font.BOLD, 20));
                }

                else if (field.getText().length() >= 10) {
                    field.setFont(new Font("Consolas", Font.BOLD, 25));
                }
            }
        });
    }

    @Override
    public void actionPerformed(ActionEvent event) {

        //only one if is executed each time, so use if - else
        //or switch

        //get the text from clicked button
        String text = ((JButton)event.getSource()).getText();
        if(isInteger(text)) {
            field.setText(field.getText() + Integer.parseInt(text));
        }

        else if (text.equals(".")) {

            if ((field.getText().indexOf(".") == -1) && !field.getText().isEmpty()) {
                field.setText(field.getText() + ".");
            }
        }

        else if (text.equals("c")) {

            if (!field.getText().isEmpty()) {

                fNum = 0;
                sNum = 0;
                operation = null;
                field.setText(null);
            }
        }

        else if (text.equals("<")) {

            if (!field.getText().isEmpty()) {
                field.setText(field.getText().substring(0, field.getText().length() - 1));
            }
        }

        else if (text.equals("+")) {

            if (!field.getText().isEmpty()) {

                fNum = Double.valueOf(field.getText());
                field.setText(null);
                operation = text;
            }

        }

        else if (text.equals("-")) {

            if (!field.getText().isEmpty()) {

                fNum = Double.valueOf(field.getText());
                field.setText(null);
                operation = text;
            }
        }


        else if (text.equals("\u00D7")) { //multiply

            if (!field.getText().isEmpty()) {

                fNum = Double.valueOf(field.getText());
                field.setText(null);
                operation = text;
            }
        }

        else if (text.equals("\u00F7")) {//divide

            if (!field.getText().isEmpty()) {

                fNum = Double.valueOf(field.getText());
                field.setText(null);
                operation = text;
            }
        }

        else if (text.equals("%")) {

            if (("\u00F7").equals(operation)) { //% applies only after divide

                sNum = Double.valueOf(field.getText());
                field.setText(String.valueOf(percentageFormat.format(fNum/sNum)));
                operation = null;
            }
        }

        else if (text.equals("=")) {

            if (!field.getText().isEmpty() && (operation != null)) {

                sNum = Double.valueOf(field.getText());

                if (operation.equals("+")) {
                    result = fNum + sNum;
                } else if (operation.equals("-")) {
                    result = fNum - sNum;
                } else if (operation.equals("x")) {
                    result = fNum * sNum;
                } else if (operation.equals("\u00F7")) {
                    result = fNum / sNum;
                } else if (operation.equals("\u00D7")) {
                    result = fNum * sNum;
                }

                field.setText(String.valueOf(result));
            }
        }

        else if (event.getSource().equals(bPlusMine)) {

            if (!field.getText().isEmpty()) {

                double num = Double.valueOf(field.getText());

                if (num > 0) {
                    field.setText(String.valueOf(num - (num * 2)));
                } else {
                    field.setText(String.valueOf(Math.abs(num)));
                }
            }
        }
    }

    private boolean isInteger(String text) {

        try {
            Integer.parseInt(text);
        } catch (NumberFormatException e) {
            return false;
        }

        return true;
    }

    private JButton makeButton(String text) {

        JButton button = new JButton(text);
        button.setFont(fontButton);
        button.addActionListener(this);
        centerPanel.add(button);

        return button;
    }
}

//source : https://stackoverflow.com/a/10136854/3992939
class JTextFieldLimit extends PlainDocument {
    private int limit;
    JTextFieldLimit(int limit) {
        super();
        this.limit = limit;
    }

    JTextFieldLimit(int limit, boolean upper) {
        super();
        this.limit = limit;
    }

    @Override
    public void insertString(int offset, String str, AttributeSet attr) throws BadLocationException {
        if (str == null) {
            return;
        }

        if ((getLength() + str.length()) <= limit) {
            super.insertString(offset, str, attr);
        }
    }
}

I would also recommend to improve the code implementing to following changes:

//Constants  (better use enum)
    private final static String BACK ="<", CLEAR="c", DIVIDE = "\u00F7", MULTIPLY = "\u00D7",
                MINUS = "-", PLUS = "+", PLUS_MINUS = "±" , DOT = ".", EQUAL = "=" ;
    //buttons text in the same order as appear on calculator
    private final String[] buttonText = {
        BACK,CLEAR,"%",DIVIDE,"1","2","3",MULTIPLY,"4","5","6",MINUS,"7","8"
        ,"9",PLUS,PLUS_MINUS,"0",DOT,EQUAL
    };
    /* remove redundant code
    private JButton b1, b2, b3, b4, b5, b6, b7, b8, b9, b0;
    private JButton bPlus,  bMine, bMultiple, bDivision, bEqual;
    private JButton bClear, bErase, bPercent, bPlusMine, bDot;
    */

Add a method to make all buttons:

private void makeButtons() {

        for(String text : buttonText) {
            JButton button = new JButton(text);
            button.setFont(fontButton);
            button.addActionListener(this);
            centerPanel.add(button);
        }
} 

And modify setGUI()

        makeButtons(); //replaces all the following code 

        /*remove redundant code 
         //a repeated code is an opportunity for a method
        //the method also adds buttons to JPanel
        bErase = makeButton("<");
        bClear = makeButton("c");
        bPercent = makeButton("%");
        bDivision = makeButton("\u00F7");

        b1 = makeButton("1");
        b2 = makeButton("2");
        b3 = makeButton("3");
        bMultiple = makeButton("\u00D7");

        b4 = makeButton("4");
        b5 = makeButton("5");
        b6 = makeButton("6");
        bMine = makeButton("-");

        b7 = makeButton("7");
        b8 = makeButton("8");
        b9 = makeButton("9");
        bPlus = makeButton("+");

        bPlusMine = makeButton("±");
        b0 = makeButton("0");
        bDot = makeButton(".");
        bEqual = makeButton("=");

         */

Here is a link to amended code.

c0der
  • 18,467
  • 6
  • 33
  • 65