第二次作业
一、实验目的
1.掌握软件开发的基本流程。
2.掌握软件设计和开发的基本工具。
3.理解集成软件开发环境在软件开发过程中的作用。
4.模拟计算器的功能,对数据进行加减乘除以及开方运算并可保存历史计算记录。
二、实验要求
1.完成计算器软件的UI设计、使用Visio设计计算器软件中所涉及的流程图。
2.选择合适的集成开发环境和工具完成计算器软件的开发和功能测试。
3.自己设计登录页面并和简易计算器连接并将数据保存在数据库中。
三、实验环境
1.操作系统:Windows11
2.开发测试工具:IDEA编写登录界面以及计算器相关代码,连接MySQL数据库存储计算记录。
3.流程图:visio
四、基本功能描述
一、相关功能
简易计算器包括基本的四则运算(加、减、乘、除)及开方运算并可存储历史计算数据功能。
五、软件设计
**********************************************用户登录界面************************************************88
package User; public class Login { String id; String password; LoginDemo loginDemo; boolean loginSuccess = false; public void setLoginDemo(LoginDemo loginDemo) { this.loginDemo = loginDemo; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public boolean isLoginSuccess() { return loginSuccess; } public void setLoginSuccess(boolean loginSuccess) { this.loginSuccess = loginSuccess; } }
package User; import javax.swing.*; import javax.swing.plaf.basic.BasicButtonUI; import javax.swing.plaf.basic.BasicPanelUI; import java.awt.*; import java.sql.SQLException; public class LoginDemo extends JFrame { public LoginDemo() { super("计算器登录"); //获取显示屏的大小 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); int sw = screenSize.width; int sh = screenSize.height; //设置窗口的位置 int width = 300; int height = 340; this.setBounds((sw - width) / 2, (sh - height) / 2, width, height); // 盒子模块 Box ubox = Box.createHorizontalBox(); Box pbox = Box.createHorizontalBox(); Box vbox = Box.createVerticalBox(); JLabel uLabel = new JLabel(" I d :"); JTextField uField = new JTextField(); JLabel pLabel = new JLabel("密 码:"); JPasswordField pFd = new JPasswordField(); pFd.setColumns(16); pFd.setEchoChar('●'); JButton button1 = new JButton("登录"); button1.setToolTipText("登录"); JButton button2 = new JButton("重置"); button2.setToolTipText("重置"); JMenu Menubutton3 = new JMenu("注册账号"); Menubutton3.setToolTipText("注册账号"); button1.setBounds((this.getWidth() - 120 - 180) / 2, 250, 100, 30); button1.setCursor(new Cursor(Cursor.HAND_CURSOR)); button2.setBounds((this.getWidth() - 120 + 180) / 2, 250, 100, 30); Menubutton3.setUI(new BasicButtonUI()); Menubutton3.setBounds(5, 280, 85, 20); //小盒子,设计用户名模块 ubox.add(uLabel); ubox.add(Box.createHorizontalStrut(5)); ubox.add(uField); //小盒子,设计密码模块 pbox.add(pLabel); pbox.add(Box.createHorizontalStrut(5)); pbox.add(pFd); //大盒子 vbox.add(Box.createVerticalStrut(80)); vbox.add(ubox); vbox.add(Box.createVerticalStrut(60)); vbox.add(pbox); JPanel panel = new JPanel(); panel.setUI(new BasicPanelUI()); panel.setOpaque(false); panel.add(vbox, BorderLayout.CENTER); this.setDefaultCloseOperation(EXIT_ON_CLOSE); button1.addActionListener(e -> { try { init(this,uField, pFd); } catch (Exception exception) { JOptionPane.showMessageDialog(null, "异常", "警告", JOptionPane.WARNING_MESSAGE); } }); button2.addActionListener(e -> { uField.setText(""); pFd.setText(""); }); Menubutton3.addActionListener(e -> { try { this.dispose(); Thread.sleep(1000); new RegisterDemo(); } catch (InterruptedException interruptedException) { JOptionPane.showMessageDialog(null, "异常", "警告", JOptionPane.WARNING_MESSAGE); } }); this.add(button1); this.add(button2); this.add(Menubutton3); this.add(panel); this.setVisible(true); this.setResizable(false); } public void init(LoginDemo loginDemo,JTextField uField, JPasswordField pFd) { Login login; UserLogin UserLogin; try { login=new Login(); login.setLoginDemo(loginDemo); login.setId(uField.getText()); char[] p = pFd.getPassword(); login.setPassword(new String(p)); UserLogin = new UserLogin(); UserLogin.readLogin(login); } catch (SQLException | ClassNotFoundException e) { JOptionPane.showMessageDialog(null, "异常", "警告", JOptionPane.WARNING_MESSAGE); } } }
*************************************计算器界面*******************************************\
package POJO; import java.math.BigDecimal; import java.util.Stack; public class calculate { // 符号栈 private Stack<String> signStack = new Stack(); // 数字栈 private Stack<BigDecimal> numStack = new Stack(); // switch可以判断引用类型变量的值相等吗{0:'+', 1:'-', 2:'x', 3:'/'} private static final String signCode = "+-x/()"; // 计算器主体模块 public BigDecimal work(BigDecimal caled, BigDecimal cal, String sign) { BigDecimal ans = null; switch (signCode.indexOf(sign)) { case 0: ans = caled.add(cal); break; case 1: ans = caled.subtract(cal); break; case 2: ans = caled.multiply(cal); break; case 3: try { ans = caled.divide(cal); }catch (ArithmeticException AE) { if(AE.getLocalizedMessage().equals("Non-terminating decimal expansion; no exact representable decimal result.")) ans = caled.divide(cal, 5, BigDecimal.ROUND_HALF_UP); else ans = BigDecimal.valueOf(32202); System.out.println("Exception : "+AE.getLocalizedMessage()); } break; case 4: case 5: this.numStack.push(caled); ans = cal; break; default: ans = null; } return ans; } // 设计开方(牛顿莱布尼兹) public static BigDecimal niuton(BigDecimal caled) { BigDecimal ans; if (caled.doubleValue() < 0) { System.out.println("Exception : Negative caled"); return BigDecimal.valueOf(32202); } double x = 1; double y = x - (x * x - caled.doubleValue()) / (2 * x); while (x - y > 0.00000001 || x - y < -0.00000001) { x = y; y = x - (x * x - caled.doubleValue()) / (2 * x); } ans = BigDecimal.valueOf(y); return ans; } // 设计平方 public static BigDecimal square(BigDecimal caled) { return caled.pow(2); } // 设计清屏 public void refresh() { this.numStack.clear(); this.signStack.clear(); this.signStack.push("="); // 解决计算当(x+y)后输入符号时,需要出栈两个数进行括号运算(即将数按顺序压回去)时数字栈只有一个栈的问题。 this.numStack.push(new BigDecimal(0)); } // 索引 private String index = "+-x/()="; // 数据,>为0,<为1,=为2,null为3 private int[][] compareToSign = {{0, 0, 1, 1, 1, 0, 0}, {0, 0, 1, 1, 1, 0, 0}, {0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 1, 0, 0}, {1, 1, 1, 1, 1, 2, 3}, {0, 0, 0, 0, 3, 0, 0}, {1, 1, 1, 1, 1, 3, 2}}; // 数字入栈 public void numPush(String decimal) { this.numStack.push(new BigDecimal(decimal)); } public void numPush(BigDecimal decimal) { this.numStack.push(decimal); } // 控制流 public void calIOC(String topSign) { BigDecimal caled, cal; String temp; temp = this.signStack.peek(); switch (this.compareToSign[index.indexOf(temp)][index.indexOf(topSign)]) { case 0: cal = this.numStack.pop(); caled = this.numStack.pop(); temp = this.signStack.pop(); this.numStack.push(this.work(caled, cal, temp)); this.signStack.push(topSign); break; case 1: this.signStack.push(topSign); break; case 2: this.signStack.pop(); break; default: System.out.println("Exception : wrong I/O"); break; } } // 等号入栈 public BigDecimal equaIOC() { BigDecimal ans, caled, cal; String topSign; while (!"=".equals(this.signStack.peek())) { topSign = this.signStack.pop(); cal = this.numStack.pop(); caled = this.numStack.pop(); this.numStack.push(this.work(caled, cal, topSign)); } ans = this.numStack.pop(); return ans; } // pow的IO流控制 public void powIOC(String topSign) { BigDecimal temp; temp = this.numStack.pop(); if (topSign.equals("^2")) { this.numStack.push(calculate.square(temp)); } else { this.numStack.push(calculate.niuton(temp)); } } public void barcketIOC() { BigDecimal caled, cal; String topSign; while (!"(".equals(this.signStack.peek())) { topSign = this.signStack.pop(); cal = this.numStack.pop(); caled = this.numStack.pop(); this.numStack.push(this.work(caled, cal, topSign)); } this.signStack.pop(); } }
package com.auqa.version; // 导入自己的计算类 import POJO.calculate; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.math.BigDecimal; import java.sql.SQLException; // 计算器界面 public class calculator extends JFrame implements ActionListener { Records rec = new Records(); // 获得显示屏大小 public static final int SCREAM_HEIGHT = (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight(); // 根据显示屏高度设定计算器界面大小 private static final int EXAMPLE = (int) (SCREAM_HEIGHT / 4.32); // 字体大小 Font cu = new Font("粗体", Font.BOLD, (int) (EXAMPLE * 0.2)); protected void __init__() { // 设置窗口名称 this.setTitle("计算器"); // 4比3固定窗口 this.setSize(EXAMPLE * 3, EXAMPLE * 4); this.setResizable(false); this.setLocationRelativeTo(null); // 设置窗口可见 this.setVisible(true); this.setBackground(Color.black); // 设置关闭按钮(释放进程) this.setDefaultCloseOperation(EXIT_ON_CLOSE); // 设置方向布局 this.setLayout(new BorderLayout()); } // 北面组件 private JPanel northBox = new JPanel(new FlowLayout()); private JTextField input = new JTextField(); private JButton clear = new JButton(); // 设置北面组件 private void setNorth() { // 设置数字栏 this.input.setPreferredSize(new Dimension((int) (EXAMPLE * 2.2), (int) (EXAMPLE * 0.4))); this.input.setFont(this.cu); this.input.setForeground(Color.BLACK); this.input.setEnabled(false); this.input.setHorizontalAlignment(SwingConstants.RIGHT); // 设置清空 this.clear.setText("C"); this.clear.setPreferredSize(new Dimension((int) (EXAMPLE * 0.4), (int) (EXAMPLE * 0.4))); this.clear.setFont(this.cu); this.clear.setForeground(Color.RED); // 安装北仪表 this.northBox.add(this.input); this.northBox.add(this.clear); // 安装北仪表到主体 this.add(this.northBox, BorderLayout.NORTH); } // 中部组件 private JPanel CPU = new JPanel(); private JButton[] cal = new JButton[20]; String str = "789/456x123-0.=+"; // 设置中部组件 private void setCenter() { // 划分20格 this.CPU.setLayout(new GridLayout(5, 4)); // 设置开方按钮 this.cal[0] = new JButton(); this.cal[0].setText("^-2"); this.cal[0].setPreferredSize(new Dimension((int) (EXAMPLE * 0.2), (int) (EXAMPLE * 0.15))); this.cal[0].setFont(this.cu); this.cal[0].setForeground(Color.BLUE); // 设置括号按钮 this.cal[1] = new JButton(); this.cal[1].setText("^2"); this.cal[1].setPreferredSize(new Dimension((int) (EXAMPLE * 0.2), (int) (EXAMPLE * 0.15))); this.cal[1].setFont(this.cu); this.cal[1].setForeground(Color.BLUE); this.cal[2] = new JButton(); this.cal[2].setText("("); this.cal[2].setPreferredSize(new Dimension((int) (EXAMPLE * 0.2), (int) (EXAMPLE * 0.15))); this.cal[2].setFont(this.cu); this.cal[2].setForeground(Color.BLUE); // 设置清除按钮 this.cal[3] = new JButton(); this.cal[3].setText(")"); this.cal[3].setPreferredSize(new Dimension((int) (EXAMPLE * 0.2), (int) (EXAMPLE * 0.15))); this.cal[3].setFont(this.cu); this.cal[3].setForeground(Color.BLUE); // 设置后16个按钮 for (int i = 4; i < 20; i++) { String temp = this.str.substring(i - 4, i - 3); this.cal[i] = new JButton(); this.cal[i].setText(temp); this.cal[i].setPreferredSize(new Dimension((int) (EXAMPLE * 0.2), (int) (EXAMPLE * 0.15))); this.cal[i].setFont(this.cu); if ("+-x/=".contains(temp)) { this.cal[i].setForeground(Color.GRAY); } } // 添加按钮 for (int i = 0; i < 20; i++) { this.CPU.add(this.cal[i]); } this.add(this.CPU,BorderLayout.CENTER); } public String uid; public void setUid(String id) { this.uid = id; } // 南面组件 private JLabel message = new JLabel("welcome,", SwingConstants.CENTER); // 设置南面组件 private void setSouth() { this.message.setText("welcome," + this.uid); this.message.setPreferredSize(new Dimension((int) (EXAMPLE * 0.1), (int) (EXAMPLE * 0.1))); this.message.setForeground(Color.BLACK); this.add(this.message, BorderLayout.SOUTH); } // 给按钮添加监听 private void setListener() { for (JButton j : cal) { j.addActionListener(this); } this.clear.addActionListener(this); } // 监听事件设置 @Override public void actionPerformed(ActionEvent e) { String listen = e.getActionCommand(); if ("0.1^23456789+-x/()^-2".contains(listen)) { this.input.setText(this.input.getText() + listen); } this.bigWork(listen); } // 小数点信号 private Boolean pointSignal = false; // 括号信号 private int barcketNum = 0; private String num = "0123456789"; private String sign = "+-x/("; // 输入的最后一位为数字时的状态,详细见详细设计表格 public void inNum() { // 只能输入pow函数,右括号,数字和符号按钮,不能输入左括号,若小数点信号为真,则可以输入小数点 for (int i=0;i<20;i++) { if("(".equals(this.cal[i].getText())) { this.cal[i].setEnabled(false); } else { this.cal[i].setEnabled(true); } } // 根据信号设置 this.cal[17].setEnabled(this.pointSignal); } // 输入的最后一位为符号或左括号时 public void inSign() { // 只能输入非小数点数字及左括号,小数点信号开启 for (int i=0;i<20;i++) { if("(".equals(this.cal[i].getText()) || this.num.contains(this.cal[i].getText())) { this.cal[i].setEnabled(true); } else { this.cal[i].setEnabled(false); } } this.pointSignal = true; } // 输入最后一位为右括号或pow运算时 public void inPow() { // 只能输入符号和右括号和pow函数 for (int i=0;i<20;i++) { if("(".equals(this.cal[i].getText()) || this.num.contains(this.cal[i].getText()) || ".".equals(this.cal[i].getText())) { this.cal[i].setEnabled(false); } else { this.cal[i].setEnabled(true); } } } // 输入最后一位为小数点时 public void inPoint() { // 只能输入非小数点数字,小数点信号关闭 for (int i=0;i<20;i++) { if(this.num.contains(this.cal[i].getText())) { this.cal[i].setEnabled(true); } else { this.cal[i].setEnabled(false); } } this.pointSignal = false; } public void inEqual() { for (int i=0;i<20;i++) { this.cal[i].setEnabled(false); } } // 真正的超级初始化块 public calculator() throws HeadlessException, SQLException, ClassNotFoundException { // 界面设置 this.__init__(); this.setNorth(); this.setCenter(); this.setSouth(); // 交互设置 this.setListener(); JOptionPane.showMessageDialog(this, "由于框架原因,本计算器打开时可能按钮显示不全,请最小化后打开"); this.inSign(); this.calculate.refresh(); } calculate calculate = new calculate(); private String temStr = ""; private String records; private String result; public void setCaled(String caled) { this.records = caled; } public void setAns(BigDecimal ans) { this.result = ans.toString(); } public String getCaled() { return records; } public String getAns() { return result; } // 控制器 public void bigWork(String listen) { // 记录括号信号 if ("(".equals(listen)) { this.barcketNum++; } if (")".equals(listen)) { this.barcketNum--; } // 基础状体转换 if (this.num.contains(listen)) { this.temStr = this.temStr +listen; this.inNum(); } else if (this.sign.contains(listen)) { if(!"".equals(temStr)) { this.calculate.numPush(this.temStr); this.temStr = ""; } this.calculate.calIOC(listen); this.inSign(); } else if (")".equals(listen) || listen.contains("^")) { if(!"".equals(temStr)) { this.calculate.numPush(this.temStr); this.temStr = ""; } if (listen.contains("^")) { calculate.powIOC(listen); } else { this.calculate.barcketIOC(); } this.inPow(); } else if (".".equals(listen)) { this.temStr = this.temStr +listen; this.inPoint(); } else if ("=".equals(listen)) { if(!"".equals(temStr)) { this.calculate.numPush(this.temStr); this.temStr = ""; } this.setCaled(this.input.getText()); this.setAns(this.calculate.equaIOC()); try { rec.excuteins(uid,records,result); } catch (Exception e) { throw new RuntimeException(e); } this.input.setText(this.result); this.inEqual(); }else if ("C".equals(listen)) { this.calculate.refresh(); this.input.setText(""); this.temStr = ""; this.barcketNum = 0; this.inSign(); } else { JOptionPane.showMessageDialog(this, "error : unvaild input"); } // 限制用户输入 if (this.barcketNum < 0) { JOptionPane.showMessageDialog(this,"error : wrong number of barcket"); } if(this.barcketNum == 0) { this.cal[3].setEnabled(false); } if (this.barcketNum > 0) { this.cal[18].setEnabled(false); } } public calculator(String uid) throws HeadlessException, SQLException, ClassNotFoundException { // 界面设置 this.__init__(); this.setNorth(); this.setCenter(); // 获取uid this.setUid(uid); this.setSouth(); // 交互设置 this.setListener(); JOptionPane.showMessageDialog(this, "由于框架原因,本计算器打开时可能按钮显示不全,请最小化后打开"); this.inSign(); this.calculate.refresh(); } }
******************************************数据库连接**************************************************
package User; import com.mysql.cj.jdbc.MysqlDataSource; import javax.swing.*; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; public class UserRegister { Connection connection = null; PreparedStatement presql; public UserRegister() throws SQLException { try { MysqlDataSource mysqlDataSource = new MysqlDataSource(); mysqlDataSource.setURL("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false"); mysqlDataSource.setUser("root"); mysqlDataSource.setPassword("123456"); connection = mysqlDataSource.getConnection(); } catch (SQLException throwables) { JOptionPane.showMessageDialog(null,"数据库连接失败","警告",JOptionPane.WARNING_MESSAGE); } } public void writeRegister(Register register){ int flag; try { String sql = "INSERT INTO test.User VALUES (?,?,?)"; presql = connection.prepareStatement(sql); presql.setString(1,register.getId()); presql.setString(2,register.getPassword()); presql.setString(3,register.getName()); flag = presql.executeUpdate(); connection.close(); if (flag!=0){ JOptionPane.showMessageDialog(null,"注册成功"); }else { JOptionPane.showMessageDialog(null,"注册失败","提示",JOptionPane.WARNING_MESSAGE); } } catch (SQLException e) { JOptionPane.showMessageDialog(null,"ID已存在!","警告",JOptionPane.WARNING_MESSAGE); } } }
package com.auqa.version; import com.mysql.cj.jdbc.MysqlDataSource; import javax.swing.*; import java.sql.*; public class Records { Connection connection = null; Statement statement = null; public Records() throws SQLException, ClassNotFoundException { try { MysqlDataSource mysqlDataSource = new MysqlDataSource(); mysqlDataSource.setURL("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false"); mysqlDataSource.setUser("root"); mysqlDataSource.setPassword("123456"); this.connection = mysqlDataSource.getConnection(); this.statement = this.connection.createStatement(); } catch (Exception e) { JOptionPane.showMessageDialog(null, "数据库连接失败", "提示", JOptionPane.WARNING_MESSAGE); } } public int excuteins(String uid,String records, String result) throws Exception { int temp = this.statement.executeUpdate("INSERT INTO record VALUE ('"+uid+"','"+records+"',"+result+")"); return temp; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南