Simple calculator implemented by Java Swing

Posted by anthonyw17 on Fri, 07 Jan 2022 16:07:25 +0100

 

Project introduction

 

MVC model

 

Project introduction (download at the end of the text):

 

Calculator window, user interface

 

Button monitoring and keyboard monitoring are equivalent to controllers

 

Data processing, equivalent to model

 

General idea,

When the user clicks the button or presses the keyboard, the controller will listen and obtain the returned value of the event,

And call the handleValue method of the data processing class to enter the switch according to the returned value to judge what to do

Here is the design code of the window. I use a lot of box layout

(Note: if you want to see the window without event monitoring, just remove it)

import javax.swing.*;
import java.awt.*;

/**
 * @author mobeicanyue
 * Create  2021-12-18 10:35
 * Describe:Calculator window
 */

public class CalculatorWindow extends JFrame {
    JTextField[] text = new JTextField[4];

    List resultList = new List(11, false);//List selection box

    //Button listening and event listening
    ButtonAction buttonAction = new ButtonAction(this);
    KeyAction keyAction = new KeyAction(this);

    public void basicInit() { //Initialize the basic settings of the form
        setTitle("create by mobeiCanyue                                       Calculator");
        setResizable(false);
        setBounds(200, 200, 700, 340);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
        setIconImage(Toolkit.getDefaultToolkit().getImage(CalculatorWindow.class.getResource("Porsche.png")));
    }

    public CalculatorWindow() {
        basicInit();//initialization

        add(Box.createVerticalStrut(8));

        JPanel topPanel = loadTopPanel(text, keyAction);//Load the top four display boxes and place them in topPanel
        add(topPanel);

        add(Box.createVerticalStrut(8));

        final Box bottomBox = Box.createHorizontalBox();//In addition to the top, the lower box, the style is horizontal
        bottomBox.add(Box.createHorizontalStrut(7));//Left spacing

        final Font font = new Font("Isoline", Font.BOLD, 16);

        final JButton[][] buttons = new JButton[4][5];//Several buttons on the left
        Box buttonBox = loadButtonBox(font, buttons, buttonAction, keyAction);//Load a large button on the left
        bottomBox.add(buttonBox);

        bottomBox.add(Box.createHorizontalStrut(3)); //Space between left and right

        final Box rightBox = Box.createVerticalBox();//A large piece to the right of the bottom box
        //Add list selection box
        rightBox.add(resultList);

        rightBox.add(Box.createVerticalStrut(10));//The distance from the text field to the three boxes below

        final JButton[] buttons2 = new JButton[3];//Several buttons on the lower right
        Box buttonBox2 = loadButtonBox2(font, buttons2, buttonAction);//Load the second box that holds the button
        rightBox.add(buttonBox2);

        bottomBox.add(Box.createHorizontalStrut(2));
        bottomBox.add(rightBox);
        bottomBox.add(Box.createHorizontalStrut(7));
        add(bottomBox);
        try {//Change the subject
            for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        }catch(Exception e) {
            e.printStackTrace();
        }
        setVisible(true);
    }

    public JPanel loadTopPanel(JTextField[] text, KeyAction keyAction) {
        final JPanel topPanel = new JPanel();//The top four text box containers, JPanel default flow layout
        //Font and size used
        final Font font = new Font("", Font.BOLD, 25);
        //The four text boxes above
        text[0] = new JTextField(9);
        text[1] = new JTextField(2);
        text[2] = new JTextField(9);
        text[3] = new JTextField(13);

        topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.X_AXIS));

        for (JTextField jTextField : text) {
            jTextField.setEditable(false);
            jTextField.setFont(font);
            jTextField.addKeyListener(keyAction);
            jTextField.setHorizontalAlignment(JTextField.CENTER);
        }

        text[0].setPreferredSize(new Dimension(175, 9));
        text[1].setPreferredSize(new Dimension(50, 9));
        text[2].setPreferredSize(new Dimension(175, 9));
        text[3].setPreferredSize(new Dimension(175, 9));

        text[0].setText("0");

        topPanel.add(Box.createHorizontalStrut(7));
        for (int i = 0; i < 3; i++) {
            topPanel.add(text[i]);
        }
        //Because the panels need to be spaced, they are added separately
        topPanel.add(Box.createHorizontalStrut(8));
        topPanel.add(text[3]);
        topPanel.add(Box.createHorizontalStrut(5));
        return topPanel;
    }

    public Box loadButtonBox(Font font, JButton[][] buttons, ButtonAction buttonAction, KeyAction keyAction) {
        final Box buttonBox = Box.createVerticalBox();//A large button on the left of the bottom box

        final JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new GridLayout(4, 5, 5, 10));
        final String[][] names = {
                {"1", "2", "3", "/", "C"}, {"4", "5", "6", "*", "Backspace"},
                {"7", "8", "9", "-", "sqrt"}, {"0", "+/-", ".", "+", "="}
        };
        for (int row = 0; row < names.length; row++) {
            for (int col = 0; col < names[0].length; col++) {
                buttons[row][col] = new JButton(names[row][col]);// Create button
                buttons[row][col].setFont(font);
                buttons[row][col].setPreferredSize(new Dimension(65, 50));
                buttons[row][col].addActionListener(buttonAction);
                buttons[row][col].addKeyListener(keyAction);
                buttonPanel.add(buttons[row][col]); // Add button to button panel
            }
        }
        buttonBox.add(buttonPanel);
        buttonBox.add(Box.createVerticalStrut(5));//Bottom margin
        return buttonBox;
    }

    public Box loadButtonBox2(Font font, JButton[] buttons2, ButtonAction buttonAction) {
        final Box buttonBox2 = Box.createVerticalBox();//The second box carrying the button

        //final Font font = new Font("Microsoft YaHei", Font.BOLD, 14);
        JPanel buttonPanel2 = new JPanel();
        buttonPanel2.setLayout(new GridLayout(1, 3, 8, 8));

        buttons2[0] = new JButton("preservation");
        buttons2[1] = new JButton("see");
        buttons2[2] = new JButton("eliminate");
        for (JButton button : buttons2) {
            button.setPreferredSize(new Dimension(55, 43));
            buttonPanel2.add(button);
            button.setFont(font);
            button.addActionListener(buttonAction);
        }
        buttonBox2.add(buttonPanel2);

        buttonBox2.add(Box.createVerticalStrut(5));//Width of the right box from the bottom
        return buttonBox2;
    }
}
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author mobeiCanyue
 * Create  2021-12-24 19:25
 * Describe: The class used to process data is separated to simplify the code because the processing of button events and keyboard events highly coincide
 */
public class DataHandle {
    static StringBuilder s1 = new StringBuilder();//Left
    static String s2;//right
    static StringBuilder s3 = new StringBuilder();//in

    //"LEFT" "RIGHT" "MID" "RESULT"
    static String status = "LEFT";//The default position of the initialization window, ****** is very important. You can understand the process control of this program and determine the position of the text box by changing it!

    public static void changeValue(String tabValue, StringBuilder s, JTextField jTextField) {
        s.append(tabValue);
        jTextField.setText(s.toString());
    }

    public static void cleanPanel(StringBuilder s1, StringBuilder s3, JTextField[] texts) {
        s1.delete(0, s1.length());
        s3.delete(0, s3.length());
        for (JTextField jTextField : texts) {
            jTextField.setText("");
        }
        texts[0].setText("0");
        status = "LEFT";
    }

    public static float calculate(StringBuilder s1, String s2, StringBuilder s3, JTextField textField) {
        float result = 0;
        switch (s2) {
            case "/":
                result = Float.parseFloat(s1.toString()) / Float.parseFloat(s3.toString());
                textField.setText(String.valueOf(result));
                break;
            case "*":
                result = Float.parseFloat(s1.toString()) * Float.parseFloat(s3.toString());
                textField.setText(String.valueOf(result));
                break;
            case "+":
                result = Float.parseFloat(s1.toString()) + Float.parseFloat(s3.toString());
                textField.setText(String.valueOf(result));
                break;
            case "-":
                result = Float.parseFloat(s1.toString()) - Float.parseFloat(s3.toString());
                textField.setText(String.valueOf(result));
                break;
        }
        return result;
    }

    public static void back(StringBuilder s, JTextField textField) {
        if (s.length() != 0) {
            s.delete(s.length() - 1, s.length());
            textField.setText(s.toString());
        }
    }

    public static void addList(StringBuilder s1, String s2, StringBuilder s3, float result, List results) {
        String temp = s1.toString() + " " + s2 + " " + s3.toString() + " = " + result;
        results.add(temp);
    }

    public static void positive_negative(StringBuilder sb, JTextField textField) {
        if (sb.toString().equals("0")) {//If it is 0, it remains positive or negative
            return;
        }
        if (String.valueOf(sb.charAt(0)).equals("-")) {
            sb.deleteCharAt(0);
        } else {
            sb.insert(0, "-");
        }
        textField.setText(sb.toString());
    }

    public static void saveList(List list) {
        Date date = new Date();//Get current time
        SimpleDateFormat dateFormat = new SimpleDateFormat("'Date' yyyy.MM.dd 'Time' HH.mm.ss");
        String fileName = dateFormat.format(date) + ".txt";//file name
        try (BufferedWriter bw = new BufferedWriter(new FileWriter(fileName))) {
            String[] items = list.getItems();//Gets a String array of all elements of the list
            bw.write(dateFormat.format(date) + "\n");
            for (String item : items) {
                bw.write(item + "\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void viewFile(CalculatorWindow calculatorWindow, List list) {

        String fileName = new FileChooseDialog(calculatorWindow).getFile();
        if (fileName == null) {
            System.out.println("No files selected");
            return;
        }

        try (BufferedReader br = new BufferedReader(new FileReader(fileName))
        ) {
            list.removeAll();
            int len;
            char[] data = new char[20];
            StringBuilder temp = new StringBuilder();
            while ((len = br.read(data)) != -1) {
                temp.append(data, 0, len);
            }
            int head = 0;
            int index = temp.indexOf("\n");
            while (index != temp.length()) {
                String substring = temp.substring(head, index);
                System.out.println("substring = " + substring);
                list.add(substring);
                temp.delete(head, index + 1);
                index = temp.indexOf("\n");
                if (index == -1) {
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void handleValue(String tabValue, CalculatorWindow calculatorWindow) {
        switch (tabValue) {
            case "0":
            case "1":
            case "2":
            case "3":
            case "4":
            case "5":
            case "6":
            case "7":
            case "8":
            case "9":
                if ("RESULT".equals(status)) {
                    System.out.println(status);
                    cleanPanel(s1, s3, calculatorWindow.text); //Clear before doing
                    changeValue(tabValue, s1, calculatorWindow.text[0]);
                    break;
                }
                if ("LEFT".equals(status)) {
                    System.out.println(status);
                    changeValue(tabValue, s1, calculatorWindow.text[0]);
                    break;
                }
                if ("MID".equals(status)) {//If the state is in the middle, do it
                    if (s2.equals("")) {
                        break;
                    }
                    status = "RIGHT";//Change the status, which is in the number box on the right
                }
                if ("RIGHT".equals(status)) {
                    System.out.println(status);
                    changeValue(tabValue, s3, calculatorWindow.text[2]);
                    break;
                }
            case ".":
                if ("LEFT".equals(status)) {
                    if (s1.indexOf(".") != -1) {
                        break;
                    }
                    System.out.println(status);
                    changeValue(tabValue, s1, calculatorWindow.text[0]);
                    break;
                }
                if ("RIGHT".equals(status)) {
                    if (s3.indexOf(".") != -1) {
                        break;
                    }
                    System.out.println(status);
                    changeValue(tabValue, s3, calculatorWindow.text[2]);
                    break;
                }

            case "sqrt":
                if ("LEFT".equals(status)) {
                    if (s1.toString().equals("")) {
                        break;
                    }
                    s1 = new StringBuilder(String.valueOf(Math.sqrt(Float.parseFloat(s1.toString()))));
                    calculatorWindow.text[0].setText(s1.toString());
                }
                if ("RIGHT".equals(status)) {
                    if (s3.toString().equals("")) {
                        break;
                    }
                    s3 = new StringBuilder(String.valueOf(Math.sqrt(Float.parseFloat(s3.toString()))));
                    calculatorWindow.text[2].setText(s3.toString());
                }
                break;
            case "Backspace":
                if ("RESULT".equals(status)) {
                    break;//The results come out and can't be disqualified
                }
                if ("LEFT".equals(status)) {
                    if (s1.length() == 1) {
                        back(s1, calculatorWindow.text[0]);
                        calculatorWindow.text[0].setText("0");
                    } else {
                        back(s1, calculatorWindow.text[0]);
                    }
                    break;
                }
                if ("MID".equals(status)) {
                    if (s2.equals("")) {//If the middle is empty, run to the front
                        status = "LEFT";
                        back(s1, calculatorWindow.text[0]);
                        break;
                    }
                    s2 = "";
                    calculatorWindow.text[1].setText(s2);
                    break;
                }
                if ("RIGHT".equals(status)) {
                    if (s3.toString().equals("")) {//If the back is empty, run to the middle
                        status = "MID";
                        s2 = "";
                        calculatorWindow.text[1].setText(s2);
                    }
                    back(s3, calculatorWindow.text[2]);
                    break;
                }

            case "/":
            case "*":
            case "-":
            case "+":
                if (s1.length() == 0 || status.equals("RESULT")) {
                    break;
                }
                calculatorWindow.text[1].setText(tabValue);//Set text box display
                s2 = tabValue; //Set operator
                status = "MID";
                System.out.println(status);
                break;
            case "+/-":
                if (status.equals("LEFT")) {
                    positive_negative(s1, calculatorWindow.text[0]);
                }
                if (status.equals("RIGHT")) {
                    positive_negative(s3, calculatorWindow.text[2]);
                }
                break;
            case "=":
                if (!"RIGHT".equals(status)) {
                    break;
                }
                status = "RESULT";
                System.out.println(status);
                float result = calculate(s1, s2, s3, calculatorWindow.text[3]);
                addList(s1, s2, s3, result, calculatorWindow.resultList);
                break;

            case "C":
                cleanPanel(s1, s3, calculatorWindow.text);
                break;

            case "eliminate":
                calculatorWindow.resultList.removeAll();
                break;

            case "preservation":
                if (calculatorWindow.resultList.getItemCount() == 0) {
                    JOptionPane.showMessageDialog(calculatorWindow, "The list is empty! ! ! ", "The list is empty", JOptionPane.ERROR_MESSAGE);
                } else {
                    saveList(calculatorWindow.resultList);
                    JOptionPane.showMessageDialog(calculatorWindow, "Saved successfully", "Saved successfully", JOptionPane.INFORMATION_MESSAGE);
                }
                break;

            case "see":
                viewFile(calculatorWindow, calculatorWindow.resultList);
                break;
        }
    }
}

Small details:

  • I use a string to store the current position of the window. For example, the initial character input is on the left. I keep inputting numbers without changing the state quantity. Then I press the operator. At this time, the state quantity will change to the middle. If I press the string again, it will change to the right (this is very convenient for other operations later)
  • Each time you press the button or the keyboard, the value of the button and the current state (in which window the string is entered) will be output on the command line
  • If there is a decimal point in the string, you can't enter the string. break directly

  • When the result comes out, it will not be backspace. When the window on the left has no value, it will be 0

  • To change the value in the calculator box, the usual idea is: enter a value, 1 Take the string from the text box, 2 Append the value to or before the string, 3 Then set it in the text box
  • This is what I do. I take out the value in the text box separately. 1 Get the value and add it directly, 2 Then set to the text box In this way, there are fewer steps to add and set the value (of course, pay attention to ensure the synchronization of the two each time), and the StringBuilder is used to greatly improve the efficiency

  • Save the history to a file. If it is empty, a warning will be given

 

The complete code is put on GitHub. You need to take it yourself,

mobeiCanyue/Java_calculator: Calculator implements by Java (github.com) 

 

If you just want to run, you can download only jar files (of course, you have to have a Java environment)

Releases · mobeiCanyue/Java_calculator (github.com)

Topics: Java Back-end IDEA