java上机实验

我们使用的教材是《java简明教程(第三版)》- 皮德常

Swing实现计算器

  这个上机实验老师要求我们使用Swing制作一个计算器,老师要求我们按照他给定的样式制作,样式如图:


计算器样式

  之后就没啥说的了,直接开始秀智商吧。

盲目分析

  学过Swing后,我们了解到在JFrame框架上需要添加组件来实现样式,那么我们需要

  • JButton组件
  • JTextField组件
  • JPanel组件
  • Container组件

布局实现

  差不多这些组件吧,然后我们就开始动手实现,首先我们需要把这个面板元素划分一下,需要俩个JPanel组件来分区,一个用于上面的显示框,另一个用来放置按钮,显示框我们使用BorderLayout布局,按钮我们使用GridLayout布局。区块划分差不多如图显示:

计算器样式分析

源码长这样子:

frame = new subJFrame("Calculator");
contentPane = frame.getContentPane();
// set the result panel
pan1 = new JPanel();
pan1.setLayout(new BorderLayout());
resultText.setHorizontalAlignment(JTextField.CENTER);// 设置文字居中
resultText.setFont(new Font( "",Font.BOLD,20));// 设置文字大小
pan1.add(resultText, BorderLayout.WEST);// 文本框靠左
pan1.add(clear, BorderLayout.EAST);// 清除按钮靠右
pan1.setPreferredSize(new Dimension(0,60));// 设置显示框大小
// set the input panel
pan2 = new JPanel();
pan2.setLayout(new GridLayout(4,7,10,10));
fillComponent(pan2);
// add the elems to the Frame
contentPane.setLayout(new BorderLayout());
contentPane.add(pan1, BorderLayout.NORTH);
contentPane.add(pan2, BorderLayout.CENTER);
frame.setResizable(false);// cannot scale the window
frame.setLocation(300,200);// where it come in
frame.setSize(700, 400);
frame.setVisible(true);

变量定义都设为全局了,所以这里看上去像是弱语言的语法。

对于 subJFrame("Calculator")这个方法,我们在Swing教程里说过,不过鉴于你们不会去看,我还是在下面写出来吧。

class subJFrame extends JFrame{
    public subJFrame(){}
    public subJFrame(String title){
        super(title);
    }
    protected void frameInit(){
        super.frameInit();
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }
}

大概是这样子。错了看编译器报什么错误吧。也可以留言通知我,实在不行。

添加按钮

那么我们怎么定义按钮呢,我们使用JButton数组来实现,搭配String数组来显示按钮文字。代码如下:

final String str[] = {"7","8","9","/","√","cos","x^2+2x+1","4","5","6","*",
    "x^2","tan","x^2+y^2","1","2","3","-","1/x","x^3","x^3+y^2",".",
    "0","=","+","sin","%","x+x*y"};
JButton buttons[] = new JButton[str.length];

  然后呢,我们需要把这些按钮都加入到Container中去,需要一个小循环来添加。如下:

private void fillComponent(Container c) {
    for (int i = 0; i < str.length; i++) {
        buttons[i] = new JButton(str[i]);
        c.add(buttons[i]);
    }
}

通过调用该方法来添加按钮,并且在实例化buttons的时候,也把字符串数组str也加入进去,于是按钮就有相应的标码了。顺序是从左到右,从上到下加入。

添加监听

  那么,我们组件那些弄好了,就应该添加监听事件了,我们在主类上写implements ActionListener,然后为buttons和clear按钮添加点击按钮事件监听器,如下面所示,需要小循环:

for (JButton button : buttons) {
    button.addActionListener(this);
}
clear.addActionListener(this);

这里说明一下这个循环,估计你们没用过这样的形式的,这意思是定义一个JButton的button来取遍buttons里面的元素,然后为每个button添加监听事件。

重载actionPerformed

  我们添加完监听事件后,那么就需要作出响应,需要重载actionPerformed方法,如下复制就好了:

@Override
public void actionPerformed(ActionEvent e) {
    String label = e.getActionCommand();
    if ("0123456789.+-*/".contains(label)) {
        dealNumber(label);
        comd += label;
    }else if (label.equals(clear.getActionCommand())) {
        clearText();
    }else {
        dealOperator(label);
    }
}

  这里,我们分为三个情况,一个是点击 数字键 以及 小数点 时,我们调用dealNumber(label)方法,二是点击 clear按钮 时,调用clearText()方法,最后点击 其他按钮 时,我们调用dealOperator(label)。方法功能呢,说实话我不想解释了,自己调用谷歌翻译吧,不行就百度。

处理数字按钮

  我们处理数字按钮以及小数点时,需要显示到显示框上,直接上代码吧,懒得说了

private void dealNumber(String label) {
    if (firstDigit) {
        resultText.setText(label);
    } else if ((label.equals("."))) {
        resultText.setText(resultText.getText() + ".");
    } else if (!label.equals(".")) {
        resultText.setText(resultText.getText() + label);
    }
    firstDigit = false;
}

我们使用了firstDigit变量来表示是否是我们输入的第一个数字

处理清除

  当我们点击C按钮时,需要清除所有东西,至为初始阶段,懒得说。

private void clearText() {
    resultText.setText("0");
    firstDigit = true;
    operator = "=";
    resultNum = 0.0;
    comd = "";
}

处理运算符

  最具影响力的、最具难度力的区域在这里呢,以上都是打打闹闹,我们需要处理剩下的所有运算符,以此来实现加减乘除以及其他运算。所以难度也就在这里。不说了直接打码。

private void dealOperator(String label) {
    switch (operator) {
        case "√":
            resultNum = Math.sqrt(resultNum);
            break;
        case "x^2":
            resultNum *= resultNum;
            break;
        case "1/x":
            if (resultNum == 0.0) {
                operateValidFlag = false;
                resultText.setText("There is no reciprocal of zero");
            } else {
                resultNum = 1 / resultNum;
            }
            break;
        case "sin":
            resultNum = Math.sin(Math.PI * resultNum / 180);
            break;
        case "cos":
            resultNum = Math.cos(Math.PI * resultNum / 180);
            break;
        case "tan":
            resultNum = Math.tan(Math.PI * resultNum / 180);
            break;
        case "x^3":
            resultNum = Math.pow(resultNum, 3);
            break;
        case "%":
            resultNum %= getNumberFromText();
            break;
        case "x^2+2x+1":
            resultNum = Math.pow(resultNum, 2) + 2 * resultNum + 1;
            break;
        case "x^2+y^2":
            resultNum = Math.pow(resultNum, 2) + Math.pow(getNumberFromText(), 2);
            break;
        case "x^3+y^2":
            resultNum = Math.pow(resultNum, 3) + Math.pow(getNumberFromText(), 2);
            break;
        case "x+x*y":
            resultNum += resultNum * getNumberFromText();
            break;
        case "=":
            if (!comd.isEmpty()) {
                resultNum = prase(comd);
                comd = "";
            }
            else
                resultNum = getNumberFromText();
            break;
        default:
    }
    if (operateValidFlag) {
        long t1;
        double t2;
        t1 = (long) resultNum;
        t2 = resultNum - t1;
        if (t2 == 0)
            resultText.setText(String.valueOf(t1));
        else
            resultText.setText(String.valueOf(resultNum));
    }
    operator = label;
    firstDigit = true;
    operateValidFlag = true;
}

  我们通过匹配字符串来识别是哪一个运算符,然后运算。这里需要注意的是,我在计算 加减乘除 时候,我特殊处理了,我通过String comd来存储我们需要的四则运算,然后调用函数处理这个四则运算。方便我们实现运算顺序问题(例如:2+3*4)。

处理四则运算

  上面我们说道,运用comd变量处理四则运算,所以我们用这个变量当作参数传入方法prase(String content)中,借此来得出四则运算的答案,该方法运用递归的思想,所以有些生涩难懂,不过从简单的comd上手,跟着方法思路走就可以了解到他的精髓。下面贴出代码:

private static double prase(String content){
    // Add
    int index = content.indexOf("+");
    if (index != -1)
        return prase(content.substring(0, index)) + prase(content.substring(index + 1));
    // subtract
    index = content.lastIndexOf("-");
    if (index != -1)
        return prase(content.substring(0, index)) - prase(content.substring(index + 1));
    // multiply
    index = content.indexOf("*");
    if (index != -1)
        return prase(content.substring(0, index)) * prase(content.substring(index + 1));
    // divide
    index = content.lastIndexOf("/");
    if (index != -1)
        return prase(content.substring(0, index)) / prase(content.substring(index + 1));
    return Double.parseDouble(content);
}

处理右值

  在观察了处理运算符后,是不是发现还有一个方法没见过呢,那就是getNumberFromText()这个方法,这个方法可以称作获取右值,即得到第二个数。事实上,这是个从文本中获取数字的方法。直接上马:

private double getNumberFromText() {
    double result = 0;
    try {
        result = Double.valueOf(resultText.getText());
    } catch (NumberFormatException e) {
    }
    return result;
}

差不多了

  写到这里就差不多结束了,这个程序可以说是目前写的最多行的程序,一共200多行,所以得花费一定时间,码字也不容易,希望屏幕前的朋友可以留个言啥的,沙发给你们,空调也准备好。

实验效果

  实验效果的话,只要不是非正常输入,一般都是可以得出正确结果的,若果说你硬是要搞我的话,那么我也没办法,你电脑出问题了可别怪我。所以,不要挑战程序的底线,虽然我这样设计出来的计算器BUG比较多,但是正常使用的话,应该是没啥大问题。不行的话,就点清零按钮,一切都好说。


这里说明一下我参考的资料:

小金子博客(四则运算)

程序猿style(框架)


爱狂笑的孩子运气不会差