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)游戏界面
主界面
菜单页面
二级菜单页面