package shixi;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
public class Calculator implements ActionListener {
private JFrame f;
private JPanel p;
//定义两个文本框用来显示算式和结果
private JTextField show, showexp;
//定义数字按钮
private JButton zero, one, two, three, four, five, six, seven, eight, nine;
//定义控制按钮
private JButton H, C, DEL, point, LK, RK;
//定义运算符号按钮
private JButton div, mul, sum, minus, eql;
//定义算式的字符串表示
private String input, output;
public static void main(String[] args) {
Calculator c = new Calculator();
c.display();
}
//在构造函数中 初始化控件和变量
Calculator() {
f = new JFrame("Calculator By Lny");
Image image = new ImageIcon("C:\\Users\\李宁宇\\Pictures\\Saved Pictures\\1.jpg").getImage(); //添加背景图片
p = new BackgroundPanel(image);
show = new JTextField("0");//创建单行文本控件
showexp = new JTextField();
zero = new JButton("0");//创建按钮
one = new JButton("1");
two = new JButton("2");
three = new JButton("3");
four = new JButton("4");
five = new JButton("5");
six = new JButton("6");
seven = new JButton("7");
eight = new JButton("8");
nine = new JButton("9");
H = new JButton("HIS");
C = new JButton("C");
DEL = new JButton("DEL");
sum = new JButton("+");
minus = new JButton("-");
mul = new JButton("*");
div = new JButton("/");
point = new JButton(".");
LK = new JButton("(");
RK = new JButton(")");
eql = new JButton("=");
input = output = "";//初始设置存储算式和结果的字符串为空串
}
//计算器界面设置
public void display() {
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置关闭就退出程序
//设置显示结果的单行文本框相关属性
show.setFont(new Font(Font.SERIF, Font.BOLD, 40));//设置字体样式
show.setBorder(BorderFactory.createEmptyBorder());//设置单行文本控件无边框
show.setHorizontalAlignment(SwingConstants.RIGHT);//设置文本靠右显示
show.setEnabled(false);//设置单行文本框不能点击
showexp.setFont(new Font(Font.SERIF, Font.BOLD, 16));//设置字体样式
showexp.setBorder(BorderFactory.createEmptyBorder());//设置单行文本控件无边框
showexp.setHorizontalAlignment(SwingConstants.RIGHT);//设置文本靠右显示
showexp.setEnabled(false);//设置文本框不能点击
H.setForeground(Color.red);//设置按钮字体颜色为蓝色
H.setFont(new Font(Font.SERIF, Font.BOLD, 16));//设置按钮字体样式
H.setContentAreaFilled(false);//设置按钮为透明效果
C.setForeground(Color.red);
C.setFont(new Font(Font.SERIF, Font.BOLD, 16));
C.setContentAreaFilled(false);
DEL.setForeground(Color.red);
DEL.setFont(new Font(Font.SERIF, Font.BOLD, 16));
DEL.setContentAreaFilled(false);
LK.setForeground(Color.red);//设置按钮字体颜色为蓝色
LK.setFont(new Font(Font.SERIF, Font.BOLD, 16));//设置按钮字体样式
LK.setContentAreaFilled(false);//设置按钮为透明效果
RK.setForeground(Color.red);//设置按钮字体颜色为蓝色
RK.setFont(new Font(Font.SERIF, Font.BOLD, 16));//设置按钮字体样式
RK.setContentAreaFilled(false);//设置按钮为透明效果
sum.setForeground(Color.BLUE);
sum.setFont(new Font(Font.SERIF, Font.BOLD, 16));
sum.setContentAreaFilled(false);
minus.setForeground(Color.BLUE);
minus.setFont(new Font(Font.SERIF, Font.BOLD, 16));
minus.setContentAreaFilled(false);
mul.setFont(new Font(Font.SERIF, Font.BOLD, 16));
mul.setForeground(Color.BLUE);
mul.setContentAreaFilled(false);
div.setForeground(Color.BLUE);
div.setFont(new Font(Font.SERIF, Font.BOLD, 16));
div.setContentAreaFilled(false);
point.setForeground(Color.BLUE);
point.setFont(new Font(Font.SERIF, Font.BOLD, 16));
point.setContentAreaFilled(false);
eql.setForeground(Color.red);
eql.setFont(new Font(Font.SERIF, Font.BOLD, 16));
eql.setContentAreaFilled(false);
zero.setForeground(Color.BLUE);
zero.setFont(new Font(Font.SERIF, Font.BOLD, 16));
zero.setContentAreaFilled(false);
one.setForeground(Color.BLUE);
one.setFont(new Font(Font.SERIF, Font.BOLD, 16));
one.setContentAreaFilled(false);
two.setForeground(Color.BLUE);
two.setFont(new Font(Font.SERIF, Font.BOLD, 16));
two.setContentAreaFilled(false);
three.setForeground(Color.BLUE);
three.setFont(new Font(Font.SERIF, Font.BOLD, 16));
three.setContentAreaFilled(false);
four.setForeground(Color.BLUE);
four.setFont(new Font(Font.SERIF, Font.BOLD, 16));
four.setContentAreaFilled(false);
five.setForeground(Color.BLUE);
five.setFont(new Font(Font.SERIF, Font.BOLD, 16));
five.setContentAreaFilled(false);
six.setForeground(Color.BLUE);
six.setFont(new Font(Font.SERIF, Font.BOLD, 16));
six.setContentAreaFilled(false);
seven.setForeground(Color.BLUE);
seven.setFont(new Font(Font.SERIF, Font.BOLD, 16));
seven.setContentAreaFilled(false);
eight.setForeground(Color.BLUE);
eight.setFont(new Font(Font.SERIF, Font.BOLD, 16));
eight.setContentAreaFilled(false);
nine.setForeground(Color.BLUE);
nine.setFont(new Font(Font.SERIF, Font.BOLD, 16));
nine.setContentAreaFilled(false);
//为按钮添加监听事件
H.addActionListener(this);
C.addActionListener(this);
DEL.addActionListener(this);
sum.addActionListener(this);
minus.addActionListener(this);
mul.addActionListener(this);
div.addActionListener(this);
point.addActionListener(this);
eql.addActionListener(this);
zero.addActionListener(this);
one.addActionListener(this);
two.addActionListener(this);
three.addActionListener(this);
four.addActionListener(this);
five.addActionListener(this);
six.addActionListener(this);
seven.addActionListener(this);
eight.addActionListener(this);
nine.addActionListener(this);
LK.addActionListener(this);
RK.addActionListener(this);
//GridBagLayout(网格包布局管理器)
GridBagLayout gblayout = new GridBagLayout();
//创建GridBagLayout布局管理器
p.setLayout(gblayout);
//使用GridBagLayout布局管理器
GridBagConstraints g = new GridBagConstraints();
g.fill = GridBagConstraints.BOTH;//设置当某个单元格未填满时填满整个空间
//fill
//指定组件填充网格的方式,可以是如下值:GridBagConstraints.NONE(默认值)、
// GridBagConstraints.HORIZONTAL(组件横向充满显示区域,但是不改变组件高度)、
// GridBagConstraints.VERTICAL(组件纵向充满显示区域,但是不改变组件宽度)
// GridBagConstraints.BOTH(组件横向、纵向充满其显示区域)。
g.weightx = 1.0;//设置窗口变大时缩放比例
g.weighty = 1.0;
//weightx 和 weighty
//用来指定在容器大小改变时,增加或减少的空间如何在组件间分配,默认值为 0,
// 即所有的组件将聚拢在容器的中心,多余的空间将放在容器边缘与网格单元之间。
// weightx 和 weighty 的取值一般在 0.0 与 1.0 之间,数值大表明组件所在的行或者列将获得更多的空间。
g.gridx = 0;//定位在第一行第一列
g.gridy = 0;
//gridx 和 gridy
//用来指定组件左上角在网格中的行和列。容器中最左边列的 gridx 为 0,最上边行的 gridy 为 0。
// 这两个变量的默认值是 GridBagConstraints.RELATIVE,表示对应的组件将放在前一个组件的右边或下面。
g.gridwidth = GridBagConstraints.REMAINDER;//填满整行
g.gridheight = 1;//占一行网格
gridwidth 和 gridheight
//用来指定组件显示区域所占的列数和行数,以网格单元而不是像素为单位,默认值为 1
g.insets = new Insets(5, 5, 0, 5);
//设置该组件与其它组件的距离
// insets指定组件显示区域的外部填充,即组件与其显示区域边缘之间的空间,默认组件没有外部填充。
gblayout.setConstraints(showexp, g);//设置文本控件位置
g.gridx = 0;
g.gridy = 1;//设置在第二行第一列
g.gridheight = 2;//占两行网格
g.insets = new Insets(0, 5, 5, 5);
gblayout.setConstraints(show, g);
g.gridwidth = 1;
g.gridheight = 1;//占一行网格且填满整行
g.insets = new Insets(5, 5, 5, 5);
g.gridy = 4;//第五行
g.gridx = 0;
gblayout.setConstraints(C, g);
g.gridx = 1;
gblayout.setConstraints(DEL, g);
g.gridx = 2;
gblayout.setConstraints(LK, g);
g.gridx = 3;
gblayout.setConstraints(RK, g);
g.gridy = 5;
g.gridx = 0;
gblayout.setConstraints(seven, g);
g.gridx = 1;
gblayout.setConstraints(eight, g);
g.gridx = 2;
gblayout.setConstraints(nine, g);
g.gridx = 3;
gblayout.setConstraints(div, g);
g.gridy = 6;
g.gridx = 0;
gblayout.setConstraints(four, g);
g.gridx = 1;
gblayout.setConstraints(five, g);
g.gridx = 2;
gblayout.setConstraints(six, g);
g.gridx = 3;
gblayout.setConstraints(mul, g);
g.gridy = 7;
g.gridx = 0;
gblayout.setConstraints(one, g);
g.gridx = 1;
gblayout.setConstraints(two, g);
g.gridx = 2;
gblayout.setConstraints(three, g);
g.gridx = 3;
gblayout.setConstraints(sum, g);
g.gridy = 8;
g.gridx = 0;
gblayout.setConstraints(point, g);
g.gridx = 1;
gblayout.setConstraints(zero, g);
g.gridx = 2;
gblayout.setConstraints(eql, g);
g.gridx = 3;
gblayout.setConstraints(minus, g);
p.add(showexp);
p.add(show);
p.add(H);
p.add(C);
p.add(DEL);
p.add(div);
p.add(seven);
p.add(eight);
p.add(nine);
p.add(mul);
p.add(four);
p.add(five);
p.add(six);
p.add(minus);
p.add(one);
p.add(two);
p.add(three);
p.add(sum);
p.add(zero);
p.add(point);
p.add(eql);
p.add(LK);
p.add(RK);
f.setContentPane(p);
f.setSize(450, 550); //设置窗口尺寸
f.setLocationRelativeTo(null);
f.setVisible(true); //设置窗口是否可见
}
//算式合法性
@Override
public void actionPerformed(ActionEvent e) {
output = "";
if ((e.getSource()) == C) {//清空算式
input = "0";
show.setText(input); //显示文本框内容
} else if ((e.getSource()) == DEL) {
//提取字符串开始到倒数第二个字符
input = input.substring(0, input.length() - 1);
if (input.length() == 0) input = "0";
show.setText(input);
} else if ((e.getSource()) == sum || (e.getSource()) == minus || (e.getSource()) == mul || (e.getSource()) == div) {
if (input.length() != 0 && (!isOperator(input.charAt(input.length() - 1))))//确认必须有数字才能输入运算符
input += e.getActionCommand(); //getActionCommand():返回于此动作相关的命令字符串
show.setText(input);
} else if ((e.getSource()) == point) {
int pos = input.lastIndexOf('.');//找到最后一个小数点的位置
if (pos >= 0)//前后两个小数点间不能都是数字,即不能2.33时又添加一个小数点变为2.33.
{
if (isDigit(input.charAt(input.length() - 1)) && !isDigitSring(input.substring(pos + 1)))
input += e.getActionCommand();
} else {//小数点前一个必须是数字
if (isDigit(input.charAt(input.length() - 1)))
input += e.getActionCommand();
}
show.setText(input);
} else if ((e.getSource()) == eql) {
input += '#';//算式末尾添加’#’
//从算式中拆分出数字
String[] nums = input.split("[^.0-9]"); //将字符串分割为子字符串,然后结果以字符串数组返回
//任何字符除了.、0-9
List<Double> numList = new ArrayList<>();
for (int i = 0; i < nums.length; i++) {//将每个数字串转化为Double类型
if (!"".equals(nums[i]))
numList.add(Double.parseDouble(nums[i]));
}
double out = getValueOfMid(input, numList);//利用中缀式求值
output = "" + out;//将求得的结果转为字符串
input = input.substring(0, input.length() - 1);//去除算式后的’#’
showexp.setText(input);//第一个单行文本框展示算式
show.setText(output);//第二个单行文本框显示结果
input = "";//存储算式的字符串清空
} else {
if (input == "0") input = "";
input += e.getActionCommand();
show.setText(input);
}
}
public static boolean isDigit(char ch)//判断一个字符是否为数字
{
return (ch >= '0' && ch <= '9');
}
public boolean isDigitSring(String s)//判断一个字符是否都为数字
{
for (int i = 0; i < s.length(); i++) {
if (!isDigit(s.charAt(i)))
return false;
}
return true;
}
public boolean isOperator(char c)//判断一个字符是否为运算符或’.’或括号
{
return (c == '+') || (c == '-') || (c == '*') || (c == '/') || (c == '.') || (c == '(');
}
public static int isp(char ch)//定义栈内运算符优先级,并将相应算符的优先级返回
{
switch (ch) {
case ')':
return 4;
case '*':
return 3;
case '/':
return 3;
case '+':
return 2;
case '-':
return 2;
case '(':
return 1;
case '#':
return 0;
}
return -1;
}
public static int icp(char ch)//定义栈外运算符优先级,并将相应算符的优先级返回
{
switch (ch) {
case ')':
return 1;
case '*':
return 3;
case '/':
return 3;
case '+':
return 2;
case '-':
return 2;
case '(':
return 4;
case '#':
return 0;
}
return 0;
}
public static double compute(double a, char ch, double b)//将取出的两个操作数与对应的算符进行计算并返回计算结果
{
switch (ch) {
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
case '/':
return a / b;
default:
break;
}
return 0;
}
//对输入的算式(中缀式)进行求值
public static double getValueOfMid(String input, List<Double> numList) {
Stack<Character> OP = new Stack<>();//定义算符栈
Stack<Double> OPN = new Stack<>();//定义操作数栈
double output = 0;//最终结果
double a, b;//定义两个操作数
char sym;//定义运算符
OP.push('#');
int i = 0, j = 0;
while (input.charAt(i) != '#' || OP.peek() != '#') //peek():返回栈顶元素但不移除它
{
if (isDigit(input.charAt(i)))//数字直接入OPN栈
{//此字符是数字
while (isDigit(input.charAt(i)) || input.charAt(i) == '.')//此字符是数字或者此字符是·
{
i++;//跳过此字符
if (i == input.length())
break;
}
i--;
OPN.push(numList.get(j)); //操作数入栈
j++;
} else {//扫描到是操作符
sym = OP.peek();
int m = isp(sym); //m为栈内运算符
int n = icp(input.charAt(i));//n为栈外元素
if (m < n || n == '(') OP.push(input.charAt(i));// //这个运算符比OP栈顶运算符的优先级高,则入栈;
else if (m > n || m == n)//这个运算符比OP栈顶运算符优先级低
{
sym = OP.peek();
OP.pop();//取出栈内的运算符
if (sym != '(' && (m == n || m > n)) {
b = OPN.peek();//从操作数栈取出一个操作数
OPN.pop();
if (!OPN.empty() && OP.peek() != '(')//当操作数栈不为空且不为’(’时继续取出栈中的数进行运算
{
a = OPN.peek();
OPN.pop();
OPN.push(compute(a, sym, b));
continue;
} else//处理负数
{
switch (sym)//实现一元运算符的运算
{
case '+':
OPN.push(b);
break;
case '-':
OPN.push(-b);
break;
}
continue;
}
}
}
}
i++;
}
output = OPN.peek();
return output;
}
}
package shixi;
//BackgroundPanel类中的代码
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.JPanel;
//继承Jpanel类创建一个可以添加背景的面板类
class BackgroundPanel extends JPanel{
private Image image = null;
public BackgroundPanel(Image image) {
this.image = image;
}
// 固定背景图片,允许这个JPanel可以在图片上添加其他组件
protected void paintComponent(Graphics g) {
g.drawImage(image, 0, 0, this.getWidth(), this.getHeight(), this);
}
}
项目一源代码
最新推荐文章于 2023-06-08 14:33:41 发布