# 实验二 学生选课模拟系统 **Repository Path**: night-yang/homework2 ## Basic Information - **Project Name**: 实验二 学生选课模拟系统 - **Description**: 学生选课模拟系统,拥有GUI,学校第二次实验作业 - **Primary Language**: Unknown - **License**: WTFPL - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2023-10-06 - **Last Updated**: 2024-07-23 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 实验二 学生选课模拟系统 #### 介绍 学生选课模拟系统,基于java1.8开发,拥有GUI,学校第二次实验作业 #### 实验目的 初步了解分析系统需求,从学生选课角度了解系统中的实体及其关系,学会定义类中的属性以及方法; 掌握面向对象的类设计方法(属性、方法); 掌握通过构造方法实例化对象; 自我目的:复习java内容,探索java在windows上的GUI开发基础。 #### 业务要求 学校人员分为“教师”和“学生”,教师教授“课程”,学生选择“课程”。 对象: 教师(编号、姓名、性别) 学生(编号、姓名、性别、所选课程) 课程(编号、课程名称、上课地点、时间、教师) 软件要有基本GUI界面方便操作。 #### 实验基本要求 1. 编写上述实体类以及测试主类 2. 在测试主类中,实例化多个类实体,模拟 1)教师开设某课; 2)学生选课、退课 3)打印学生课表信息(包括:编号、课程名称、上课地点、时间、授课教师) #### 解题思路 1.首先定义Course、Teacher、Student三个类,为保证Main简洁性与可读性,引入MyFrame类用于GUI布局。 2.Teacher类详解: 此类包含教师有的三个属性:姓名、编号、性别。规范考虑所有属性设置为私有,构建getter方法获取类变量。 有一个三参构造器:姓名、性别、编号。 3.Student类: 与Teacher类相似,但额外增加一个Course[]类型类变量,用于存储该学生选的课程。与此同时增加3个为Course[]准备的方法:addCourse、 delCourse、getCourse 4.Main类: 包含两个极为重要的静态类变量,HashMap类型。 courses:用于储存教师添加的所有的课程。 students:用于储存所有学生。 主程序任务为初始化两个hashmap,然后调用myframe绘制窗体。 5.Course类: 5个属性:编号、课程名称、上课地点、时间、教师。课程信息在课程添加时就已经确定。因此构造器需传入5个属性。 6.MyFrame类: 最重要的一个类,包含所有GUI信息,借此理清思路: 主界面3个按钮:教师添加课程、学生选课、查询课表 点击教师添加课程:用户输入教师姓名、教师编号、教师性别、课程名称、课程号、上课地点、上课时间。 点击确认添加后,获取输入框信息,实例化教师与课程。把课程的编号压入hashmap存储。 点击学生选课后,在列表框内显示所有的课程,学生输入自己的信息后选择要选的课程点击确认选课。 **这时候就体现了hashmap students存在的必要性:避免重复实例化同一个学生。** 点击确认选课后,现在hashmap中查找学生是否存在,如果没有则实例化新学生,若已存在则直接调用该student的添加课程方法加课。 最后弹窗提示选课成功。 点击查询课表:输入学生编号,然后根据学生编号在hashmap students中查找该学生,然后从中Crouse[]中遍历学生选的课并显示在列表。 显示在列表中的课信息更为完整,以体现Teacher类的价值。 此界面还有个退课选项,即调用student类中delCrouse方法遍历学生类中的Crouse[]删除选中的课程。 #### 流程图 ![输入图片说明](%E5%AD%A6%E7%94%9F%E9%80%89%E8%AF%BE%E6%A8%A1%E6%8B%9F%E7%B3%BB%E7%BB%9F.png) #### 关键代码 **_其实感觉最有难度的是关于GUI的部分,swing中没有向安卓开发一样惯用的线性布局,流式布局不合我意,所以我其实使用了手工布局+流式布局的方式,并且限制了窗体形状大小以及生成位置,列表控件的使用也很有意思,但考虑到作业性质不做重点说明_** 1.students类中的加课方法,将课程对象压入数组 ``` void addCourse(Course course){ for (int i = 0; i < 30; i++) { if (courses[i]==null){ courses[i]=course; break; } } } ``` 2.students类中的删课方法,将课程对象从数组中恢复为null ``` void delCourse(Course course){ for (int i = 0; i < 30; i++) { if (courses[i]==course){ courses[i]=null; } } } ``` 3.运算让按钮处于中间 ``` // 创建并添加“学生选课”按钮 JButton button2 = new JButton("学生选课"); button2.setSize(140, 40); button2.setBounds((380 - button2.getWidth()) / 2, 60, button2.getWidth(), button2.getHeight()); mainpane.add(button2); button2.addActionListener(e -> { System.out.println("学生选课"); // 创建新的窗口以支持学生选课 JFrame main = new MyFrame("学生选课", 3); this.dispose(); // 关闭当前窗口 }); ``` 4.性别单选框,选择一个性别自动取消勾选另一个性别 ``` mainpane.add(new JLabel("教师性别:")); JCheckBox c1 = new JCheckBox("男 "); JCheckBox c2 = new JCheckBox("女 "); mainpane.add(c1); mainpane.add(c2); c1.addActionListener(e -> { if (c2.isSelected()) { c2.setSelected(false); } }); c2.addActionListener(e -> { if (c1.isSelected()) { c1.setSelected(false); } }); ``` 5.教师加课代码,获取输入框内容数据类型转化后进行实例化 ``` // 添加确认添加按钮 JButton button2 = new JButton("确认添加"); mainpane.add(button2); button2.addActionListener(e -> { System.out.println("确认添加"); Course course = Main.courses.get(text4.getText()); if (course == null) { String sex = "男"; if (c2.isSelected()) { sex = "女"; } Teacher teacher = new Teacher(text1.getText(), Integer.parseInt(text2.getText()), sex); course = new Course(Integer.parseInt(text4.getText()), text3.getText(), text5.getText(), text6.getText(), teacher); Main.courses.put(Integer.valueOf(text4.getText()), course); } System.out.println(Main.courses); JOptionPane.showMessageDialog(null, "添加成功!"); }); } ``` 6.遍历HashMap实现显示课程列表 ``` // 添加课程列表和滚动条 JList list = new JList<>(); JScrollPane scrollPane = new JScrollPane(list); mainpane.add(scrollPane, BorderLayout.CENTER); DefaultListModel model = new DefaultListModel<>(); Course course; Teacher teacher; for (Map.Entry entry : Main.courses.entrySet()) { course = entry.getValue(); teacher = course.getTeacher(); model.addElement(course.getId() + " " + course.getName() + " 地点:" + course.getPlace() + " 时间:" + course.getTime() + " 教师:" + teacher.getName()); } list.setModel(model); list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); ``` 7.查询课表,显示课程与其授课教师的所有信息 ``` // 添加查询按钮 JButton button2 = new JButton("查询"); mainpane.add(button2); button2.addActionListener(e -> { System.out.println("查询课表"); model.clear(); list.setModel(model); Student student = Main.students.get(text1.getText()); for (Course cours : student.getCourses()) { if (cours != null) { Teacher teacher = cours.getTeacher(); model.addElement(cours.getId() + " " + cours.getName() + " 地点:" + cours.getPlace() + " 时间:" + cours.getTime() + " 教师姓名:" + teacher.getName() + " 教师编号:" + teacher.getId() + " 教师性别:" + teacher.getSex()); } } list.setModel(model); }); ``` 8.运用字符串处理获取选中的课程号实现退课 ``` // 添加退课按钮 JButton button3 = new JButton("退课"); mainpane.add(button3); button3.addActionListener(e -> { System.out.println("退课"); Student student = Main.students.get(text1.getText()); String str = list.getSelectedValue().substring(0, list.getSelectedValue().indexOf(" ")); student.delCourse(Main.courses.get(Integer.valueOf(str))); JOptionPane.showMessageDialog(null, "退课成功!"); }); ``` #### 运行截图 程序主界面,用了手工布局达到的效果 ![程序主界面,用了手工布局达到的效果](%E4%B8%BB%E7%95%8C%E9%9D%A2.png) 教师加课页面 ![输入图片说明](%E6%95%99%E5%B8%88%E6%B7%BB%E5%8A%A0%E8%AF%BE%E7%A8%8B%E7%95%8C%E9%9D%A2.png) 性别是单选项,选了一个性别自动取消另一个 ![输入图片说明](%E8%BE%93%E5%85%A5%E8%AF%BE%E7%A8%8B%E4%BF%A1%E6%81%AF.png) 加课成功提示弹窗 ![输入图片说明](%E6%8F%90%E7%A4%BA%E5%BC%B9%E7%AA%97.png) 选课界面 ![输入图片说明](%E9%80%89%E8%AF%BE%E7%95%8C%E9%9D%A2.png) 重名也是没关系的,学号不同就行 ![输入图片说明](%E9%80%89%E8%AF%BE%E7%95%8C%E9%9D%A22.png) ![输入图片说明](%E9%80%89%E8%AF%BE%E6%88%90%E5%8A%9F.png) 查课表界面 ![输入图片说明](%E6%9F%A5%E8%AF%BE%E8%A1%A8%E7%A4%BA%E4%BE%8B.png) 滚动条确保用户能看到所有信息,包括教师性别等等 ![输入图片说明](%E6%9F%A5%E8%AF%BE%E8%A1%A8%E7%A4%BA%E4%BE%8B2.png) 一个学生选很多课自然也没问题 ![输入图片说明](%E6%9F%A5%E8%AF%BE%E8%A1%A8%E7%A4%BA%E4%BE%8B3.png) 选中课程后点击退课,退掉的课就没啦 ![输入图片说明](%E9%80%80%E8%AF%BE%E6%88%90%E5%8A%9F%E6%8F%90%E7%A4%BA%E5%BC%B9%E7%AA%97.png) ![输入图片说明](%E6%9F%A5%E8%AF%BE%E8%A1%A8%E7%A4%BA%E4%BE%8B4.png) #### 优化方向 **尽管本程序已经超过本次实验的基本要求,但离真正可使用的程序还差得远,这里记录一些重点优化方向** 1.没有异常数据处理,尽管报错不会导致闪退。 2.弹窗提示不够人性化,应该添加更多的用户提示,比如输入信息不完整等等。 3.没有数据校验,如果用户乱输入内容,可能造成异常。 4.没有数据保存至本地的环节。 5.虽然本程序符合实验要求,但是其中逻辑有一点不好,教师类与课程类的联系不够,如果要添加一个教师删除课程的模块,会需要较大改动。 #### 感想与体会 - Java自带的swing是真不好使啊,比安卓自带的布局器简易的多,或许应该尝试使用一些现成的框架会有更好的结果。 - 复习了HashMap的使用,熟悉了HashMap与数组的优缺点,老实说我之前HashMap用的真不多,为了规避排序问题总是自己写数组替代HashMap功能,但HashMap还是要方便多了。 - 实验中在将文本框内内容转为数字时用到了Integer.parseInt()和Integer.valueOf()两个方法,看起来效果差不多,其实返回类型不同,令我印象深刻。 - 熟悉了swing布局相关知识,了解了和Android GUI编程的区别,尤其是列表相关的。 - 写注释的习惯变差了,最后才补了一点注释。