小白瞎搞系列 1:
Introduction :
今天上JAVA课遇到了一个很蠢的作业,为什么蠢呢,其实我对JAVA不算很熟,关键还是,老师让我们用GUI写界面.....
没错,你没听错。都什么时间了!? 都2024.5.13 晚上 22:18分了,还在写GUI。好吧,不狡辩了,就是不想写。
那为什么笔者要发呢, 夜深了发牢骚
作业是做一个Calculator(demo),说到demo,笔者顺便预告一下,笔者正在谋划一个大项目--从零实现操作系统demo版本
其实也还好了,有参考书,而且不光笔者在做,MIT,Tsinghua都在做,今天OS课上,老师还让我们做了HIT的OS一小节
确实深深的被OS吸引住了,虽然我主要major in AI,但是很好玩,以至于我论文都没看,代码也没跑
关于星期四要组会但我一篇论文都没看,代码没有跑,纯在瞎搞并且极度后悔的我
Code :
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;public class Experiment4_2_22 extends JFrame implements ActionListener {private JTextField outputField;private StringBuilder stringBuffer = new StringBuilder();JPanel jPanel = new JPanel();Experiment4_2_22() {setTitle("Calculate");setSize(500, 500);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);setLocationRelativeTo(null);setLayout(new BorderLayout());outputField = new JTextField();outputField.setHorizontalAlignment(JTextField.CENTER);outputField.setEditable(false);add(outputField, BorderLayout.NORTH);jPanel.setLayout(new GridLayout(4, 4));String[] buttons = {"7", "8", "9", "/","4", "5", "6", "*","1", "2", "3", "+","0", ".", "=", "-"};for (String button : buttons) {JButton jButton = new JButton(button);jButton.addActionListener(this);jPanel.add(jButton);}add(jPanel);}@Overridepublic void actionPerformed(ActionEvent e) {String command = e.getActionCommand();if (command.equals("=")) {try {//用eval作为处理函数,减少冗杂double result = eval(stringBuffer.toString());outputField.setText(String.valueOf(result));stringBuffer.setLength(0);stringBuffer.append(result);} catch (ArithmeticException ex) {outputField.setText("Error");stringBuffer.setLength(0);}} else {stringBuffer.append(command);outputField.setText(stringBuffer.toString());}}private double eval(String expression) {// 如果表达式为空或长度为0,则返回0if (expression == null || expression.length() == 0) {return 0;}double res = 0;String[] tmp;// 根据运算符分割表达式并执行相应的计算if (expression.contains("+")) {tmp = expression.split("\\+");double n1 = Double.parseDouble(tmp[0]);double n2 = Double.parseDouble(tmp[1]);res = n1 + n2;} else if (expression.contains("-")) {tmp = expression.split("-");double n1 = Double.parseDouble(tmp[0]);double n2 = Double.parseDouble(tmp[1]);res = n1 - n2;} else if (expression.contains("*")) {tmp = expression.split("\\*");double n1 = Double.parseDouble(tmp[0]);double n2 = Double.parseDouble(tmp[1]);res = n1 * n2;} else if (expression.contains("/")) {tmp = expression.split("/");double n1 = Double.parseDouble(tmp[0]);double n2 = Double.parseDouble(tmp[1]);// 检查除数是否为0if (n2 != 0) {res = n1 / n2;} else {// 如果除数为0,返回0或者抛出异常,这里返回0res = 0;}} else {// 如果表达式中没有运算符,则直接将表达式解析为双精度浮点数res = Double.parseDouble(expression);}return res;}public static void main(String[] args) {SwingUtilities.invokeLater(() -> {Experiment4_2_22 e = new Experiment4_2_22();e.setVisible(true);});}
}
出于保险,读者还是解释一下把,防止你的语言基础不熟
JTextField outputField;
首先这个就是一个文本框, 叫JTextField
可以看到在source 里面他是一个swing的框架,说了跟没说一样
这里有几个比较重要的函数:第一个是setHorizontalAlignment,可以很明显的知道里面有很多方位词,所以肯定是用来判断方位的
第二个是setEditable,看不懂没关系,反正设为false就是不可修改的
接下来,是add这个函数
这个函数很清晰,意思就是在哪个component add‘,约束条件是哪个constraint
好啦,我铺垫了这么多基础知识,你应该能看懂一点我之前的代码啦。 加油!
接下来这个 JPanel的东西是用来布局的,注意他跟JFrame的布局是有区别的。JFrame是整体的,JPanel是用来把容器连在一起的,就例如,JButton要add在JPanel上。
JPanel jPanel = new JPanel();
(#`O′),别困了,给你个小任务
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
查查这两行代码作用于谁?代码是什么意思?
再查查
new GridLayout()
new BorderLayout()
是什么意思?
好啦,你查完了吧,我们继续吧。
我们看到这一段。
我们说说处理事件的逻辑,我们首先用getActionCommand()去得到动作对象的字符串,什么东西?
LLM讲的很好。我这里顺便也问了getSource()与之的区别,getSource()是什么?谷歌吧。 _
String command = e.getActionCommand();
if (command.equals("=")) {try {//用eval作为处理函数,减少冗杂double result = eval(stringBuffer.toString());outputField.setText(String.valueOf(result));stringBuffer.setLength(0);stringBuffer.append(result);} catch (ArithmeticException ex) {outputField.setText("Error");stringBuffer.setLength(0);}
} else {stringBuffer.append(command);outputField.setText(stringBuffer.toString());
}
这里我们是要做一个计算器,那肯定要用stringBuffer去做,因为他是个动态字符串,JAVA不像Cpp,他的string是个常值,所以我们这里得用stringBuffer
然后在去转string去输出到outputField。假如没遇到"="之前,那就一直加,显示一直打出来,遇到了就进行处理,每次处理完,就设置stringBuffer长度为0,即是设置为空值的意思,然后具体怎么实现呢,请看eval函数,很简单的,我就不讲解了。
private double eval(String expression) {// 如果表达式为空或长度为0,则返回0if (expression == null || expression.length() == 0) {return 0;}double res = 0;String[] tmp;// 根据运算符分割表达式并执行相应的计算if (expression.contains("+")) {tmp = expression.split("\\+");double n1 = Double.parseDouble(tmp[0]);double n2 = Double.parseDouble(tmp[1]);res = n1 + n2;} else if (expression.contains("-")) {tmp = expression.split("-");double n1 = Double.parseDouble(tmp[0]);double n2 = Double.parseDouble(tmp[1]);res = n1 - n2;} else if (expression.contains("*")) {tmp = expression.split("\\*");double n1 = Double.parseDouble(tmp[0]);double n2 = Double.parseDouble(tmp[1]);res = n1 * n2;} else if (expression.contains("/")) {tmp = expression.split("/");double n1 = Double.parseDouble(tmp[0]);double n2 = Double.parseDouble(tmp[1]);// 检查除数是否为0if (n2 != 0) {res = n1 / n2;} else {// 如果除数为0,返回0或者抛出异常,这里返回0res = 0;}} else {// 如果表达式中没有运算符,则直接将表达式解析为双精度浮点数res = Double.parseDouble(expression);}return res;
}
对了,最后说一点,
SwingUtilities.invokeLater(() -> {Experiment4_2_22 e = new Experiment4_2_22();e.setVisible(true);
});
因为我们进行GUI编程的时候,很多时候会多线程操作,会有一点安全问题,具体请谷歌,蛮复杂的。
所以我们得用SwingUtilities.invokeLater()去保证安全。
invokeLater(接受一个对象),一旦执行,这个任务会被放入事件队列中,等待事件分发线程去执行。这样就确保了在正确的线程上执行 GUI 相关的操作,避免了多线程导致的并发访问问题。