Java学习记录(二):黑马程序员拼图小游戏

Java学习记录(二)

1、相关介绍

(1)思路来源

本人跟着B站黑马程序员Java教程学习,本文记录其中的拼图小游戏,详细可查看原视频。首先看完他的思路讲解后,自己再独立编写,仅供学习交流。

代码中所使用的全部素材均来自黑马程序员,具体可访问其官网获取。

(2)主要功能

① 登录功能

登录功能主要包括账号密码的输入验证、显示密码、验证码的输入与更新与验证,以及注册按钮的实现。

② 注册功能

注册功能主要包括账号密码与二次密码的输入与验证,注册按钮与重置按钮的实现。

③ 游戏主功能

游戏主功能主要包含拼图上下左右移动逻辑的实现、更换游戏图片的实现、重新开始游戏的实现、返回登录页面的实现、退出游戏、查看完整图片以及一键作弊功能的实现。

(3)项目整体结构

图片


2、主要代码实现

(1)接口Adapter实现

窗体事件Adapter实现

package com.test.Adapter;

import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

// 先定义一个Adapter类实现WindowListener接口,并重写所有函数但不用
// 写明函数体,后续使用时只需继承该类(匿名类)重写部分所需要的响应函数即可。
// 当然也可以使用Java自带的那些Adapter,此处只是我为了复习一下
public class WindowAdapter implements WindowListener {
    @Override
    public void windowOpened(WindowEvent e) {}

    @Override
    public void windowClosing(WindowEvent e) {}

    @Override
    public void windowClosed(WindowEvent e) {}

    @Override
    public void windowIconified(WindowEvent e) {}

    @Override
    public void windowDeiconified(WindowEvent e) {}

    @Override
    public void windowActivated(WindowEvent e) {}

    @Override
    public void windowDeactivated(WindowEvent e) {}
}
(2)账户JavaBean类Users实现
package com.test.bean;

// 用户JavaBean类
public class Users {
    /**
    * username: 用户名
    * password: 用户密码
    */
    private String username;
    private String password;

    // 空参构造
    public Users() {
    }

    // 有参构造,初始化成员变量
    public Users(String username, String password) {
        this.username = username;
        this.password = password;
    }

    /**
    * username和password的getter和setter函数
    */
    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    // 重写toString方法,便于打印等操作
    @Override
    public String toString() {
        return "Users{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}
(3)游戏主功能实现

整体代码如下,详细逻辑实现可以看代码注释,比较详尽

package com.test.ui;

import javax.swing.*;
import javax.swing.border.BevelBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;

public class GameJFrame extends JFrame implements KeyListener, ActionListener {
    // 初始化一个随机类变量
    Random rand = new Random();

    // 整型二元数组,存储16*16方格中每一个图片的编号
    int[][] data = new int[4][4];
    // 根据编号存储对应的组件,暂无用处
    JLabel[] jLabels = new JLabel[16];
    // x,y分别记录当前空白方块的在图中的坐标位置,分别表示横纵坐标
    // 但是对应的是屏幕的Y轴和X轴
    int x = 0;
    int y = 0;

    // 拼图图像文件中对应三个类别对应图片数量,girl类不用最后两张,可自行打开查明原因,哈哈
    int[] imgNumbers = {8, 11, 10};
    // 记录图片的类型,通过主界面菜单更新图片选择
    String imgType = "animal";
    // 记录当前图片类型对应的编号,基于imgNumbers随机更新
    int imgNumber = 3;
    // 记录当前游戏图片的路径,随更换图片功能更新
    String basePath;

    // 图片正确顺序,即赢得游戏胜利的条件
    int[][] winData = {
            {1, 2, 3, 4},
            {5, 6, 7, 8},
            {9, 10, 11, 12},
            {13, 14, 15, 0},
    };

    // 记录当前图片移动步数
    int steps = 0;

    // 菜单中重新开始选项
    JMenuItem replayJMenuItem;
    // 菜单中重新登录选项
    JMenuItem reLoginJMenuItem;
    // 菜单中退出游戏选项
    JMenuItem exitJMenuItem;
    // 菜单中关于选项,暂未实现
    JMenuItem weChatJMenuItem;
    // 更新游戏图片动物类选项
    JMenuItem animalJmenuItem;
    // 更新游戏图片美女类选项
    JMenuItem girlJmenuItem;
    // 更新游戏图片运动类选项
    JMenuItem sportJmenuItem;

    // 无参构造
    public GameJFrame() {
        // 初始话窗口设置
        initJFrame();

        // 初始化菜单
        initMenu();

        // 初始化游戏数据
        initData();

        // 初始化游戏画面
        initImage();

        // 设置可显示
        this.setVisible(true);
    }

    // 初始化整个框架
    private void initJFrame() {
        // 设置大小
        this.setSize(603, 680);
        // 设置框架名
        this.setTitle("拼图单机版 v1.0.0");
        // 设置在所有窗口之上,暂不使用,否则信息提示窗无法使用
        //this.setAlwaysOnTop(true);
        // 设置窗口位于正中央
        this.setLocationRelativeTo(null);
        // 设置关闭窗口时退出虚拟机
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // 关闭布局
        this.setLayout(null);

        // 使用当前类实现按键监听器相关接口,同时添加监听器
        this.addKeyListener(this);
    }

    // 初始化菜单
    private void initMenu() {
        // 主体菜单栏对象
        JMenuBar jMenuBar = new JMenuBar();

        // 功能菜单对象,包含重新开始、退出登录、退出游戏以及更换图片二级菜单
        JMenu functionJMenu = new JMenu("功能");
        // 关于按钮菜单
        JMenu aboutJMenu = new JMenu("关于");

        // 功能菜单以及关于菜单按钮选项
        replayJMenuItem = new JMenuItem("重新开始");
        reLoginJMenuItem = new JMenuItem("退出登录");
        exitJMenuItem = new JMenuItem("退出游戏");
        weChatJMenuItem = new JMenuItem("公众号");

        // 本类继承ActionListener并实现相关接口,同时添加监听器
        replayJMenuItem.addActionListener(this);
        reLoginJMenuItem.addActionListener(this);
        exitJMenuItem.addActionListener(this);
        weChatJMenuItem.addActionListener(this);

        // 更换图片二级菜单以及各选项
        JMenu changeImgjMenu = new JMenu("更换图片");
        animalJmenuItem = new JMenuItem("动物");
        girlJmenuItem = new JMenuItem("美女");
        sportJmenuItem = new JMenuItem("运动");

        // 添加监听器
        animalJmenuItem.addActionListener(this);
        girlJmenuItem.addActionListener(this);
        sportJmenuItem.addActionListener(this);

        // 将二级菜单选项添加进更换图片菜单
        changeImgjMenu.add(animalJmenuItem);
        changeImgjMenu.add(girlJmenuItem);
        changeImgjMenu.add(sportJmenuItem);

        // 在菜单中添加更换图片二级菜单以及其他菜单选项
        functionJMenu.add(changeImgjMenu);
        functionJMenu.add(replayJMenuItem);
        functionJMenu.add(reLoginJMenuItem);
        functionJMenu.add(exitJMenuItem);
        aboutJMenu.add(weChatJMenuItem);

        // 将两个菜单添加进菜单栏
        jMenuBar.add(functionJMenu);
        jMenuBar.add(aboutJMenu);

        // 将菜单栏添加到窗口
        this.setJMenuBar(jMenuBar);
    }

    // 随机初始化各个图片方块的顺序并进行编码
    private void initData() {
        // 打乱图片方块编号,思路为遍历整个数组,随机获取一个下标,交换两者的位置,实现打乱效果
        Random random = new Random();
        int[] tempArr = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
        for (int i = 0; i < tempArr.length; i++) {
            int randomIndex = random.nextInt(16);
            int temp = tempArr[randomIndex];
            tempArr[randomIndex] = tempArr[i];
            tempArr[i] = temp;
        }

        // 成员变量data记录对应顺序
        int count = 0;
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                this.data[i][j] = tempArr[count++];
                if (this.data[i][j] == 0) {
                    x = i;
                    y = j;
                }
            }
        }
    }

    // 更新主界面的各个图片方框和背景图
    public void initImage() {
        // 更新路径成员变量
        basePath = "image\\" + imgType + "\\" + imgType + imgNumber + "\\";

        // 清除窗口中所有原始组件
        this.getContentPane().removeAll();

        // 判断是否达到胜利条件,达到则更新胜利图片
        if (victory()){
            // 加载图片
            ImageIcon imageIcon2 = new ImageIcon("image\\win.png");
            // 用JLabel组件放置图片
            JLabel imageLabel = new JLabel(imageIcon2);
            // 设置组件的位置大小
            imageLabel.setBounds(203, 283, imageIcon2.getIconWidth(), imageIcon2.getIconHeight());
            // 将组件添加到窗口
            this.getContentPane().add(imageLabel);
        }

        // 更新移动次数显示,使用JLabel显示文字
        JLabel stepsJLabel = new JLabel("移动次数:  " + steps);
        // 设置当前组件的字体、大小等
        stepsJLabel.setFont(new Font(Font.SERIF, Font.BOLD, 16));
        stepsJLabel.setBounds(30, 20, 100, 20);
        this.getContentPane().add(stepsJLabel);

        // 根据成员变量data更新所有的图片方块,根据对应的规律循环加载,减少代码
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {

                ImageIcon imageIcon = new ImageIcon(basePath + this.data[i][j] + ".jpg");
                JLabel jLabel = new JLabel(imageIcon);
                jLabel.setBounds(j * imageIcon.getIconWidth() + 83, i * imageIcon.getIconHeight()+134, imageIcon.getIconWidth(), imageIcon.getIconHeight());
                jLabel.setBorder(new BevelBorder(BevelBorder.LOWERED));

                this.getContentPane().add(jLabel);

                // 记录对应的组件
                jLabels[this.data[i][j]] = jLabel;
            }
        }

        // 添加游戏背景图片
        ImageIcon imageIcon = new ImageIcon("image\\background.png");
        JLabel jLabel = new JLabel(imageIcon);
        jLabel.setBounds(39, 40, imageIcon.getIconWidth(), imageIcon.getIconHeight());
        this.getContentPane().add(jLabel);

        // 重绘整个窗口
        this.getContentPane().repaint();
    }

    // 根据胜利条件成员变量winData判断游戏是否胜利
    private boolean victory() {
        boolean victory = true;

        // 当前编号和正确游戏编号顺序一一对应则游戏胜利,否则游戏失败
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                if (this.data[i][j] != this.winData[i][j]) {
                    victory = false;
                    break;
                }
            }
        }

        return victory;
    }

    // KeyTyped事件响应函数
    @Override
    public void keyTyped(KeyEvent e) {
        // System.out.println("按键typed"+ e.getKeyChar());
    }

    // 按键按下事件响应函数,按键持续按下将会持续调用
    @Override
    public void keyPressed(KeyEvent e) {
        // System.out.println("按键按下"+ e.getKeyChar());
        // 当按键为A时,显示当前游戏图片对应的原始完整图片
        if (e.getKeyCode() == KeyEvent.VK_A) {
            this.getContentPane().removeAll();

            // 加载完整图片
            ImageIcon imageIcon = new ImageIcon( basePath + "all.jpg");
            JLabel jLabel = new JLabel(imageIcon);
            jLabel.setBounds(31, 82, 525, 525);
            this.getContentPane().add(jLabel);

            // 加载背景图片
            ImageIcon imageIcon2 = new ImageIcon("image\\background.png");
            JLabel jLabel2 = new JLabel(imageIcon2);
            jLabel2.setBounds(39, 40, imageIcon2.getIconWidth(), imageIcon2.getIconHeight());
            this.getContentPane().add(jLabel2);

            // 重绘窗口
            this.getContentPane().repaint();
        }

    }

    // 按键松开事件响应函数
    @Override
    public void keyReleased(KeyEvent e) {
        // System.out.println("按键松开"+ e.getKeyChar());
        // 当游戏胜利后无法再移动图片方块,但显示原始完整图片例外
        if (victory() && e.getKeyCode() != KeyEvent.VK_A){
            return;
        }

        // 根据上下左右不同按键更新图片方框
        switch (e.getKeyCode()) {
            case KeyEvent.VK_UP -> {
                // 向上移x值的边界条件为x等于3,无法再向上移动
                if (x < 3){
                    System.out.println("向上移动");
                    // 未到边界,交换空白方块和下方图片方块
                    this.data[x][y] = this.data[x + 1][y];
                    this.data[x + 1][y] = 0;
                    // 更新空白方块位置
                    x++;

                    // 更新游戏步数,同时更新图片方块位置
                    steps++;
                    initImage();
                } else {
                    System.out.println("无法向上移动");
                }
            }
            case KeyEvent.VK_DOWN -> {
                // 方块向下移动的边界条件为x等于0,此时无法再向下移动
                if (x > 0){
                    System.out.println("向下移动");
                    this.data[x][y] = this.data[x - 1][y];
                    this.data[x - 1][y] = 0;
                    x--;

                    steps++;
                    initImage();
                } else {
                    System.out.println("无法向下移动");
                }

            }
            case KeyEvent.VK_LEFT -> {
                // 方块左移的边界条件为y等于3,无法再左移
                if (y < 3){
                    System.out.println("向左移动");
                    this.data[x][y] = this.data[x][y + 1];
                    this.data[x][y + 1] = 0;
                    y++;

                    steps++;
                    initImage();
                } else {
                    System.out.println("无法向左移动");
                }
            }
            case KeyEvent.VK_RIGHT -> {
                // 方块右移的边界条件为y等于0,无法再右移
                if (y > 0){
                    System.out.println("向右移动");
                    this.data[x][y] = this.data[x][y - 1];
                    this.data[x][y - 1] = 0;
                    y--;

                    steps++;
                    initImage();
                } else {
                    System.out.println("无法向右移动");
                }
            }
            case KeyEvent.VK_A -> {
                // A键松开,重绘图片方块
                //System.out.println("A键松开");
                this.initImage();
            }
            case KeyEvent.VK_W -> {
                // System.out.println("点击了W");
                // W键松开,将图片方块序号更新为正确序号
                int count = 1;
                for (int i = 0; i < 4; i++) {
                    for (int j = 0; j < 4; j++) {
                        if (count < 16) {
                            this.data[i][j] = count++;
                        } else {
                            this.data[i][j] = 0;
                        }

                    }
                }
                // 重绘图片方块
                this.initImage();
            }
        }
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        // 获取点击事件来自于哪一个组件,用于执行不同的功能
        JMenuItem source = (JMenuItem) e.getSource();

        if (source == replayJMenuItem) {
            // 点击重新开始游戏菜单选项,更新步数、更新随机图片位置、初始化图片
            steps = 0;
            initData();
            initImage();
        } else if (source == reLoginJMenuItem) {
            // 点击退出登录菜单选项,设置当前窗口不显示,new一个登录窗口
            this.setVisible(false);
            new LoginJFrame().setVisible(true);
        } else if (source == exitJMenuItem) {
            // 系统退出菜单选项
            System.exit(0);
        } else if (source == weChatJMenuItem) {
            // 关于菜单选项
            System.out.println("Powered by ITHEIMA");
        } else if (source == animalJmenuItem){
            // 二级菜单动物类别选项
            // 更新图片类别,随机图片序号,清空游戏步数,重绘游戏界面
            imgType = "animal";
            imgNumber = rand.nextInt(imgNumbers[0]) + 1;
            System.out.println("animal" + imgNumber);
            steps = 0;
            initData();
            initImage();
        } else if (source == girlJmenuItem) {
            // 二级菜单美女类别选项
            imgType = "girl";
            imgNumber = rand.nextInt(imgNumbers[1]) + 1;
            System.out.println("girl" + imgNumber);
            steps = 0;
            initData();
            initImage();
        } else if (source == sportJmenuItem){
            // 二级菜单运动类别选项
            imgType = "sport";
            imgNumber = rand.nextInt(imgNumbers[2]) + 1;
            System.out.println("sport" + imgNumber);
            steps = 0;
            initData();
            initImage();
        }
    }
}
(4) 登录功能逻辑实现

完整代码如下,具体逻辑可查看注释,比较详尽

package com.test.ui;

import com.test.bean.Users;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.Random;

public class LoginJFrame extends JFrame implements MouseListener {
    // 图片素材位置成员变量
    String basePath = "image\\login\\";

    // 静态变量,记录所有的用户信息
    private static ArrayList<Users> usersList;

    // 登录JLabel
    JLabel loginJLabel;
    // 注册JLabel
    JLabel registerJLabel;
    // 显示密码JLabel
    JLabel showpasswordJLabel;
    // 正确验证码JLabel
    JLabel trueCodeJLabel;
    // 用户名输入框
    JTextField usernameJTextField;
    // 密码输入框
    JPasswordField jPasswordField;
    // 验证码输入框
    JTextField codeJTextField;

    // 记录随机验证码,由随机4个字母和一个数字构成,位置不固定
    String randomCode = "";

    // 静态构造代码块,用于初始化用户列表,同时添加一个默认账户
    static {
        usersList = new ArrayList<>();
        Users user = new Users("admin", "123456");
        usersList.add(user);
    }

    // 无参构造函数
    public LoginJFrame() {
        // 初始化登录窗口
        initFrame();

        // 初始化各个组件
        initComponent();
    }

    // 初始化窗口函数实现,各个代码含义同GameJFrame
    private void initFrame() {
        this.setSize(488, 430);
        this.setTitle("拼图游戏单机版 用户登录");
        // 不能设置当前窗口指定,否则不能显示提示信息窗口
        //this.setAlwaysOnTop(true);
        this.setLocationRelativeTo(null);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setLayout(null);

        this.setVisible(true);
    }

    // 初始化组件函数实现
    private void initComponent() {
        // 加载用户名文字图片
        ImageIcon usernameImageIcon = new ImageIcon(basePath + "用户名.png");
        // 使用JLabel放置图片
        JLabel usernameJLabel = new JLabel(usernameImageIcon);
        // 设置组件位置,大小
        usernameJLabel.setBounds(45, 118, 168, 63);
        // 设置用户名输入框
        usernameJTextField = new JTextField();
        usernameJTextField.setBounds(165, 135, 200, 30);
        // 将JLabel和用户名输入框添加进窗口
        this.getContentPane().add(usernameJLabel);
        this.getContentPane().add(usernameJTextField);

        // 添加密码文字图片以及密码输入框
        ImageIcon passwordImageIcon = new ImageIcon(basePath + "密码.png");
        JLabel passwordJLabel = new JLabel(passwordImageIcon);
        passwordJLabel.setBounds(45, 183, 168, 63);
        jPasswordField = new JPasswordField();
        jPasswordField.setBounds(165, 200, 200, 30);
        // 设置密码的密码符号为‘●’
        jPasswordField.setEchoChar('●');
        this.getContentPane().add(passwordJLabel);
        this.getContentPane().add(jPasswordField);

        // 添加显示密码图片以及对应的JLabel
        ImageIcon showPasswordImageIcon = new ImageIcon(basePath + "显示密码.png");
        showpasswordJLabel = new JLabel(showPasswordImageIcon);
        showpasswordJLabel.setBounds(355, 194, 40, 40);
        // 通过本类时间MouseListener各接口,同时添加接口用于实现点击效果
        showpasswordJLabel.addMouseListener(this);
        this.getContentPane().add(showpasswordJLabel);

        // 设置验证码文字图片,设置验证码输入框,设置正确的验证码
        ImageIcon codeImageIcon = new ImageIcon(basePath + "验证码.png");
        JLabel codeJLabel = new JLabel(codeImageIcon);
        codeJLabel.setBounds(45, 250, 168, 63);
        codeJTextField = new JTextField();
        codeJTextField.setBounds(165, 265, 130, 30);
        // 初始话一个随机验证码
        trueCodeJLabel = new JLabel(getRandomCode());
        trueCodeJLabel.setBounds(305, 248, 168, 63);
        // 设置对应的字体,显示更清楚
        trueCodeJLabel.setFont(new Font("Serif", Font.BOLD, 17));
        // 通过自带的MouseAdapter重写鼠标点击事件响应函数,实现点击验证码后更新验证码
        trueCodeJLabel.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                trueCodeJLabel.setText(getRandomCode());
            }
        });
        //codeJTextField.setText(randomCode); 方便测试,先默认添加上正确验证码,运行阶段删除
        this.getContentPane().add(codeJLabel);
        this.getContentPane().add(codeJTextField);
        this.getContentPane().add(trueCodeJLabel);

        // 设置登录按钮和注册按钮,通过JLabel实现
        ImageIcon loginImageIcon = new ImageIcon(basePath + "登录按钮.png");
        loginJLabel = new JLabel(loginImageIcon);
        loginJLabel.setBounds(80, 320, 128, 47);
        ImageIcon registerImageIcon = new ImageIcon(basePath + "注册按钮.png");
        registerJLabel = new JLabel(registerImageIcon);
        registerJLabel.setBounds(260, 320, 128, 47);
        // 添加监听器实现登录功能和注册界面跳转功能,同时通过点击和松开事件实现按钮的点击效果
        loginJLabel.addMouseListener(this);
        registerJLabel.addMouseListener(this);
        this.getContentPane().add(loginJLabel);
        this.getContentPane().add(registerJLabel);

        // 添加背景图片
        ImageIcon imageIcon = new ImageIcon(basePath + "background.png");
        JLabel jLabel = new JLabel(imageIcon);
        jLabel.setBounds(2, 0, imageIcon.getIconWidth(), imageIcon.getIconHeight());
        this.getContentPane().add(jLabel);

        // 重绘整个界面
        this.getContentPane().repaint();
    }

    // 获取5位随机验证码函数
    public String getRandomCode(){
        Random rand = new Random();

        // 将26个英文字母的全部大小添加进数组,便于随机获取
        char[] allLetters = new char[52];
        for (int i = 0; i < 52; i++) {
            if (i < 26){
                allLetters[i] = (char) (65 + i);
            } else {
                allLetters[i] = (char) (97 + i - 26);
            }
        }

        // 通过StringBuilder拼接字符串
        StringBuilder stringBuilder = new StringBuilder();
        // 随机获取5个位置中的1个,放置数字
        int numberIndex = rand.nextInt(5);
        for (int i = 0; i < 5; i++) {
            if (i == numberIndex){
                // 获取一个随机数放到对应位置
                stringBuilder.append(rand.nextInt(10));
            } else {
                // 随机获取一个字母
                stringBuilder.append(allLetters[rand.nextInt(allLetters.length)]);
            }
        }

        // 记录正确验证码,方便比对
        randomCode = stringBuilder.toString();

        // 返回验证码,用于显示
        return stringBuilder.toString();
    }

    // 重写鼠标点击事件响应函数
    @Override
    public void mouseClicked(MouseEvent e) {
        // 获取点击事件来自于哪一个组件,用于执行不同的功能
        JLabel jLabel = (JLabel) e.getSource();
        if (jLabel == loginJLabel) {
            // 当点击了登录按钮
            //System.out.println("鼠标点击了登录按钮");
            // 获取用户名以及密码以及输入的验证码
            String username = usernameJTextField.getText();
            String password = String.valueOf(jPasswordField.getPassword());
            String code = codeJTextField.getText();

            if (!code.equalsIgnoreCase(randomCode)) {
                // 验证码输入不正确
                String message = "验证码为空或输入有误,请重新输入!";
                JOptionPane.showMessageDialog(null, message, "提示" ,  JOptionPane.ERROR_MESSAGE);
                trueCodeJLabel.setText(getRandomCode());
                //codeJTextField.setText(randomCode);
            } else if (username.isEmpty() || password.isEmpty()){
                // 用户名或密码为空
                String msg = "请将账号信息填写完整!";
                JOptionPane.showMessageDialog(null, msg, "提示" ,  JOptionPane.ERROR_MESSAGE);
                trueCodeJLabel.setText(getRandomCode());
                //codeJTextField.setText(randomCode);
            } else {
                // 判断用户名密码是否正确
                boolean flag = false;

                // 判断用户名是否存,存在则继续判断是否正确
                for (Users user : usersList) {
                    if (username.equals(user.getUsername()) && password.equals(user.getPassword())) {
                        flag = true;
                        break;
                    }
                }

                if (flag) {
                    // 用户名存在且匹配正确
                    this.setVisible(false);
                    new GameJFrame().setVisible(true);
                    String msg = "登录成功!欢迎您," + username;
                    JOptionPane.showMessageDialog(null, msg, "提示" ,  JOptionPane.INFORMATION_MESSAGE);
                } else {
                    // 不存在用户名
                    String msg = "账号不存在或密码错误,请检查后登录!";
                    JOptionPane.showMessageDialog(null, msg, "提示", JOptionPane.ERROR_MESSAGE);
                    trueCodeJLabel.setText(getRandomCode());
                    //codeJTextField.setText(randomCode);
                }
            }
        } else if (jLabel == registerJLabel) {
            // 点击了注册按钮
            //System.out.println("鼠标点击了注册按钮");
            // 关闭当前窗口,new一个注册页面
            this.setVisible(false);
            new RegisterJFrame(usersList).setVisible(true);
        }
    }

    // 鼠标按钮按住事件
    @Override
    public void mousePressed(MouseEvent e) {
        JLabel jLabel = (JLabel) e.getSource();
        if (jLabel == loginJLabel) {
            //System.out.println("鼠标点击登录按钮");
            // 当为登录按钮,更换图片为按下图片
            ImageIcon imageIcon = new ImageIcon(basePath + "登录按下.png");
            loginJLabel.setIcon(imageIcon);
        } else if (jLabel == registerJLabel) {
            //System.out.println("鼠标点击注册按钮");
            // 当为注册按钮,更换图片为按下图片
            ImageIcon imageIcon = new ImageIcon(basePath + "注册按下.png");
            registerJLabel.setIcon(imageIcon);
        } else if (jLabel == showpasswordJLabel) {
            // 当为显示密码按钮,更换图片为显示密码按下图片
            ImageIcon imageIcon = new ImageIcon(basePath + "显示密码按下.png");
            showpasswordJLabel.setIcon(imageIcon);
            // 同时需要设置密码输入框的字符为明文
            jPasswordField.setEchoChar((char) 0);
        }
    }

    // 鼠标按钮松开事件
    @Override
    public void mouseReleased(MouseEvent e) {
        JLabel jLabel = (JLabel) e.getSource();
        if (jLabel == loginJLabel) {
            //System.out.println("鼠标松开登录按钮");
            // 松开登录按钮,更新为初始图片
            ImageIcon imageIcon = new ImageIcon(basePath + "登录按钮.png");
            loginJLabel.setIcon(imageIcon);
        } else if (jLabel == registerJLabel) {
            //System.out.println("鼠标松开注册按钮");
            // 松开注册按钮,更新为注册按钮
            ImageIcon imageIcon = new ImageIcon(basePath + "注册按钮.png");
            registerJLabel.setIcon(imageIcon);
        } else if (jLabel == showpasswordJLabel) {
            // 松开显示密码,更换为原始图片
            ImageIcon imageIcon = new ImageIcon(basePath + "显示密码.png");
            showpasswordJLabel.setIcon(imageIcon);
            // 同时将密码输入更新为密文
            jPasswordField.setEchoChar('●');
        }
    }

    // 鼠标划入事件
    @Override
    public void mouseEntered(MouseEvent e) {}

    // 鼠标划出事件
    @Override
    public void mouseExited(MouseEvent e) {}
}
(5)注册功能实现

完整代码如下,具体逻辑可查看注释,比较详尽。

package com.test.ui;

import com.test.bean.Users;
import com.test.Adapter.WindowAdapter;

import javax.swing.*;
import java.awt.event.*;
import java.util.ArrayList;

public class RegisterJFrame extends JFrame implements MouseListener{
    // 图像路径成员变量,记录图片位置
    String basePath = "image\\register\\";

    // 用户列表成员变量,记录所有用户
    private ArrayList<Users> usersList;

    // 注册JLabel
    JLabel registerJLabel;
    // 重置按钮JLabel
    JLabel resetJLabel;
    // 用户名输入框
    JTextField usernameJTextField;
    // 密码输入框
    JPasswordField jPasswordField;
    // 二次密码输入框
    JPasswordField reJPasswordField;

    // 构造函数,包含了用户列表参数,由用户登录界面传递过来,便于添加用户
    public RegisterJFrame(ArrayList<Users> usersList) {
        // 初始化用户列表
        this.usersList = usersList;

        // 初始化窗口
        initJFrame();

        // 初始话组件
        initComponent();
    }

    // 窗口初始化函数,各代码含义同另外GameJFrame
    private void initJFrame() {
        this.setSize(488, 430);
        this.setTitle("拼图游戏单机版 用户注册");
        //this.setAlwaysOnTop(true);
        this.setLocationRelativeTo(null);
        // 由于注册窗口需要返回登录界面,因此不能设置变比此窗口就关闭整个应用程序
        //this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setLayout(null);

        // 为当前窗口重写窗口关闭事件,关闭后重新返回登录界面
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                //super.windowClosing(e);
                new LoginJFrame().setVisible(true);
            }
        });

        this.setVisible(true);
    }

    // 窗口组件初始化函数
    private void initComponent() {
        // 注册用户名图片以及用户名输入框
        // 加载图片
        ImageIcon usernameImageIcon = new ImageIcon(basePath + "注册用户名.png");
        // 使用JLabel放置图片
        JLabel usernameJLabel = new JLabel(usernameImageIcon);
        // 设置组件位置大小
        usernameJLabel.setBounds(43, 118, 168, 63);
        // 设置用户名输入框同时设置大小
        usernameJTextField = new JTextField();
        usernameJTextField.setBounds(188, 135, 200, 30);
        // 添加组件到窗口
        this.getContentPane().add(usernameJLabel);
        this.getContentPane().add(usernameJTextField);

        // 添加注册密码图片以及密码输入框
        ImageIcon passwordImageIcon = new ImageIcon(basePath + "注册密码.png");
        JLabel passwordJLabel = new JLabel(passwordImageIcon);
        passwordJLabel.setBounds(43, 178, 168, 63);
        jPasswordField = new JPasswordField();
        jPasswordField.setBounds(188, 195, 200, 30);
        // 设置密码密文符号为'●'
        jPasswordField.setEchoChar('●');
        this.getContentPane().add(passwordJLabel);
        this.getContentPane().add(jPasswordField);

        // 设置二次密码输入框以及对应图片
        ImageIcon rePasswordImageIcon = new ImageIcon(basePath + "再次输入密码.png");
        JLabel rePasswordJLabel = new JLabel(rePasswordImageIcon);
        rePasswordJLabel.setBounds(43, 240, 168, 63);
        reJPasswordField = new JPasswordField();
        reJPasswordField.setBounds(188, 255, 200, 30);
        // 设置密码密文符号为'●'
        reJPasswordField.setEchoChar('●');
        this.getContentPane().add(rePasswordJLabel);
        this.getContentPane().add(reJPasswordField);

        // 类似LoginJFrame,设置注册按钮以及重置按钮
        ImageIcon registerImageIcon = new ImageIcon(basePath + "注册按钮.png");
        registerJLabel = new JLabel(registerImageIcon);
        registerJLabel.setBounds(80, 320, 128, 47);
        ImageIcon resetImageIcon = new ImageIcon(basePath + "重置按钮.png");
        resetJLabel = new JLabel(resetImageIcon);
        resetJLabel.setBounds(260, 320, 128, 47);
        // 绑定点击事件实现注册功能以及重置功能,绑定按住事件和松开事件,实现按钮点击效果
        registerJLabel.addMouseListener(this);
        resetJLabel.addMouseListener(this);
        this.getContentPane().add(registerJLabel);
        this.getContentPane().add(resetJLabel);

        // 添加背景图片
        ImageIcon imageIcon = new ImageIcon(basePath + "background.png");
        JLabel jLabel = new JLabel(imageIcon);
        jLabel.setBounds(2, 0, imageIcon.getIconWidth(), imageIcon.getIconHeight());
        this.getContentPane().add(jLabel);

        // 重绘窗口
        this.getContentPane().repaint();
    }

    // 鼠标点击事件
    @Override
    public void mouseClicked(MouseEvent e) {
        // 获取点击事件来自于哪一个组件,用于执行不同的功能
        JLabel jLabel = (JLabel) e.getSource();
        if (jLabel == registerJLabel) {
            // 点击注册按钮,实现注册功能
            // 获取用户名、密码以及二次密码
            String username = usernameJTextField.getText();
            String password = String.valueOf(jPasswordField.getPassword());
            String rePassword = String.valueOf(reJPasswordField.getPassword());

            if (username.isEmpty() || password.isEmpty() || rePassword.isEmpty()) {
                // 三者信息某一项为空
                String msg = "请将注册信息填写完整!";
                // 使用JOptionPane输出提示信息
                JOptionPane.showMessageDialog(null, msg, "提示", JOptionPane.ERROR_MESSAGE);
            } else {
                if (password.equals(rePassword)) {
                    // 两次密码输入一致
                    boolean flag = false;

                    // 判断账号是否存在
                    for (Users user : usersList) {
                        if (user.getUsername().equals(username)) {
                            flag = true;
                            break;
                        }
                    }

                    if (flag){
                        // 账号存在
                        String msg = "账号已存在,请重新输入!";
                        JOptionPane.showMessageDialog(null, msg, "提示", JOptionPane.ERROR_MESSAGE);
                    } else {
                        // 账号不存在,则往用户列表添加用户
                        usersList.add(new Users(username, password));
                        String msg = "账号(" + username + ")注册成功!\n关闭窗口以登录!";
                        JOptionPane.showMessageDialog(null, msg, "提示", JOptionPane.INFORMATION_MESSAGE);
                    }
                } else {
                    // 两次密码输入不一致
                    String msg = "两次输入的密码不一致,请重新输入!";
                    JOptionPane.showMessageDialog(null, msg, "提示", JOptionPane.ERROR_MESSAGE);
                }
            }
        } else if (jLabel == resetJLabel) {
            // 点击重置按钮,清空所有输入框中的信息
            //System.out.println("点击了重置按钮");
            usernameJTextField.setText("");
            jPasswordField.setText("");
            reJPasswordField.setText("");
        }
    }

    // 鼠标按住事件
    @Override
    public void mousePressed(MouseEvent e) {
        JLabel jLabel = (JLabel) e.getSource();
        if (jLabel == registerJLabel) {
            // 按住注册按钮,将图片更换为注册按下
            //System.out.println("点击注册按钮");
            ImageIcon imageIcon = new ImageIcon(basePath + "注册按下.png");
            registerJLabel.setIcon(imageIcon);
        } else if (jLabel == resetJLabel) {
            // 按住重置按钮,将图片更换为重置按下
            //System.out.println("点击重置按钮");
            ImageIcon imageIcon = new ImageIcon(basePath + "重置按下.png");
            resetJLabel.setIcon(imageIcon);
        }
    }

    // 鼠标松开事件
    @Override
    public void mouseReleased(MouseEvent e) {
        JLabel jLabel = (JLabel) e.getSource();
        if (jLabel == registerJLabel) {
            // 注册按钮松开,将图片更换为原始图片
            //System.out.println("松开注册按钮");
            ImageIcon imageIcon = new ImageIcon(basePath + "注册按钮.png");
            registerJLabel.setIcon(imageIcon);
        } else if (jLabel == resetJLabel) {
            // 重置按钮松开,将图片更换为原始图片
            //System.out.println("松开重置按钮");
            ImageIcon imageIcon = new ImageIcon(basePath + "重置按钮.png");
            resetJLabel.setIcon(imageIcon);
        }
    }

    // 鼠标划入事件
    @Override
    public void mouseEntered(MouseEvent e) {}

    // 鼠标划出事件
    @Override
    public void mouseExited(MouseEvent e) {}
}
(6)程序主入口
import com.test.ui.LoginJFrame;

public class APP {
    public static void main(String[] args) {
        new LoginJFrame();
    }
}

3、功能界面展示

(1)游戏界面

主界面

在这里插入图片描述

菜单页面

在这里插入图片描述

二级菜单页面

图片

(2)登录界面

图片

(3)注册界面

图片

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值