一 JFrame类创建界面 initJFrame();
1 创建JFrame类的窗口对象;
2 初始化界面:大小;标题;置顶;界面居中;关闭模式;取消组件居中以启用坐标轴;显示窗口;等等。
private void initJFrame() {
// 设置界面的大小
this.setSize(420,500);
// 设置界面标题
this.setTitle("拼图单机版 v1.0");
// 设置界面置顶
this.setAlwaysOnTop(true);
// 设置界面居中
this.setLocationRelativeTo(null);
//设置关闭模式
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
//取消图片的默认居中放置,只有取消了才会按照xy轴的形式添加组件
this.setLayout(null);
}
二 初始化菜单 initJMenuBar();
1 创建菜单对象;
2 创建选项对象;
3 创建条目对象;
4 将条目添加到选项中,选项添加到菜单中;
5 在窗口对象中设置JMenuBar。
private void initJMenuBar() {
// 创建整个菜单对象
JMenuBar JMenuBar = new JMenuBar();
// 创建菜单上面两个选项对象
JMenu functionJMenu = new JMenu("功能");
JMenu aboutJMenu = new JMenu("关于我们");
// 创建选项下面的条目对象
JMenuItem replayItem = new JMenuItem("重新游戏");
JMenuItem reLoginItem = new JMenuItem("重新登录");
JMenuItem closeItem = new JMenuItem("关闭游戏");
JMenuItem accountItem = new JMenuItem("公众号");
functionJMenu.add(replayItem);
functionJMenu.add(reLoginItem);
functionJMenu.add(closeItem);
aboutJMenu.add(accountItem);
JMenuBar.add(functionJMenu);
JMenuBar.add(aboutJMenu);
this.setJMenuBar(JMenuBar);
}
三 添加图片
涉及类:ImageIcon; Jlabel
概括说,创建一个ImageIcon类的图片对象,并指定图片在电脑中的位置;再创建一个Jabel对象,把图片交给Jlabel;再把整体放到界面中。
图片文件夹添加到当前模块下;设计打乱图片的方法;打乱图片;在界面的不同位置放置这些图片。
1 创建ImageIcon的对象;
2 创建JLabel的对象(管理容器);
3 指定图片位置
4 添加管理容器到界面中,getContentPane()可以理解为获取界面的隐藏容器。
int[][] data = new int[4][4];
private void initData() {
int[] temp = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
Random r = new Random();
for (int i = 0; i < 16; i++) {
int index = r.nextInt(temp.length);
int value = temp[i];
temp[i] = temp[index];
temp[index] = value;
}
for (int i = 0; i < 16; i++) {
data[i/4][i%4]= temp[i];
}
}
private void initImage() {
int number=1;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
// 创建一个图片ImageIcon的对象
ImageIcon Icon = new ImageIcon("D:\\JavaLearning\\JavaLearning_1\\puzzlegame\\image\\girl\\girl1\\"+data[i][j]+".jpg");
number++;
//创建一个JLabel的对象(管理容器)
JLabel label = new JLabel(Icon);
//指定图片位置
label.setBounds(105*i,105*j,105,105);
//把管理容器添加到界面中,getContentPane()可以理解为获取界面的隐藏容器
this.getContentPane().add(label);
}
}
}
四 事件
事件是可以被组件识别的操作
1 事件源:按钮,图片,窗体等。
2 事件: 对事件源的操作,如鼠标单击,鼠标划入等。
3 绑定监听:当事件源上发生了某个事件,则执行某段代码。
(1)KeyListener:键盘监听,
细节:
a addKeyListener()方法的调用者是窗口对象,参数时接口KeyListener的实现类。
b 如果按下一个键不松开,会重复调用Keypressed方法;
c e.getKeyCode()表示获取键盘上每一个按键的编号
(2)MouseListener:鼠标监听;
(3)ActionListener:动作监听
单击或者空格触发。
4 流程:
(1)创建一个按钮对象;
(2)并设置位置和宽高;
(3)给按钮对象设置监听并以参数的形式传递事件触发后执行的代码;
(4)把按钮添加到界面当中。
5 两种在界面中添加事件的方式
(1)以匿名内部类的方式将ActionListener的实现类作为参数传递给绑定监听方法(如ActionListener())。
public class test {
public static void main(String[] args) {
JFrame jf = new JFrame();
jf.setSize(500, 500);
jf.setTitle("添加事件的方式一");
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭即退出
jf.setLocationRelativeTo(null);//居中
jf.setLayout(null);//取消组件的默认居中
jf.setAlwaysOnTop(true);//置顶显示
//设置按钮的范围,绑定监听
JButton b1 = new JButton("点我!");
b1.setBounds(0, 0, 100, 100);
b1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("不要点我!!");
}
});
jf.getContentPane().add(b1);//在窗口界面添加按钮
jf.setVisible(true);
}
}
不要点我!!
(2)将本类(JFrame)对象实现ActionListener接口后作为实现类传递给绑定监听方法(如ActionListener())。
public class MyJFrame extends JFrame implements ActionListener {
JButton button1;
JButton button2;
public MyJFrame() {
//初始化窗口
this.setSize(500, 500);
this.setTitle("添加事件的方式二");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭即退出
this.setLocationRelativeTo(null);//居中
this.setLayout(null);//取消组件的默认居中
this.setAlwaysOnTop(true);//置顶显示
//新建两个按钮对象
button1 = new JButton("你点我就变大");
button2 = new JButton("你点我就跳");
//设置按钮大小
button1.setBounds(0,0,150,150);
button2.setBounds(250,250,100,100);
//由于本类实现了ActionListener接口,所以本类对象可以作为addActionListener()的参数,
// 在事件触发时执行本类中的actionPerformed()方法。
button1.addActionListener(this);
button2.addActionListener(this);
//在我的窗口界面中添加这两个按钮
this.getContentPane().add(button1);
this.getContentPane().add(button2);
//显示窗口
this.setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
//getSource()获取当前被操作的按钮对象,e为事件,返回发生事件的对象
Object source = e.getSource();
if (source == button1) {
button1.setSize(200,200);
}
else if (source == button2) {
Random r = new Random();
button2.setLocation(r.nextInt(500),r.nextInt(500));
}
}
}
public class MyTest {
public static void main(String[] args) {
new MyJFrame();
}
}
五 移动图片
重要步骤:
1 在界面初始化函数中写好事件接口
2 事件:松开键盘的上下左右键;
触发代码(keyReleased):以向上移动为例,空白格位置变成它下面的图片;
3 在每次利用ImageIcon和JLabel添加图片之前,要清空之前的图片,否则无法更新图片;并且每次更新完图片要进行刷新。
4 对于超出范围的情况要做处理。
六 查看完整图片
七 作弊码
八 判断胜利
九 计步功能
十 菜单业务实现
1 重新游戏
2 重新登录
3 关闭游戏
4 公众号
十一 最终代码呈现
主函数
package com.byc.ui;
public class App {
public static void main(String[] args) {
//表示程序的启动入口,需要显示哪个界面就创建哪个对象
//创建登录界面的对象
new LoginJFrame();
// 创建主界面的对象
//new GameJFrame();
// //创建注册界面的对象
// new RegisterJFrame();
}
}
游戏界面
package com.byc.ui;
import javax.swing.*;
import javax.swing.border.BevelBorder;
import java.awt.event.*;
import java.util.Random;
public class GameJFrame extends JFrame implements KeyListener,ActionListener {
int[][] data = new int[4][4];
// 记录空白方块的位置
int x;
int y;
// 记录步数
int count;
int number;
// 创建选项下面的条目对象
JMenuItem replayItem = new JMenuItem("重新游戏");
JMenuItem reLoginItem = new JMenuItem("重新登录");
JMenuItem closeItem = new JMenuItem("关闭游戏");
JMenuItem ladyItem = new JMenuItem("美女");
JMenuItem animalItem = new JMenuItem("动物");
JMenuItem sportItem = new JMenuItem("运动");
JMenuItem accountItem = new JMenuItem("公众号");
int[][] winData = {
{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,0}
};
String path = "puzzlegame\\image\\animal\\animal1\\";
public GameJFrame(){
// 初始化界面
initJFrame();
// 初始化菜单
initJMenuBar();
// 初始化数据(打乱图片)
initData();
// 初始化图片(加载打乱的图片)
initImage();
// 显示界面
this.setVisible(true);
}
private void initJFrame() {
// 设置界面的大小
this.setSize(603,680);
// 设置界面标题
this.setTitle("拼图单机版 v1.0");
// 设置界面置顶
this.setAlwaysOnTop(true);
// 设置界面居中
this.setLocationRelativeTo(null);
//设置关闭模式
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
//取消图片的默认居中放置,只有取消了才会按照xy轴的形式添加组件
this.setLayout(null);
//给整个界面调用键盘监听事件
this.addKeyListener(this);
}
private void initJMenuBar() {
// 创建整个菜单对象
JMenuBar JMenuBar = new JMenuBar();
// 创建菜单上面两个选项对象
JMenu functionJMenu = new JMenu("功能");
JMenu aboutJMenu = new JMenu("关于我们");
JMenu changePictureJMenu = new JMenu("更换图片");
// 给每个条目绑定监听
replayItem.addActionListener(this);
reLoginItem.addActionListener(this);
closeItem.addActionListener(this);
accountItem.addActionListener(this);
ladyItem.addActionListener(this);
animalItem.addActionListener(this);
sportItem.addActionListener(this);
functionJMenu.add(changePictureJMenu);
changePictureJMenu.add(ladyItem);
changePictureJMenu.add(animalItem);
changePictureJMenu.add(sportItem);
functionJMenu.add(replayItem);
functionJMenu.add(reLoginItem);
functionJMenu.add(closeItem);
aboutJMenu.add(accountItem);
JMenuBar.add(functionJMenu);
JMenuBar.add(aboutJMenu);
this.setJMenuBar(JMenuBar);
}
private void initData() {
int[] temp = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
Random r = new Random();
for (int i = 0; i < 16; i++) {
int index = r.nextInt(temp.length);
int value = temp[i];
temp[i] = temp[index];
temp[index] = value;
}
for (int i = 0; i < 16; i++) {
if(temp[i] == 0){
x = i/4;
y = i%4;
}
data[i/4][i%4]= temp[i];
}
}
private void initImage() {
this.getContentPane().removeAll() ;
//如果胜利,添加胜利图标
if(IsVictory()){
JLabel winLabel = new JLabel(new ImageIcon("puzzlegame\\image\\win.png"));
winLabel.setBounds(203, 283, 197,73);
this.add(winLabel);
}
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
// 创建一个图片ImageIcon的对象
ImageIcon Icon = new ImageIcon(path+data[i][j]+".jpg");
//创建一个JLabel的对象(管理容器)
JLabel label = new JLabel(Icon);
//指定图片位置
label.setBounds(105*j+83,105*i+134,105,105);
//给图片添加边框
label.setBorder(new BevelBorder(0));
//把管理容器添加到界面中,getContentPane()可以理解为获取界面的隐藏容器
this.getContentPane().add(label);
}
}
//添加步数记录
JLabel countLabel = new JLabel("步数"+count);
countLabel.setBounds(50, 30, 100,20);
this.getContentPane().add(countLabel);
//添加背景图片
//注意:先加载的图片在上方,后加载的图片在下方
ImageIcon background = new ImageIcon("puzzlegame\\image\\background.png");
JLabel backgroundLabel = new JLabel(new ImageIcon("puzzlegame\\image\\background.png"));
backgroundLabel.setBounds(40, 40, background.getIconWidth(), background.getIconHeight());
this.getContentPane().add(backgroundLabel);
//刷新一下界面
this.getContentPane().repaint();
}
private boolean IsVictory() {
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i].length; j++) {
if(data[i][j] != winData[i][j]){
return false;
}
}
}
return true;
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
//按下不松的时候显示完整图片
public void keyPressed(KeyEvent e) {
//如果胜利,直接结束触发行为
if(IsVictory()){
return;
}
int pressedNum = e.getKeyCode();
if(pressedNum == 65){
this.getContentPane().removeAll() ;
// 创建一个图片ImageIcon的对象
ImageIcon Icon = new ImageIcon(path+"all.jpg");
//创建一个JLabel的对象(管理容器)
JLabel label = new JLabel(Icon);
//指定图片位置
label.setBounds(83,134,420,420);
//给图片添加边框
label.setBorder(new BevelBorder(0));
//把管理容器添加到界面中,getContentPane()可以理解为获取界面的隐藏容器
this.getContentPane().add(label);
//添加背景图片
//注意:先加载的图片在上方,后加载的图片在下方
ImageIcon background = new ImageIcon("puzzlegame\\image\\background.png");
JLabel backgroundLabel = new JLabel(new ImageIcon("puzzlegame\\image\\background.png"));
backgroundLabel.setBounds(40, 40, background.getIconWidth(), background.getIconHeight());
this.getContentPane().add(backgroundLabel);
//刷新一下界面
this.getContentPane().repaint();
}
}
@Override
public void keyReleased(KeyEvent e) {
//如果胜利,直接结束触发行为
if(IsVictory()){
return;
}
//对上下左右进行判断; 左:37 上:38 右:39 下:40
int code = e.getKeyCode();
//System.out.println(code);
if(code == 37){
if(y==3){
return;
}
System.out.println("向左移动");
data[x][y] = data[x][y+1];
data[x][y+1] = 0;
y++;
//步数自增
count++;
}
else if(code == 38){
if(x==3){
return;
}
System.out.println("向上移动");
data[x][y] = data[x+1][y];
data[x+1][y] = 0;
x++;
//步数自增
count++;
}
else if(code == 39){
if(y==0){
return;
}
System.out.println("向右移动");
data[x][y] = data[x][y-1];
data[x][y-1] = 0;
y--;
//步数自增
count++;
}
else if(code == 40){
if(x==0){
return;
}
System.out.println("向下移动");
data[x][y] = data[x-1][y];
data[x-1][y] = 0;
x--;
//步数自增
count++;
}else if(code == 87){
//按下w(87),一键速通
data = new int[][]{
{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,0}
};
}
initImage();
}
@Override
public void actionPerformed(ActionEvent e) {
//获取事件发生的条目
Object source = e.getSource();
if(source == replayItem){
System.out.println("重新游戏");
count = 0;
initData();
initImage();
}
else if(source == reLoginItem){
System.out.println("重新登录");
this.setVisible(false);
new LoginJFrame();
}
else if(source == closeItem){
System.out.println("关闭游戏");
System.exit(0);
}
else if(source == accountItem){
System.out.println("关于我们");
//创建一个弹窗对象
JDialog dialog = new JDialog();
//创建一个图片容器对象
JLabel label = new JLabel(new ImageIcon("puzzlegame\\image\\about.png"));
//设置容器在弹窗中的位置和宽高
label.setBounds(0,0,258,258);
//设置弹窗大小
dialog.setSize(344,344); ;
//将容器添加到弹窗中
dialog.getContentPane().add(label);
//设置置顶
dialog.setAlwaysOnTop(true);
//设置弹窗居中
dialog.setLocationRelativeTo(null);
//不关闭则无法操作
dialog.setModal(true) ;
//显示
dialog.setVisible(true);
}
else if(source == ladyItem){
System.out.println("更换美女图片");
Random r = new Random();
number = r.nextInt(13)+1;
path = "puzzlegame\\image\\girl\\girl"+number+"\\";
count = 0;
initData();
initImage();
}
else if(source == animalItem){
System.out.println("更换动物图片");
Random r = new Random();
number = r.nextInt(8)+1;
path = "puzzlegame\\image\\animal\\animal"+number+"\\";
count = 0;
initData();
initImage();
}
else if(source == sportItem){
System.out.println("更换运动图片");
Random r = new Random();
number = r.nextInt(10)+1;
path = "puzzlegame\\image\\sport\\sport"+number+"\\";
count = 0;
initData();
initImage();
}
}
}
登陆界面
package com.byc.ui;
import javax.swing.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.Objects;
public class LoginJFrame extends JFrame implements MouseListener {
//创建一个集合存储正确的用户名和密码
static ArrayList<User> list = new ArrayList<>();
static {
list.add(new User("zhangsan","123"));
list.add(new User("lisi","1234"));
}
JButton login = new JButton();
JButton register = new JButton();
//创建两个路径用于记录登陆与注册按钮图片的位置
private String pathLogin = "puzzlegame\\image\\login\\登录按钮.png";
private String pathRegister = "puzzlegame\\image\\login\\注册按钮.png";
JTextField username;
JTextField password;
JTextField code;
JLabel rightCode;
public LoginJFrame() {
//初始化界面
initJFrame();
//在这个界面中添加内容
initView();
//让当前界面显示出来
this.setVisible(true);
}
public void initView() {
this.getContentPane().removeAll();
//1. 添加用户名文字
JLabel usernameText = new JLabel(new ImageIcon("puzzlegame\\image\\login\\用户名.png"));
usernameText.setBounds(116, 135, 47, 17);
this.getContentPane().add(usernameText);
//2.添加用户名输入框
username = new JTextField();
username.setBounds(195, 134, 200, 30);
this.getContentPane().add(username);
//3.添加密码文字
JLabel passwordText = new JLabel(new ImageIcon("puzzlegame\\image\\login\\密码.png"));
passwordText.setBounds(130, 195, 32, 16);
this.getContentPane().add(passwordText);
//4.密码输入框
password = new JTextField();
password.setBounds(195, 195, 200, 30);
this.getContentPane().add(password);
//验证码提示
JLabel codeText = new JLabel(new ImageIcon("puzzlegame\\image\\login\\验证码.png"));
codeText.setBounds(133, 256, 50, 30);
this.getContentPane().add(codeText);
//验证码的输入框
code = new JTextField();
code.setBounds(195, 256, 100, 30);
this.getContentPane().add(code);
String codeStr = CodeUtil.getCode();
rightCode = new JLabel();
//设置内容
rightCode.setText(codeStr);
//位置和宽高
rightCode.setBounds(300, 256, 50, 30);
//添加到界面
this.getContentPane().add(rightCode);
//5.添加登录按钮
login.setBounds(123, 310, 128, 47);
login.setIcon(new ImageIcon(pathLogin));
//去除按钮的默认边框
login.setBorderPainted(false);
//去除按钮的默认背景
login.setContentAreaFilled(false);
login.addMouseListener(this);
this.getContentPane().add(login);
//6.添加注册按钮
register.setBounds(256, 310, 128, 47);
register.setIcon(new ImageIcon(pathRegister));
//去除按钮的默认边框
register.setBorderPainted(false);
//去除按钮的默认背景
register.setContentAreaFilled(false);
register.addMouseListener(this);
this.getContentPane().add(register);
//7.添加背景图片
JLabel background = new JLabel(new ImageIcon("puzzlegame\\image\\login\\background.png"));
background.setBounds(0, 0, 470, 390);
this.getContentPane().add(background);
this.getContentPane().repaint();
}
public void initJFrame() {
this.setSize(488, 430);//设置宽高
this.setTitle("拼图游戏 V1.0登录");//设置标题
this.setDefaultCloseOperation(3);//设置关闭模式
this.setLocationRelativeTo(null);//居中
this.setAlwaysOnTop(true);//置顶
this.setLayout(null);//取消内部默认布局
}
//要展示用户名或密码错误
public void showJDialog(String content) {
//创建一个弹框对象
JDialog jDialog = new JDialog();
//给弹框设置大小
jDialog.setSize(200, 150);
//让弹框置顶
jDialog.setAlwaysOnTop(true);
//让弹框居中
jDialog.setLocationRelativeTo(null);
//弹框不关闭永远无法操作下面的界面
jDialog.setModal(true);
//创建Jlabel对象管理文字并添加到弹框当中
JLabel warning = new JLabel(content);
warning.setBounds(0, 0, 200, 150);
jDialog.getContentPane().add(warning);
//让弹框展示出来
jDialog.setVisible(true);
}
@Override
public void mouseClicked(MouseEvent e) {
Object button = e.getSource();
if(button==login){
String usernameInput = username.getText();
String passwordInput = password.getText();
String codeInput = code.getText();
if(!codeInput.equalsIgnoreCase(rightCode.getText())){
System.out.println("验证码输入错误");
showJDialog("验证码输入错误");
String newCode = CodeUtil.getCode();
rightCode.setText(newCode);
username.setText("");
password.setText("");
code.setText("");
}
else if(usernameInput.isEmpty() || passwordInput.isEmpty()){
System.out.println("用户名和密码不能为空");
showJDialog("用户名和密码不能为空");
username.setText("");
password.setText("");
code.setText("");
}
else {
User user = new User(usernameInput,passwordInput);
if(!IsContain(list,user)){
System.out.println("用户名密码错误");
showJDialog("用户名密码错误");
username.setText("");
password.setText("");
code.setText("");
}
else{
this.setVisible(false);
new GameJFrame();
}
}
}
else if(button==register){
System.out.println("进入注册界面");
}
}
private boolean IsContain(ArrayList<User> list, User user) {
for (int i = 0; i < list.size(); i++) {
if(list.get(i).username.equals(user.username)&&list.get(i).password.equals(user.password)){
return true;
}
}
return false;
}
@Override
public void mousePressed(MouseEvent e) {
// 按下不松,切换登陆按钮的背景图片
System.out.println("按下不松");
Object button = e.getSource();
if(button==login){
login.setIcon(new ImageIcon("puzzlegame\\image\\login\\登录按下.png"));
}
else if(button==register){
register.setIcon(new ImageIcon("puzzlegame\\image\\login\\注册按下.png"));
}
}
@Override
public void mouseReleased(MouseEvent e) {
// 松开
// 切换登陆按钮的背景图片
System.out.println("松开");
Object button = e.getSource();
if(button==login){
login.setIcon(new ImageIcon("puzzlegame\\image\\login\\登录按钮.png"));
}
else if(button==register){
register.setIcon(new ImageIcon("puzzlegame\\image\\login\\注册按钮.png"));
}
//
}
@Override
public void mouseEntered(MouseEvent e) {
//滑入
System.out.println("划入");
}
@Override
public void mouseExited(MouseEvent e) {
//
System.out.println("mouseExited");
}
}
工具类
package com.byc.ui;
import java.util.ArrayList;
import java.util.Random;
public class CodeUtil {
public static String getCode(){
// 随机生成5位的验证码,其中有一个数字和四个大小写字母
// 思路1:先生成4个字母,再生成1个数字,然后将这5个字符打乱(我用的这个)
// 思路2:先生成4个字母,再生成1个数字,然后将这个数字随机与0-4的索引的字符交换
// 思路3;先生成5个字母,再随机将其中一个替换为数字
StringBuilder stringBuilder = new StringBuilder();
ArrayList<Character> charList = new ArrayList<>();
Random r = new Random();
//创建字母集合
for (int i = 0; i < 26; i++) {
charList.add((char)('a'+i));
charList.add((char)('A'+i));
}
// 从集合中随机取出四个字母到stringBuilder中
for (int i = 0; i < 4; i++) {
int index = r.nextInt(charList.size());
stringBuilder.append(charList.get(index));
}
//再添加一个数字
int number = r.nextInt(10);
stringBuilder.append(number);
//打乱stringBuilder
for (int i = 0; i < stringBuilder.length(); i++) {
int num = r.nextInt(stringBuilder.length());
char temp = stringBuilder.charAt(i);
stringBuilder.setCharAt(i, stringBuilder.charAt(num));
stringBuilder.setCharAt(num,temp);
}
return stringBuilder.toString();
}
}