Java 黑马程序员学习笔记(进阶篇27)

一、拼图小游戏

1. Java Swing 图形界面 中处理「鼠标点击事件」的逻辑
java 复制代码
@Override
public void mouseClicked(MouseEvent e) {
    if (e.getSource() == submit) {  // 不太理解
        if (username.getText().length() == 0 || password.getText().length() == 0 || rePassword.getText().length() == 0) {
            showDialog("用户名和密码不能为空");
            return;  // 不太理解
        }
        if (!password.getText().equals(rePassword.getText())) {
            showDialog("两次密码输入不一致");
            return;
        }
        if (!username.getText().matches("[a-zA-Z0-9]{4,16}")) {
            showDialog("用户名不符合规则");
            return;
        }
        if (!password.getText().matches("\\S*(?=\\S{6,})(?=\\S*\\d)(?=\\S*[a-z])\\S*")) {
            showDialog("密码不符合规则,至少包含一个小写字母,一个数字,长度至少6位");
            return;
        }

        if (containUsername(username.getText())) {
            showDialog("用户名已经存在,请重新输入");
            return;
        }

        allUsers.add(new User(username.getText(),password.getText()));
        FileUtil.writeLines(allUsers,"D:\\张锐彬\\Java\\01-登录注册学生练习代码\\puzzlegame\\puzzlegame\\userinfo.txt","UTF-8");
        showDialog("注册成功");
        this.setVisible(false);  // 不太理解
        new LoginJFrame();

    } else if (e.getSource() == reset) {
        username.setText("");
        password.setText("");
        rePassword.setText("");
    }
}
关键逻辑 1:if (e.getSource() == submit)
java 复制代码
if (e.getSource() == submit) { ... } else if (e.getSource() == reset) { ... }
  • e:是 MouseEvent 类型的对象,代表「鼠标点击事件」的所有信息(比如点击的位置、点击的组件等)。
  • e.getSource():获取「触发这次鼠标点击事件的组件」(比如用户点击了「提交」按钮,就返回这个按钮对象;点击「重置」按钮,就返回重置按钮对象)。
  • submitreset:是你在界面中定义的两个按钮对象(比如 JButton submit = new JButton("提交");)。
  • 整个判断的意思:判断用户点击的是「提交」按钮还是「重置」按钮,分别执行不同逻辑。
关键逻辑 2: 注册校验:非空判断 + return
java 复制代码
if (username.getText().length() == 0 || password.getText().length() == 0 || rePassword.getText().length() == 0) {
    showDialog("用户名和密码不能为空");
    return; // 不太理解
}
  • usernamepasswordrePassword:是界面中的输入框组件(比如 JTextField username = new JTextField();)。
  • getText():获取输入框中用户输入的文本。
  • length() == 0:判断输入框是否为空(文本长度为 0)。
  • showDialog(...):自定义方法(推测是弹出一个提示框,显示错误信息)。
  • 关键:return 的作用 :一旦发现「用户名 / 密码为空」,弹出提示后,立即终止当前方法的执行 (后面的密码一致性校验、格式校验等逻辑都不会再执行)。为什么要加 return?比如用户没输入内容就点提交,此时已经不符合注册条件,再执行后面的逻辑毫无意义,还可能导致错误(比如空字符串的格式校验失败),所以直接返回,节省资源。
关键逻辑 3:注册成功后的逻辑
java 复制代码
// 1. 将新用户添加到内存中的用户列表(allUsers 是自定义的集合,比如 List<User>)
allUsers.add(new User(username.getText(), password.getText()));

// 2. 将用户列表写入本地文件(FileUtil 是自定义工具类,用于文件操作)
FileUtil.writeLines(allUsers, "D:\\...\\userinfo.txt", "UTF-8");

// 3. 弹出注册成功提示
showDialog("注册成功");

// 4. 隐藏当前注册窗口(this 指代当前的注册界面,比如 RegisterJFrame)
this.setVisible(false); // 不太理解

// 5. 创建并显示登录窗口(LoginJFrame 是登录界面的类)
new LoginJFrame();
  • 关键:this.setVisible(false) 的作用this 指代「当前的注册窗口对象」(因为这个方法所在的类是注册窗口类,比如 RegisterJFrame)。setVisible(false) 是 Swing 组件的方法,意思是「让当前窗口隐藏」(不再显示在屏幕上)。为什么要隐藏?注册成功后,用户需要跳转到「登录界面」,所以先把注册窗口关掉(隐藏),再创建登录窗口并显示。
关键逻辑 5:重置按钮的逻辑
java 复制代码
else if (e.getSource() == reset) {
    username.setText(""); // 清空用户名输入框
    password.setText(""); // 清空密码输入框
    rePassword.setText(""); // 清空重复密码输入框
}
  • 当用户点击「重置」按钮时,调用输入框的 setText("") 方法,将输入框中的文本设为空字符串,实现「清空输入」的功能。
2. 游戏存档读档的功能
java 复制代码
// 存档功能
else if(obj == saveItem0 || obj == saveItem1 || obj == saveItem2 || obj == saveItem3 ||obj == saveItem4){
    System.out.println("存档");
    JMenuItem item = (JMenuItem) obj;  // 不太理解
    String str = item.getText();
    int index = str.charAt(2) - '0';  // 不太理解

    try {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\张锐彬\\Java\\02-游戏存档和读档学生练习代码\\puzzlegame\\puzzlegame\\save\\save" + index + ".txt"));
        GameInfo gi = new GameInfo(data,x,y,path,step);  // 不太理解
        IoUtil.writeObj(oos,true,gi);  // 不太理解
    } catch (IOException ex) {
        throw new RuntimeException(ex);
    }
    item.setText("存档" + index + "(" + step + "步)");  // 不太理解
    loadJMenu.getItem(index).setText("存档" + index + "(" + step + "步)");


}
// 读档功能
else if(obj == loadItem0 || obj == loadItem1 || obj == loadItem2 || obj == loadItem3 ||obj == loadItem4){
    JMenuItem item = (JMenuItem) obj;
    String str = item.getText();
    int index = str.charAt(2) - '0';
    
    GameInfo gi = null;
    try {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\张锐彬\\Java\\02-游戏存档和读档学生练习代码\\puzzlegame\\puzzlegame\\save\\save" + index + ".txt"));
        gi = (GameInfo)ois.readObject();  // 不太理解
        ois.close();
    } catch (IOException ex) {
        throw new RuntimeException(ex);
    } catch (ClassNotFoundException ex) {
        throw new RuntimeException(ex);
    }
    
    data = gi.getData();  // 不太理解
    path = gi.getPath();
    step = gi.getStep();
    x = gi.getX();
    y = gi.getY();
    
    initImage();
}
关键逻辑 1:
(1) 存档功能 (else if 块)
关键逻辑 1:else if(obj == saveItem0 || obj == saveItem1 || ...)
  • 这是一个条件判断,用来识别用户点击的是哪个菜单项。
  • obj 是触发事件的组件对象,这里就是被点击的菜单项。
  • 整个判断的意思是:如果用户点击的是 saveItem0saveItem4 这五个菜单项中的任意一个,就执行下面的存档逻辑。
关键逻辑 2:JMenuItem item = (JMenuItem) obj;
  • 核心目的 :我们需要调用这个菜单项的特定方法(如 getText()setText()),但 obj 的类型是 Object,编译器不知道它具体是 JMenuItem 类型。
  • (JMenuItem) :这是强制类型转换 。我们明确告诉编译器:"我知道 obj 实际上是一个 JMenuItem 对象,请把它当作 JMenuItem 来处理"。
关键逻辑 3:int index = str.charAt(2) - '0';
  • 这是一个从字符串中提取数字的常用技巧。
  • str.charAt(2):获取字符串 str 中索引为 2 的字符。对于 "存档0(空)",这个字符就是 '0'
  • '0':在 Java 中,字符用单引号表示。这里的关键是,字符 '0''9' 在计算机内部是按顺序存储的。
  • str.charAt(2) - '0':这是一个数学运算。计算机会使用字符的 ASCII 码值来计算。例如,'3' - '0' 的结果是整数 3
  • 最终目的 :通过这种方式,我们从菜单项文本中提取出了存档的编号(0 到 4),并将其存储在整数变量 index 中。
关键逻辑 4:ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("...save" + index + ".txt"));
  • 这行代码创建了一个用于对象序列化的输出流。
  • new FileOutputStream("..."):创建一个文件输出流,指定了文件保存的路径和文件名。"save" + index + ".txt" 会动态生成文件名,如 save0.txt, save1.txt 等。
  • new ObjectOutputStream(...):将文件输出流包装成对象输出流。ObjectOutputStream 可以将 Java 对象(如我们的游戏状态)转换成字节流,以便写入文件。
关键逻辑 5:GameInfo gi = new GameInfo(data, x, y, path, step);
  • GameInfo 是一个你自定义的类,它的作用就像一个数据容器快照
  • 这行代码创建了一个 GameInfo 对象,并将当前游戏的所有关键状态(data 数组、空白块位置 x,y、图片路径 path、步数 step)作为参数传递给它的构造函数。
  • 这样,gi 对象就完整地记录了游戏在这一刻的状态。
关键逻辑 6:item.setText("存档" + index + "(" + step + "步)");
  • 存档成功后,更新当前点击的存档菜单项的显示文本。
  • 例如,将 "存档 0 (空)" 更新为 "存档 0 (15 步)"。
  • 目的:给用户一个清晰的视觉反馈,让用户知道该存档位已经使用,并且记录了游戏进行到第几步。
(2) 读档功能
关键逻辑 1:ObjectInputStream ois = new ObjectInputStream(new FileInputStream("...save" + index + ".txt"));
  • 这行代码创建了一个用于对象反序列化的输入流。
  • new FileInputStream("..."):创建一个文件输入流,用于读取指定的存档文件。
  • new ObjectInputStream(...):将文件输入流包装成对象输入流。ObjectInputStream 可以从字节流中读取数据,并将其还原成一个 Java 对象。
关键逻辑 2:gi = (GameInfo) ois.readObject();
  • ois.readObject() :从输入流中读取一个对象。这个方法返回的是一个 Object 类型的引用。
  • (GameInfo) :因为我们知道文件里存储的是一个 GameInfo 对象,所以需要进行强制类型转换,将读取到的 Object 转换成 GameInfo 类型。
相关推荐
豐儀麟阁贵2 小时前
6.3对象类型的转换
java·开发语言
报错小能手2 小时前
C++笔记 仿函数(函数对象)
开发语言·c++·笔记
草莓熊Lotso2 小时前
《算法闯关指南:优选算法--模拟》--39.替换所有问号,40.提莫攻击
开发语言·c++·算法·模拟
q***82912 小时前
Spring Boot 热部署
java·spring boot·后端
合作小小程序员小小店2 小时前
web开发,在线%农业产品销售管理%系统,基于idea,html,css,vue.js,layui,java,jdk,ssm
java·前端·jdk·intellij-idea·layui·数据库管理员
IT阳晨。2 小时前
【神经网络与深度学习(吴恩达)】深度学习概论学习笔记
笔记·深度学习·神经网络
草莓熊Lotso3 小时前
C++ STL set 系列完全指南:从底层原理、核心接口到实战场景
开发语言·c++·人工智能·经验分享·网络协议·算法·dubbo
珹洺3 小时前
Java-Spring实战指南(三十四)Android Service实现后台音乐播放功能
android·java·spring
咖啡の猫5 小时前
搭建Python开发环境
开发语言·python