javascript学习指南|Java 简易计算器之学习笔记

更新时间:2019-05-17    来源:js教程    手机版     字体:

【www.bbyears.com--js教程】

为了练手,抽空做了这款“简易计算器”。就此谈谈在制作过程中遇到的问题。

在制作时,swing组件的布局可累坏我了,还是比较熟悉以前那种“所见即所得”的可视化组件布局方式,下面是UI类,用于绘制UI。

 代码如下

package me.jerrys.calc;

import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.KeyEventPostProcessor;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.HashMap;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

@SuppressWarnings("serial")
public class CalcUI extends JFrame implements ActionListener {
 private CalcAction action;
 public HashMap actionsMap = new HashMap();
 public HashMap buttonMap = new HashMap();
 public JLabel rusultLabel;

 public CalcUI(CalcAction action) {
  super("简易计算器 - Coded by JerryLocke");
  this.action = action;
  createUI();
  showMessage("程序  Java 简易计算器n作者  @JerryLocken博客  http://111CN.NETn提示  您可以使用键盘进行操作");
 }

 public void createUI() {
  rusultLabel = new JLabel("0");
  rusultLabel.setFont(new Font("Arial", 0, 32));
  JPanel topPanel = new JPanel();
  topPanel.add(rusultLabel);
  topPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
  JPanel numberPanel = new JPanel(new GridLayout(4, 3, 5, 5));
  String[][] numberTitle = { { "7" }, { "8" }, { "9" }, { "4" }, { "5" }, { "6" }, { "1" }, { "2" }, { "3" }, { "0" }, { ".", "小数点" }, { "+/-", "正/负" } };
  batchCreateButton(numberTitle, numberPanel, this);
  JPanel calc1Panel = new JPanel(new GridLayout(2, 2, 5, 5));
  String[][] calc1Title = { { "←", "退格" }, { "C", "清零" }, { "×", "乘" }, { "÷", "除" } };
  batchCreateButton(calc1Title, calc1Panel, this);
  JPanel calc2Panel = new JPanel(new GridLayout(2, 1, 5, 5));
  String[][] calc2Title = { { "-", "减" }, { "=", "等于" } };
  batchCreateButton(calc2Title, calc2Panel, this);
  topPanel.setBounds(5, 0, 330, 50);
  numberPanel.setBounds(5, 50, 200, 313);
  calc1Panel.setBounds(210, 51, 130, 153);
  calc2Panel.setBounds(277, 209, 62, 153);
  JButton calcButton = createButton("+", this);
  calcButton.setBounds(210, 209, 62, 153);
  calcButton.setFont(new Font("Arial", 0, 20));
  this.setLayout(null);
  this.add(topPanel);
  this.add(numberPanel);
  this.add(calc1Panel);
  this.add(calc2Panel);
  this.add(calcButton);
  this.setSize(350, 400);
  KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
  manager.addKeyEventPostProcessor(new KeyEventPostProcessor() {
   public boolean postProcessKeyEvent(KeyEvent e) {
    if (e.getID() == KeyEvent.KEY_RELEASED) {
     String key = "-1";
     switch (e.getKeyCode()) {
     case KeyEvent.VK_NUMPAD0:
      key = "0";
      break;
     case KeyEvent.VK_NUMPAD1:
      key = "1";
      break;
     case KeyEvent.VK_NUMPAD2:
      key = "2";
      break;
     case KeyEvent.VK_NUMPAD3:
      key = "3";
      break;
     case KeyEvent.VK_NUMPAD4:
      key = "4";
      break;
     case KeyEvent.VK_NUMPAD5:
      key = "5";
      break;
     case KeyEvent.VK_NUMPAD6:
      key = "6";
      break;
     case KeyEvent.VK_NUMPAD7:
      key = "7";
      break;
     case KeyEvent.VK_NUMPAD8:
      key = "8";
      break;
     case KeyEvent.VK_NUMPAD9:
      key = "9";
      break;
     case KeyEvent.VK_MULTIPLY:
      key = "×";
      break;
     case KeyEvent.VK_DIVIDE:
      key = "÷";
      break;
     case 107:
      key = "+";
      break;
     case 109:
      if (action.getCurrentText().equals("0")) key = "-";
      else key = "-";
      break;
     case KeyEvent.VK_ENTER:
      key = "=";
      break;
     case 110:
      key = ".";
      break;
     case KeyEvent.VK_BACK_SPACE:
      key = "←";
      break;
     }
     if (key.equals("-1")) return true;
     buttonMap.get(key).doClick();
    }
    return true;
   }
  });
  this.setVisible(true);
  this.setResizable(false);
  this.setLocationRelativeTo(null);
  this.setDefaultCloseOperation(EXIT_ON_CLOSE);
 }

 public void batchCreateButton(String[][] buttonTitle, JPanel panel, ActionListener listener) {
  for (String[] title : buttonTitle) {
   if (title.length == 2) panel.add(createButton(title[0], title[1], this));
   else panel.add(createButton(title[0], this));
  }
 }

 public JButton createButton(String title, String tipText, ActionListener listener) {
  JButton button = createButton(title, this);
  button.setToolTipText(tipText);
  return button;
 }

 public JButton createButton(String title, ActionListener listener) {
  JButton button = new JButton(title);
  actionsMap.put(button.hashCode(), title);
  buttonMap.put(title, button);
  button.addActionListener(listener);
  button.setFont(new Font("Arial", 0, 20));
  return button;
 }

 public void showMessage(String message) {
  JOptionPane.showMessageDialog(null, message);
 }

 @Override
 public void actionPerformed(ActionEvent e) {
  String command = (String) actionsMap.get(e.getSource().hashCode());
  action.doAction(command);
 }

}
刚开始用的是想用边界布局(BorderLayout)+网格布局(GridLayout)制作界面,但是遇到了诸如南北高度宽度难控制,中间填充等问题,最后还是给跪了,直接上了绝对布局。以后在这方面需要多练习。

需要注意的是,为控件增加监听器时,还需要用HashMap来标识每个控件以及存放控件指向的命令。除此之外,上面还使用了 KeyboardFocusManager 为窗口添加快捷键。
以下是动作类,负责处理控件事件以及计算操作等。

package me.jerrys.calc;

import java.math.BigDecimal;

public class CalcAction {
 private CalcUI UI;
 private BigDecimal lastNum = new BigDecimal("0");
 private BigDecimal currentNum = new BigDecimal("0");
 private String currentText;
 private boolean typeClean = false;
 private boolean hadCalced = false;
 private MODE currentMode = MODE.PLUS;

 private enum MODE {
  PLUS, MINUS, MULTIPLY, DIVIDE
 }

 public static void main(String[] args) {
  new CalcAction();
 }

 public CalcAction() {
  this.UI = new CalcUI(this);
 }

 public void doAction(String command) {
  currentText = UI.rusultLabel.getText();
  switch (command) {
  case "C":
   clear();
   break;
  case "←":
   backSpace();
   break;
  case "+":
   setMode(MODE.PLUS);
   break;
  case "-":
   setMode(MODE.MINUS);
   break;
  case "×":
   setMode(MODE.MULTIPLY);
   break;
  case "÷":
   setMode(MODE.DIVIDE);
   break;
  case "=":
   calc();
   break;
  case "+/-":
   addSign();
   break;
  default:
   addNumber(command);
  }
 }

 private void calc() {
  if (hadCalced && typeClean) return;
  currentNum = new BigDecimal(currentText);
  try {
   switch (currentMode) {
   case PLUS:
    lastNum = lastNum.add(currentNum);
    break;
   case MINUS:
    lastNum = lastNum.subtract(currentNum);
    break;
   case MULTIPLY:
    lastNum = lastNum.multiply(currentNum);
    break;
   case DIVIDE:
    lastNum = lastNum.divide(currentNum, 16,
      BigDecimal.ROUND_HALF_DOWN);
    break;
   }
  } catch (Exception e) {
   UI.showMessage("发生错误:" + e.getMessage());
   return;
  }
  String resultText = lastNum.toString();
  if (resultText.indexOf(".") > 0) { // 消除小数多余位数
   resultText = resultText.replaceAll("0+?$", "");
   resultText = resultText.replaceAll("[.]$", "");
  }
  setResultText(resultText);
  typeClean = true;
  hadCalced = false;
 }

 private void setMode(MODE mode) {
  if (!hadCalced && !typeClean) {
   calc();
   currentMode = mode;
   return;
  }
  lastNum = new BigDecimal(currentText);
  currentMode = mode;
  typeClean = true;
  hadCalced = true;
 }

 private void addSign() {
  if (currentText.equals("0") || currentText.equals("")) return;
  if (currentText.startsWith("-")) setResultText(currentText.substring(1));
  else setResultText("-" + currentText);
 }

 private void backSpace() {
  if (currentText.equals("0") || currentText.equals("")) return;
  if (currentText.length() == 1) {
   setResultText("0");
   return;
  }
  setResultText(currentText.substring(0, currentText.length() - 1));
 }

 private void addNumber(String num) {
  String resultText = currentText;
  if (typeClean == true) {
   resultText = "0";
   typeClean = false;
  }
  if (num.equals(".") && currentText.lastIndexOf(".") != -1) return;
  if ((resultText.equals("0") || resultText.equals(""))
    && !num.equals("."))
   resultText = "";
  resultText = resultText + num;
  setResultText(resultText);
 }

 private void clear() {
  currentNum = new BigDecimal("0");
  lastNum = new BigDecimal("0");
  typeClean = false;
  currentMode = MODE.PLUS;
  setResultText("0");
 }

 public String getCurrentText() {
  return currentText;
 }

 private void setResultText(String text) {
  UI.rusultLabel.setText(text);
 }
}

在这里也遇到了问题,刚开始用的是 double 类型存放数值,进行加减乘除计算会有精度问题,会导致意想不到的结果,比如10-9.88会得到 0.11999999999999922 。为了解决这个可以,JDK提供了 BigDecimal 一包用于精准计算,使用方法见上。

(时间紧,未完善,勿喷)

 

Java 简易计算器之学习笔记

本文来源:http://www.bbyears.com/wangyezhizuo/51626.html