小白瞎搞系列 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);
}
@Override
public 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,则返回0
if (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]);
// 检查除数是否为0
if (n2 != 0) {
res = n1 / n2;
} else {
// 如果除数为0,返回0或者抛出异常,这里返回0
res = 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,则返回0
if (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]);
// 检查除数是否为0
if (n2 != 0) {
res = n1 / n2;
} else {
// 如果除数为0,返回0或者抛出异常,这里返回0
res = 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 相关的操作,避免了多线程导致的并发访问问题。