第二次作业
[实验目的]
1、掌握软件开发的基本流程
2、掌握常用的软件开发方式和工具
[实验内容]
1、使用java语言完成相关程序设计要求
2、设计包含登录界面的计算器
3、使用Swing组件及java事件处理机制完成一个简单计算器的图形界面及实现简单的计算功能
4、连接数据库,用来储存用户的历史计算记录
[实验要求]
完成软件的UI设计,使用Visio设计软件中所涉及的所有流程图
[实验环境]
硬件环境: Windos11系统
软件环境:eclipse
[流程图]
1、登录界面

2、计算器运行流程图

[登录界面]
1、登录界面

2、登录成功

3、登录失败

4、代码
import java.awt.*; import javax.swing.*; import javax.swing.JFrame;//使窗体位于屏幕中间 public class Example10_2 { public static void main(String[] args) { JFrame window1=new JFrame();//java提供的JFrame类的实例是一个底层容器,即通常说的窗口,其他组件必须被添加到容器中,这里是创建了一个标题为“第一个窗口”的窗口 window1.setTitle("用户登录界面"); window1.setBounds(800,200,330,380); window1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//用来设置窗口右上角的图标关闭后,程序会如何处理,这里的是做出”结束窗口所在的应用程序“ FlowLayout flow=new FlowLayout();//流式布局 window1.setLayout(flow);//设置用户界面上的屏幕组件的格式布局,默认为流式布局 //按钮 JButton anniu =new JButton("登录"); JButton guanbi =new JButton("关闭"); //标签 JLabel hauny=new JLabel(" "); JLabel xuehao=new JLabel("用户名:"); JLabel mima=new JLabel("密码:"); //输入框 JTextField xuehaowenjian=new JFormattedTextField(); JPasswordField mimawenjian=new JPasswordField(); //设置组件对象的属性 Dimension daxiao = new Dimension(250,30); xuehaowenjian.setPreferredSize(daxiao); mimawenjian.setPreferredSize(daxiao); //添加组件 window1.add(hauny); window1.add(xuehao); window1.add(xuehaowenjian); window1.add(mima); window1.add(mimawenjian); window1.add(anniu); window1.add(guanbi); window1.setVisible(true);//窗口是否可见,true为是 } }
[计算器]
1、计算器计算界面


2、代码
import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Arrays; import java.util.Objects; import java.util.Stack; import javax.swing.*; //Calculator类,继承JFrame框架,实现事件监听器接口 public class Calculator extends JFrame implements ActionListener { private final String[] KEYS = {"7", "8", "9", "AC", "4", "5", "6", "-", "1", "2", "3", "+", "0", "e", "pi", "/", "sqrt", "%", "x*x", "*", "(", ")", ".", "="}; private JButton keys[] = new JButton[KEYS.length]; private JTextArea resultText = new JTextArea("0.0"); // 文本域组件TextArea可容纳多行文本;文本框内容初始值设为0.0 private JTextArea History = new JTextArea(); // 历史记录文本框初始值设为空 private JPanel jp2 = new JPanel(); private JScrollPane gdt1 = new JScrollPane(resultText); //给输入显示屏文本域新建一个垂直滚动滑条 private JScrollPane gdt2 = new JScrollPane(History); //给历史记录文本域新建一个垂直滚动滑条 private JLabel label = new JLabel("历史记录"); private String input = ""; //计算文本框输入的中缀表达式 // 构造方法 public Calculator() { super("Caculator");//“超”关键字,表示调用父类的构造函数, resultText.setBounds(20, 18, 255, 115); // 设置文本框大小 resultText.setAlignmentX(RIGHT_ALIGNMENT); // 文本框内容右对齐 resultText.setEditable(false); // 文本框不允许修改结果 resultText.setFont(new Font("monospaced", Font.PLAIN, 18)); //设置结果文本框输入文字的字体、类型、大小 History.setFont(new Font("monospaced", Font.PLAIN, 18)); //设置历史记录文本框输入文字的字体、类型、大小 History.setBounds(290, 40, 250, 370); // 设置文本框大小 History.setAlignmentX(LEFT_ALIGNMENT); // 文本框内容右对齐 History.setEditable(false); // 文本框不允许修改结果 label.setBounds(300, 15, 100, 20); //设置标签位置及大小 jp2.setBounds(290, 40, 250, 370); //设置面板窗口位置及大小 jp2.setLayout(new GridLayout()); JPanel jp1 = new JPanel(); jp1.setBounds(20, 18, 255, 115); //设置面板窗口位置及大小 jp1.setLayout(new GridLayout()); resultText.setLineWrap(true); // 激活自动换行功能 resultText.setWrapStyleWord(true); // 激活断行不断字功能 resultText.setSelectedTextColor(Color.RED); History.setLineWrap(true); //自动换行 History.setWrapStyleWord(true); History.setSelectedTextColor(Color.blue); gdt1.setViewportView(resultText); //使滚动条显示出来 gdt2.setViewportView(History); gdt1.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); //设置让垂直滚动条一直显示 gdt2.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); //设置让垂直滚动条一直显示 gdt2.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); //设置让水平滚动条一直显示 jp1.add(gdt1); //将滚动条添加入面板窗口中 jp2.add(gdt2); this.add(jp1); //将面板添加到总窗体中 this.add(jp2); //将面板添加到总窗体中 this.setLayout(null); this.add(label); // 新建“历史记录”标签 // 放置按钮 x,y为按钮的横纵坐标 int x = 20, y = 150; for (int i = 0; i < KEYS.length; i++) { keys[i] = new JButton(); keys[i].setText(KEYS[i]); keys[i].setBounds(x, y, 60, 40); if (x < 215) { x += 65; } else { x = 20; y += 45; } this.add(keys[i]); } for (int i = 0; i < KEYS.length; i++) // 每个按钮都注册事件监听器 { keys[i].addActionListener(this); } this.setResizable(false); this.setBounds(500, 200, 567, 480); this.setDefaultCloseOperation(EXIT_ON_CLOSE); this.setVisible(true); } // 事件处理 public void actionPerformed(ActionEvent e) { String label = e.getActionCommand(); //获得事件源的标签 if (Objects.equals(label, "AC")) //清空按钮,消除显示屏文本框前面所有的输入和结果 { input = ""; resultText.setText("0.0"); //更新文本域的显示,显示初始值; } else if (Objects.equals(label, "sqrt")) { String n; if(input.isEmpty()) n="error!"; //加判断,先输入数字再输入开方符号才是合法的 else n = String.valueOf(kfys(input)); resultText.setText("sqrt" + "(" + input + ")" + "=" + n); //使运算表达式显示在输入界面 History.setText(History.getText() + resultText.getText() + "\n"); //获取输入界面的运算表达式并使其显示在历史记录文本框 input = n; } else if (Objects.equals(label, "x*x")) { String m; if(input.isEmpty()) m="error!"; else m = String.valueOf(pfys(input)); resultText.setText(input + "^2" + "=" + m); History.setText(History.getText() + resultText.getText() + "\n"); input = m; } else if (Objects.equals(label, "=")) { if (input.isEmpty()) return; String[] s = houzhui(input); //将中缀表达式转换为后缀表达式 double result = Result(s); //计算后缀表达式得出最终算式结果 resultText.setText(input + "=" + result); History.setText(History.getText() + resultText.getText() + "\n"); } else { if (Objects.equals(label, "e")) { String m = String.valueOf(2.71828); //将e的值以字符串的形式传给m label = m; } else if (Objects.equals(label, "pi")) { String m = String.valueOf(3.14159); label = m; } input = input + label; resultText.setText(input); } } //将中缀表达式转换为后缀表达式 private String[] houzhui(String infix) { //infix 中缀 String s = "";// 用于承接多位数的字符串 Stack<String> opStack = new Stack<String>(); // 操作符静态栈,对用户输入的操作符进行处理,用于存储运算符 Stack<String> postQueue = new Stack<String>(); // 后缀表达式,为了将多位数存储为独立的字符串 System.out.println("中缀:" + infix); for (int i = 0; i < infix.length(); i++) // 遍历中缀表达式 // indexof函数,返回字串首次出现的位置;charAt函数返回index位置处的字符; { if ("1234567890.".indexOf(infix.charAt(i)) >= 0) { // 遇到数字字符直接入队 //判断并记录多位操作数,比如,中缀表达式:234+4*2,我们扫描这个字符串的时候,s的作用相当于用来存储长度为3个字符的操作数:234 s = "";// 作为承接字符,每次开始时都要清空 for (; i < infix.length() && "0123456789.".indexOf(infix.charAt(i)) >= 0; i++) { s = s + infix.charAt(i); } i--; //避免跳过对非数字字符的处理 postQueue.push(s); // 数字字符直接加入后缀表达式 } else if ("(".indexOf(infix.charAt(i)) >= 0) { // 遇到左括号 opStack.push(String.valueOf(infix.charAt(i))); // 左括号入栈 } else if (")".indexOf(infix.charAt(i)) >= 0) { // 遇到右括号 while (!opStack.peek().equals("(")) { // 栈顶元素循环出栈,直到遇到左括号为止 postQueue.push(opStack.pop()); } opStack.pop(); //删除左括号 } else if ("*%/+-".indexOf(infix.charAt(i)) >= 0) // 遇到运算符 { if (opStack.empty() || "(".contains(opStack.peek())) { // 若栈为空或栈顶元素为左括号则直接入栈 opStack.push(String.valueOf(infix.charAt(i))); } else { // 当栈顶元素为高优先级或同级运算符时,让栈顶元素出栈进入后缀表达式后,直到符合规则后,当前运算符再入栈 boolean rule = ("*%/+-".contains(opStack.peek()) &&"+-".indexOf(infix.charAt(i)) >= 0) || ("*%/".contains(opStack.peek()) && "*%/".indexOf(infix.charAt(i)) >= 0); while (!opStack.empty() &&rule) { postQueue.push(opStack.peek()); //peek()方法:返回栈顶的元素但不移除它 opStack.pop(); } opStack.push(String.valueOf(infix.charAt(i))); // 当前元素入栈 } } } while (!opStack.empty()) {// 遍历结束后将栈中剩余元素依次出栈进入后缀表达式 postQueue.push(opStack.pop()); } //将后缀表达式栈转换为字符串数组格式 String[] suffix = new String[postQueue.size()]; for (int i = postQueue.size() - 1; i >= 0; i--) { suffix[i] = postQueue.pop(); } System.out.println("后缀:" + Arrays.toString(suffix.clone())); return suffix; } //牛顿迭代法计算开方 public double kfys(double n) { if(n < 0) { return Double.NaN; }else { double err = 1e-15; double root = n; while(Math.abs(n - root * root) > err) { root = (n/root + root) / 2; } return root; } } //平方运算方法 public double pfys(String str) { double a = Double.parseDouble(str); return Math.pow(a, 2); } // 计算后缀表达式,并返回最终结果 public double Result(String[] suffix) { //suffix 后缀 Stack<String> Result = new Stack<>();// 顺序存储的栈,数据类型为字符串 int i; for (i = 0; i < suffix.length; i++) { if ("1234567890.".indexOf(suffix[i].charAt(0)) >= 0) { //遇到数字,直接入栈 Result.push(suffix[i]); } else { // 遇到运算符字符,将栈顶两个元素出栈计算并将结果返回栈顶 double x, y, n = 0; x = Double.parseDouble(Result.pop()); // 顺序出栈两个数字字符串,并转换为double类型 y = Double.parseDouble(Result.pop()); switch (suffix[i]) { case "*": n = y * x; break; case "/": if (x == 0) return 000000; else n = y / x; break; case "%": if (x == 0) return 000000; else n = y % x; break; case "-": n = y - x; break; case "+": n = y + x; break; } Result.push(String.valueOf(n)); // 将运算结果重新入栈 } } System.out.println("return:" + Result.peek()); return Double.parseDouble(Result.peek()); // 返回最终结果 } // 主函数 public static void main(String[] args) { Calculator a = new Calculator(); } }
[连接数据库,实现保存历史计算记录功能]
import java.sql.*; public class CalculatorWithDatabase { static final String JDBC_DRIVER = "org.sqlite.JDBC"; static final String DB_URL = "jdbc:sqlite:calculator.db"; // 数据库文件名为 calculator.db public static void main(String[] args) { Connection conn = null; Statement stmt = null;
try { // 注册 JDBC 驱动 Class.forName(JDBC_DRIVER); // 打开一个连接 System.out.println("连接数据库..."); conn = DriverManager.getConnection(DB_URL);
// 创建表格(如果不存在) System.out.println("创建表格..."); stmt = conn.createStatement(); String sql = "CREATE TABLE IF NOT EXISTS calculation_history " + "(id INTEGER PRIMARY KEY AUTOINCREMENT, expression TEXT, result DOUBLE)"; stmt.executeUpdate(sql); // 进行计算并保存历史记录 double result = performCalculation(5, "+", 3); saveCalculation(conn, "5 + 3", result); // 检索并显示历史记录 System.out.println("历史记录:"); displayHistory(conn); } catch (Exception e) { e.printStackTrace(); } finally { try { if (stmt != null) stmt.close(); if (conn != null) conn.close(); } catch (SQLException se) { se.printStackTrace(); } } } private static double performCalculation(double operand1, String operator, double operand2) { switch (operator) { case "+": return operand1 + operand2; case "-": return operand1 - operand2; case "*": return operand1 * operand2; case "/": return operand1 / operand2; default: throw new IllegalArgumentException("Unsupported operator: " + operator); } } private static void saveCalculation(Connection conn, String expression, double result) throws SQLException { String sql = "INSERT INTO calculation_history (expression, result) VALUES (?, ?)"; try (PreparedStatement pstmt = conn.prepareStatement(sql)) { pstmt.setString(1, expression); pstmt.setDouble(2, result); pstmt.executeUpdate(); } } private static void displayHistory(Connection conn) throws SQLException { String sql = "SELECT * FROM calculation_history"; try (Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql)) { while (rs.next()) { int id = rs.getInt("id"); String expression = rs.getString("expression"); double result = rs.getDouble("result"); System.out.println(id + ": " + expression + " = " + result); } } } }

浙公网安备 33010602011771号