プラットフォームを選ばないという理由でJava swingで書いてみた
import java.util.Stack; import java.util.Map; import java.util.HashMap; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JButton; import javax.swing.JTextField; import java.awt.Dimension; import java.awt.GridLayout; import java.awt.BorderLayout; import java.awt.Font; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; public class CalcForm extends JFrame{ // サイズなどの定数 private static final String FORM_NAME = "簡易電卓"; private static final int FORM_HEIGHT = 600; private static final int FORM_WIDTH = 600; public CalcForm(){ super(FORM_NAME); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(10, 10, FORM_WIDTH, FORM_HEIGHT); // UI部分生成 setUI(); } private void setUI(){ //数値表示用 JPanel textPanel = new JPanel(); textPanel.setPreferredSize(new Dimension(FORM_WIDTH, 60)); JTextField textField = new JTextField(); textField.setPreferredSize(new Dimension(FORM_WIDTH - 10, 50)); //編集は不可にする textField.setEditable(false); textField.setFont(new Font(Font.SERIF, Font.PLAIN, 40)); textField.setHorizontalAlignment(JTextField.RIGHT); textField.setText("0"); textPanel.add(textField); getContentPane().add(textPanel, BorderLayout.NORTH); //計算エンジン CalcEngine engine = new CalcEngine(textField); JPanel panel = new JPanel(); //レイアウトはグリッド panel.setLayout(new GridLayout(4, 4)); //ボタンの作成 for(int y = 0 ; y < NumberedButton.BUTTON_LABELS.length ; ++y){ for(int x = 0 ; x < NumberedButton.BUTTON_LABELS[y].length ; ++x){ NumberedButton button = new NumberedButton(engine, x, y); button.addMouseListener(button); panel.add(button); } } getContentPane().add(panel, BorderLayout.CENTER); } } class NumberedButton extends JButton implements MouseListener{ private int x; private int y; private CalcEngine engine; public static final String[][] BUTTON_LABELS = new String[][]{ {"7", "8", "9", "/"}, {"4", "5", "6", "*"}, {"1", "2", "3", "-"}, {"0", "=", "C", "+"}, }; public NumberedButton(CalcEngine engine, int x, int y){ super(BUTTON_LABELS[y][x]); this.x = x; this.y = y; this.engine = engine; } public void mouseEntered(MouseEvent e){ /**/ } public void mouseExited(MouseEvent e){ /**/ } public void mouseReleased(MouseEvent e){ /**/ } public void mousePressed(MouseEvent e){ engine.addValue(BUTTON_LABELS[y][x]); } public void mouseClicked(MouseEvent e){ /**/ } } class CalcEngine{ private JTextField display; //計算用スタック private Stack<String> calStack = new Stack<String>(); //次回の数値セット時に表示部分をクリアするフラグ private boolean clearDispay = false; //オペレータとそれに対応したメソッドのマップ private static Map<String, Calculable> operatorMap = new HashMap<String, Calculable>(); static{ operatorMap.put("+", new Plus()); operatorMap.put("-", new Minus()); operatorMap.put("*", new Multiple()); operatorMap.put("/", new Divide()); } /** * 引数が演算子か調べる */ private boolean isOperator(String value){ return operatorMap.containsKey(value); } public CalcEngine(JTextField disp){ this.display = disp; } /** * UIより数値を受け取るメソッド */ public void addValue(String value){ String nowValue = display.getText(); if(isOperator(value)){ if(!calStack.empty()){ calc(); nowValue = display.getText(); } //演算子だったらスタックに積む calStack.push(nowValue); calStack.push(value); //次数字押した時は画面消去 clearDispay = true; }else if(value.equals("=")){ //計算 calc(); }else if(value.equals("C")){ //全クリア calStack.clear(); display.setText("0"); }else{ if(clearDispay){ clearDispay = false; nowValue = ""; } //先頭が0だったらその0は消しておく if(nowValue.equals("0")){ nowValue = ""; } //表示の限界は8文字 if(nowValue.length() < 8){ display.setText(nowValue + value); } } } /** * 実際に計算を行います */ private void calc(){ // 計算スタックが空の時は何もしない if(calStack.empty()){ return; } String operator = calStack.pop(); int leftVal = 0; int rightVal = 0; //右辺と左辺を数値化 try{ String leftValString = calStack.pop(); leftVal = Integer.parseInt(leftValString); String rightValString = display.getText(); rightVal = Integer.parseInt(rightValString); }catch(NumberFormatException e){ return; } //実際に計算は演算子クラスがやってくれる Calculable op = operatorMap.get(operator); String result = op.calc(leftVal, rightVal); //結果を表示 display.setText(result); } } /** * 演算できることを表すインターフェース */ interface Calculable{ String calc(int leftValue, int rightValue); } /** * 足し算を行う演算子 */ class Plus implements Calculable{ public String calc(int leftValue, int rightValue){ return leftValue + rightValue + ""; } } /** * 引き算を行う演算子 */ class Minus implements Calculable{ public String calc(int leftValue, int rightValue){ return leftValue - rightValue + ""; } } /** * 掛算を行う演算子 */ class Multiple implements Calculable{ public String calc(int leftValue, int rightValue){ return leftValue * rightValue + ""; } } /** * 割り算を行う演算子 */ class Divide implements Calculable{ public String calc(int leftValue, int rightValue){ if(rightValue == 0){ return "0"; } return leftValue / rightValue + ""; } }
なかなか最初から意識して書かないと、ダメだなぁ
・GridLayoutの引数はボタンラベルの配列の長さを使うべき
・setUIをボタンの初期化部分とディスプレイの初期化部分に分割すべき
・NumberedButtonの存在意義がいまひとつ
最近私、Javaでこういったカッチリしたコード書いてないなぁ…。
fkmさんのこれを見習ってJavaでちゃんと書いてみるべきかなぁ。