第二次作业
实验目的
1.掌握软件开发的基本流程。
2.掌握常用的软件开发方式和工具。
实验内容
设计一个包含登录界面的计算器软件,该软件可以实现第一次作业中的全部功能,同时可以保存用户的历史计算记录(保存数据最好使用数据库)。
实验过程
1.流程图
(1)用户登录流程图
(2)计算器功能模块流程图
2.用户登录模块
(1)用户登录界面
(2)用户登录界面代码
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8" /> <title></title> <meta name="keywords" content="" /> <meta name="description" content="" /> <style type="text/css"> body { background-size: cover; min-width: 1000px; background-image:url(https://s1.ax1x.com/2020/08/23/d0t8ln.jpg); font-size:14px; } #main { width:360px; height:320px; background:#fff; border:1px solid #ddd; position:absolute; top:50%; left:50%; margin-left:-180px; margin-top:-160px; background-size: cover; background-image:url(https://s1.ax1x.com/2020/07/31/alzGMn.jpg); } #main .title { height: 48px; line-height: 48px; color:#333; font-size:16px; font-weight:bold; text-indent:30px; border-bottom:1px dashed #eee; } #main form { width:300px; margin:20px 0 0 40px; } #main form label { margin:20px 0 0 40px; display:block; } #main form label input.text { width:200px; height:25px; } #main form label input.submit { width:200px; display:block; height:35px; cursor:pointer; margin:20px 0 0 2px; } </style> </head> <body> <div id="main"> <div class="title">欢迎使用,请登录</div> <form action="login.php" method="post" onsubmit="return enter()"> <label><input class="text" type="text" placeholder="用户名" name="username" /></label> <label><input class="text" type="password" placeholder="密码" name="password" /></label> <label><input class="submit" type="submit" name="submit" value="登录" /></label> <a href="register.html" target="_self" style="position: absolute; bottom: 10px; right: 10px;">没有账号,先注册</a> </form> </div> </body> </html>
(3)connect.php 数据库配置文件
<?php $server="localhost";//主机 $db_username="";//你的数据库用户名 $db_password="";//你的数据库密码 $con = mysql_connect($server,$db_username,$db_password);//链接数据库 if(!$con){ die("can't connect".mysql_error());//如果链接失败输出错误 } mysql_select_db('test',$con);//选择数据库 ?>
(4)login.php 登录程序
<?PHP header("Content-Type: text/html; charset=utf8"); if(!isset($_POST["submit"])){ exit("错误执行"); }//检测是否有submit操作 include('connect.php');//链接数据库 $name = $_POST['name'];//post获得用户名表单值 $passowrd = $_POST['password'];//post获得用户密码单值 if ($name && $passowrd){//如果用户名和密码都不为空 $sql = "select * from user where username = '$name' and password='$passowrd'";//检测数据库是否有对应的username和password的sql $result = mysql_query($sql);//执行sql $rows=mysql_num_rows($result);//返回一个数值 if($rows){//0 false 1 true header("refresh:0;url=welcome.html");//如果成功跳转至welcome.html页面 exit; }else{ echo "用户名或密码错误"; echo " <script> setTimeout(function(){window.location.href='login.html';},1000); </script> ";//如果错误使用js 1秒后跳转到登录页面重试; } }else{//如果用户名或密码有空 echo "表单填写不完整"; echo " <script> setTimeout(function(){window.location.href='login.html';},1000); </script>"; //如果错误使用js 1秒后跳转到登录页面重试; } mysql_close();//关闭数据库 ?>
(5)welcome.html 登录成功跳转页面
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <title>登录成功欢迎页面</title> <style> body { margin 0; padding 0; font-family Arial,sans-serif; background-image url('login_success_background.jpg'); background-size cover; background-position center; display flex; justify-content center; align-items center; height 100vh; color white; } .container { background-color rgba(0,0,0,0.5); padding 20px; border-radius 10px; width 300px; } h1 { text-align center; margin-bottom 20px; } p { text-align center; } </style> </head> <body> <div class="container"> <h1>欢迎登录!</h1> <p>感谢您选择我们的服务,祝您在使用过程中愉快!</p> </div> </body> </html>
(6)测试结果
1>数据库用户信息
2>登录成功页面
3>登录失败界面
3.计算器功能模块
(1)计算器界面
(2)计算器功能测试结果
(3)数据库实现
(4)计算器代码
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 = {"mc", "m+", "m-", "mr", "c", "/", "*", "ms", "7", "8", "9", "4", "5", "6", "1", "2", "3", "+", "√", "0", ".", "="}; 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(String str) { double a = Double.parseDouble(str); return Math.sqrt(a); } // 计算后缀表达式,并返回最终结果 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(); } }