当前位置: 首页 > ops >正文

Java 黑马程序员(进阶篇1)

项目:拼图游戏

1. 主界面分析:

① GUI 图形化接口显示操作画面

  • JFrame:最外层的窗口
  • JMenuBar:最上层的菜单
  • JLable:管理文字和图片的容器

② 创建主界面(框架)

public class App {public static void main(String[] args) {new GameFrame();new LoginFrame();new RegisterFrame();}
}
package com.itheima.ui;import javax.swing.*;public class GameJFrame extends JFrame {public GameJFrame() {this.setSize(603,680);this.setVisible(true);}
}
package com.itheima.ui;import javax.swing.*;public class LoginJFrame extends JFrame {public LoginJFrame() {this.setSize(480,430);this.setVisible(true);}
}
package com.itheima.ui;import javax.swing.*;public class RegisterJFrame extends JFrame {public RegisterJFrame() {this.setSize(488,500);this.setVisible(true);}
}

② 运行结果:

三张页面按照输入的长宽像素大下运行自动弹出

2. 创建主界面(用继承的方法)

① 为什么使用继承改写?

(1) 自定义窗口类(如 GameFrame继承 javax.swing.JFrame,直接复用 JFrame 的功能,在子类构造方法中配置窗口属性(无需额外手动创建 JFrame 对象)。

(2) 不适用继承和使用继承的对比:

先看「不使用继承」的写法(手动创建 JFrame

// 第1个窗口
JFrame frame1 = new JFrame();
frame1.setSize(600, 500); // 重复写
frame1.setTitle("主窗口");
frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 重复写
frame1.setVisible(true);// 第2个窗口(设置窗口)
JFrame frame2 = new JFrame();
frame2.setSize(600, 500); // 再次重复写
frame2.setTitle("设置窗口");
frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 再次重复写
frame2.setVisible(true);// 第3个窗口(帮助窗口)
JFrame frame3 = new JFrame();
frame3.setSize(600, 500); // 第三次重复写
frame3.setTitle("帮助窗口");
frame3.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 第三次重复写
frame3.setVisible(true);
  • 问题setSizesetDefaultCloseOperation 等通用配置被重复写了 3 次,冗余且难维护(如果要改尺寸,3 处都要改)。
继承 JFrame 的子类方式:
// 子类中封装配置(只写一次)
public class MyFrame extends JFrame {public MyFrame(String title) { // 允许传入标题区分不同窗口this.setSize(600, 500); // 只写一次this.setTitle(title);this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 只写一次this.setVisible(true);}
}// 创建3个窗口时,直接复用子类的配置:
new MyFrame("主窗口");    // 自动应用 setSize 等配置
new MyFrame("设置窗口");  // 自动应用,无需重复写
new MyFrame("帮助窗口");  // 自动应用,无需重复写
  • 优势 1:setSize 等通用配置只在子类中写一次,后续创建任何窗口都自动生效(如果要改尺寸,只需改子类中的 setSize 一行代码),只需new 子类()就能自动复用这些配置,避免手动创建时 “每次都重复写配置代码” 的冗余。
  • 优势 2:主方法中只需 new GameFrame(),就能得到一个 “已经配置好的窗口”,无需再关心 “如何初始化 JFrame” 的细节。

(3) 代码示例与关键语句分析(以 “拼图游戏主界面” 为例)

import javax.swing.*;public class GameFrame extends JFrame {public GameFrame() {// 1. 设置窗口尺寸this.setSize(603, 680);  // 2. 设置窗口标题this.setTitle("拼图小游戏1.0");  // 3. 窗口置顶(始终显示在其他窗口上层)this.setAlwaysOnTop(true);  // 4. 窗口在屏幕中居中this.setLocationRelativeTo(null);  // 5. 点击关闭按钮时,终止整个程序this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);  // 6. 让窗口可见(Swing窗口默认不可见,必须显式设置)this.setVisible(true);  }
}

3. 菜单制作

import javax.swing.*;public class GameFrame extends JFrame {public GameFrame(){initJFrame();//初始化菜单//创建整个菜单对象initJMenuBar();this.setVisible(true);}private void initJMenuBar() {JMenuBar jMenuBar = new JMenuBar();//创建菜单对象//创建菜单选项对象JMenu functinonMenu = new JMenu("功能");JMenu aboutMenu = new JMenu("关于我们");//创建下面的条目对象JMenuItem replayItem = new JMenuItem("重新游戏");JMenuItem reloginItem = new JMenuItem("重新登陆");JMenuItem closeItem = new JMenuItem("关闭游戏");JMenuItem accountItem = new JMenuItem("公众号");//将条目对象添加到选项对象当中//添加功能条目对象到功能菜单当中functinonMenu.add(replayItem);functinonMenu.add(reloginItem);functinonMenu.add(closeItem);//添加公众号条目对象到关于菜单当中aboutMenu.add(accountItem);jMenuBar.add(functinonMenu);jMenuBar.add(aboutMenu);//给整个界面设置菜单this.setJMenuBar(jMenuBar);//将菜单展示在屏幕上}private void initJFrame() {this.setSize(603,680);this.setTitle("拼图小游戏1.0");this.setAlwaysOnTop(true);this.setLocationRelativeTo(null);}
}

4. 添加图片

package com.itheima.ui;import javax.swing.*;
import java.util.Random;public class GameJFrame extends JFrame {int[][] data = new int[4][4];public GameJFrame() {initData();initJFrame();initJMenuBar();initImage();this.setVisible(true);}private void initData() {int[] tempArr = {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 < tempArr.length; i++) {int index = r.nextInt(tempArr.length);int temp = tempArr[i];tempArr[i] = tempArr[index];tempArr[index] = temp;}for (int i = 0; i < tempArr.length; i++) {data[i / 4][i % 4] = tempArr[i];   //不太理解}}private void initImage() {for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++) {int num = data[i][j];JLabel jLabel = new JLabel(new ImageIcon("D:\\张锐彬\\Java练习\\day14-test\\src\\image\\animal\\animal3\\"+ num +".jpg"));jLabel.setBounds(105 * j, 105 * i, 105, 105);this.getContentPane().add(jLabel);   //不太理解}}}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);}private void initJFrame() {this.setSize(603,680);this.setTitle("拼图单机版 v1.0");this.setAlwaysOnTop(true);this.setLocationRelativeTo(null);this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);this.setLayout(null);}
}

关键逻辑:

先执行 initData() 生成随机数据,再执行 initImage() 根据数据加载图片:

  • initData() 会创建一个包含 0~15 的一维数组,打乱后存入 4x4 的 data 数组(data[i][j] 存储的是随机数字)。
  • 执行前data 是 int[4][4] 类型的数组,int 类型数组的默认值是 0,所以此时 data 中所有元素都是 0
  • 执行后data 中充满了 0~15 的随机数字(比如 data[0][0]=5data[0][1]=12 等)。
  • initImage() 必须知道 data[i][j] 具体是什么数字,才能加载正确的图片。

5. 打乱图片

题目:数组打乱与二维数组转换

需求说明:

请编写一个 Java 程序,实现以下功能:

(1) 创建一个包含整数 0~15(共 16 个元素)的一维数组;

(2) 使用随机打乱算法(洗牌算法)将该一维数组的元素顺序打乱;

(3) 将打乱后的一维数组转换为 4 行 4 列的二维数组(int[4][4]);

按以下格式输出结果:

  • 第一行:打印打乱后的一维数组元素(元素间用空格分隔);
  • 接下来 4 行:打印转换后的二维数组,每行元素用空格分隔,每行单独占一行。
package Test;import java.util.Random;public class test1 {public static void main(String[] args) {int[] tempArr = {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 < tempArr.length; i++) {int index = r.nextInt(tempArr.length);int temp = tempArr[i];tempArr[i] = tempArr[index];tempArr[index] = temp;}for (int i = 0; i < tempArr.length; i++) {System.out.print(tempArr[i] + " ");}System.out.println();int[][] data = new int[4][4];for (int i = 0; i < tempArr.length; i++) {data[i / 4][i % 4] = tempArr[i];   //不太理解}for (int i = 0; i < data.length; i++) {for (int j = 0; j < data.length; j++) {System.out.print(data[i][j] + " ");}System.out.println();}}
}

关键逻辑:

data[i / 4][i % 4] = tempArr[i];

① 用「整数除法 i / 4」确定 “行索引”

  • 当 i = 0,1,2,3 时,i / 4 = 0 → 对应二维数组的第 0 行
  • 当 i = 4,5,6,7 时,i / 4 = 1 → 对应二维数组的第 1 行
  • 当 i = 8,9,10,11 时,i / 4 = 2 → 对应二维数组的第 2 行
  • 当 i = 12,13,14,15 时,i / 4 = 3 → 对应二维数组的第 3 行

② 用「取余运算 i % 4」确定 “列索引”

  • 当 i = 0,4,8,12 时,i % 4 = 0 → 对应每行的第 0 列
  • 当 i = 1,5,9,13 时,i % 4 = 1 → 对应每行的第 1 列
  • 当 i = 2,6,10,14 时,i % 4 = 2 → 对应每行的第 2 列
  • 当 i = 3,7,11,15 时,i % 4 = 3 → 对应每行的第 3 列
http://www.xdnf.cn/news/19797.html

相关文章:

  • 从BERT到RoBERTa、ALBERT:揭秘Encoder-only预训练模型的进化之路
  • 【常用SQL语句和语法总结】
  • 数据科学家如何更好地展示自己的能力
  • 项目中 Spring Boot 配置文件未生效该如何解决
  • JavaScript箭头函数与普通函数:两种工作方式的深度解析
  • 诊断服务器(Diagnostic Server)
  • Linux 字符设备驱动框架学习记录(三)
  • Spring Boot 全局异常处理问题分析与解决方案
  • PastePal for Mac 剪贴板历史记录管理器
  • prometheus+grafana搭建
  • 7.4Element Plus 分页与表格组件
  • js设计模式-装饰器模式
  • CI(持续集成)、CD(持续交付/部署)、CT(持续测试)、CICD、CICT
  • Few-Shot Prompting 实战:用5个例子让GPT-4学会复杂任务
  • (二)文件管理-基础命令-cd命令的使用
  • 中州养老:资源添加功能
  • gitlab推送失败,内存不足的处理
  • 深入浅出Spring IoC与DI:设计思想、实现方式与反射技术详解
  • Excel 电影名匹配图片路径教程:自动查找并写入系统全路径
  • PostgreSQL 中唯一索引的工作原理
  • 分布式AI算力系统番外篇-----超体的现实《星核》
  • Vue基础知识-重要的内置关系:vc实例.__proto__.__proto__ === Vue.prototype
  • 股指期货可以通过移仓长线持有吗?
  • AppInventor2 如何自定义包名?
  • 华为云云原生架构赋能:大腾智能加速业务创新步伐
  • 【深度学习新浪潮】视觉大模型在预训练方面有哪些关键进展?
  • 鸿蒙UI开发实战:解决布局错乱与响应异常
  • 企业实用——MySQL的备份详解
  • 基于机器学习的Backtrader波动性预测与管理
  • Kubernetes ConfigMap 更新完整指南:原理、方法与最佳实践