2
\$\begingroup\$

I have created my first Java app. I am very familiar with C++ and thus without reading any books (just introduction, googling and IntelliJ auto-completion) I directly jumped into Java. So I made a calculator.

Main.java:

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.swing.*;
import javax.swing.text.PlainDocument;
import java.awt.*;
import java.awt.event.KeyEvent;

class Main extends JFrame {

    public static void main(String[] args) throws AWTException {
        System.out.println("init");
        var app = new Main();
        app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        app.setVisible(true);
    }

    private JButton numButtons[] = new JButton[10];
    private JButton opeButtons[] = new JButton[5];
    private JButton lb = new JButton("(");
    private JButton rb = new JButton(")");
    private JButton cb = new JButton("C");
    private JButton decb = new JButton(".");
    private JTextField text = new JTextField();
    private Robot keyboard = new Robot();
    private ScriptEngine jsEng;

    public Main() throws AWTException {
        super();

        jsEng = (new ScriptEngineManager()).getEngineByName("js");

        var textDoc = (PlainDocument)text.getDocument();
        textDoc.setDocumentFilter(new EquationFilter());
        initGui();


        for(JButton i : numButtons) {
            i.addActionListener(e -> simKey(i.getText().charAt(0)));
        }

        for(int i = 0;i<4;i++) {
            int finalI = i;
            opeButtons[i].addActionListener(e -> simKey(opeButtons[finalI].getText().charAt(0)));
        }
        decb.addActionListener(e -> simKey(decb.getText().charAt(0)));
        rb.addActionListener(e -> simKey(rb.getText().charAt(0)));
        lb.addActionListener(e -> simKey(lb.getText().charAt(0)));

        cb.addActionListener(e-> text.setText(""));
        opeButtons[4].addActionListener(e -> {
            try {
                text.setText(jsEng.eval(text.getText()).toString());
            } catch (ScriptException e1) {
                e1.printStackTrace();
            }
        });


    }

    private void simKey(char code){
        text.requestFocus();
        keyboard.keyPress(KeyEvent.VK_SHIFT);
        switch (code) {
            case '+':
                keyboard.keyPress(KeyEvent.VK_EQUALS);
                keyboard.keyRelease(KeyEvent.VK_EQUALS);
                break;
            case '(':
                keyboard.keyPress(KeyEvent.VK_LEFT_PARENTHESIS);
                keyboard.keyRelease(KeyEvent.VK_LEFT_PARENTHESIS);
                break;
            case ')':
                keyboard.keyPress(KeyEvent.VK_RIGHT_PARENTHESIS);
                keyboard.keyRelease(KeyEvent.VK_RIGHT_PARENTHESIS);
                break;
            case '*':
                keyboard.keyPress('8');
                keyboard.keyRelease('8');
                break;
            default:
                keyboard.keyRelease(KeyEvent.VK_SHIFT);
                keyboard.keyPress(code);
                keyboard.keyRelease(code);
                return;
        }
        keyboard.keyRelease(KeyEvent.VK_SHIFT);

    }

    private void initGui(){
        setTitle("Calculator");
        setSize(400,500);
        var grid = new GridBagLayout();
        setLayout(grid);
        GridBagConstraints gridCon = new GridBagConstraints();
        gridCon.weightx = gridCon.weighty = 1.0;

        gridCon.gridy = 0;
        gridCon.gridx = 0;
        gridCon.gridwidth = 4;
        gridCon.fill = gridCon.BOTH;
        add(text,gridCon);

        gridCon.gridwidth = 1 ;

        String names[] = {"+","-","/","*","="};
        for(int i = 0;i < 5; i++){
            opeButtons[i] = new JButton(names[i]);
        }

        gridCon.gridx = 3;
        for( int y = 1; y < 6; y++ ){
            gridCon.gridy = y;
            add(opeButtons[y-1],gridCon);
        }

        for(int y = 2, i = 1; y < 5; y++ ){
            for(int x = 0 ; x < 3; x++,i++) {
                gridCon.gridx = x;
                gridCon.gridy = y;
                numButtons[i] = new JButton(Integer.toString(i));
                add(numButtons[i],gridCon);
            }
        }

        gridCon.gridx = 0;
        gridCon.gridy = 1;
        add(lb,gridCon);
        gridCon.gridx = 1;
        add(rb,gridCon);
        gridCon.gridx = 2;
        add(cb,gridCon);

        numButtons[0] = new JButton("0");
        gridCon.gridx = 0;
        gridCon.gridy = 5;
        gridCon.gridwidth = 2;
        add(numButtons[0],gridCon);

        gridCon.gridwidth = 1;
        gridCon.gridx = 2;
        add(decb,gridCon);
    }
}

EquationFilter.java:

import javax.swing.text.AttributeSet;
import javax.swing.text.Document;
import javax.swing.text.DocumentFilter;
import javax.swing.text.BadLocationException;
import java.awt.event.KeyEvent;
import java.security.Key;

public class EquationFilter extends DocumentFilter {

    @Override
    public void insertString(FilterBypass fb, int offset, String string,
                             AttributeSet attr) throws BadLocationException {

        Document doc = fb.getDocument();
        StringBuilder sb = new StringBuilder();
        sb.append(doc.getText(0, doc.getLength()));
        sb.insert(offset, string);

        if (test(sb.toString())) {
            super.insertString(fb, offset, string, attr);
        }
    }

    private boolean test(String text) {
        char validInput[] = {'1','2','3','4','5','6','7','8','9','0','.','/','*','-','+','(',')',' ','\0','\b'};

        if(text.isEmpty())
            return true;

        for(char i : validInput){
            if(i == text.charAt(text.length()-1))
                return true;
        }
        return false;

    }

    @Override
    public void replace(FilterBypass fb, int offset, int length, String text,
                        AttributeSet attrs) throws BadLocationException {

        Document doc = fb.getDocument();
        StringBuilder sb = new StringBuilder();
        sb.append(doc.getText(0, doc.getLength()));
        sb.replace(offset, offset + length, text);

        if (test(sb.toString())) {
            super.replace(fb, offset, length, text, attrs);
        }

    }

    @Override
    public void remove(FilterBypass fb, int offset, int length)
            throws BadLocationException {
        Document doc = fb.getDocument();
        StringBuilder sb = new StringBuilder();
        sb.append(doc.getText(0, doc.getLength()));
        sb.delete(offset, offset + length);

        try {
            if (test(sb.toString())) {
                super.remove(fb, offset, length);
            }
        }
        catch (StringIndexOutOfBoundsException e) {
            super.remove(fb,0,1);
        }

    }
}

https://gitlab.com/SmitTheTux/javacalculator

Please suggest me improvments.

\$\endgroup\$
  • \$\begingroup\$ It looks to me that the test method doesn't do what one might expect. As it is, it only checks if the last character of the input string is valid. It seems to me that one would want to check that all the characters of the input string are valid. Is the current behavior what you expected? \$\endgroup\$ – tinstaafl Dec 11 '18 at 15:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.