第一章 项目简介&创建主窗体
零、项目简介
《羊了个羊》是一款由北京简游科技有限公司开发的休闲类益智游戏,于2022年6月13日正式发行,玩家可以通过微信小程序游玩。 该作主要是让玩家利用各种道具和提示来消除每一个关卡当中的障碍和陷阱。游戏第一关其实是玩法教程,但当玩家来到第二关时,难度直线上升。
玩家们在点击游戏上方卡牌后卡牌会下移到底部的框中,栏框内一共可以储存7张卡牌,当有3张一样的卡牌时将会消除,比如:三个一样的羊毛球则可以达成消除。当场面上没有能够达成3消的卡牌时,玩家可以观察位于下层暂时无法使用的卡牌,在点击上层卡牌后,下方的卡牌便可以使用了(如图中红圈内的白菜),这样玩家就能消除一组白菜,但是在使用这个技巧时要避免手中无用卡牌堆积起来最终导致游戏失败。
游戏中一共有三个道具,每个道具每局可以用一次,通过这个机制以及下方的三个道具和一次复活的机会,一起配合过关。
通过随机算法生成的算法也非常难!
开发环境
IDEA 2023.2.x版本,下载地址
一、本章目标
完成创建羊了个羊游戏窗体并加载一张牌。效果如下图所示:
核心代码:
java
public class StartGame extends JFrame {
private Brand brand = new Brand("刷子");
public StartGame() {
this.setTitle("云和数据版-羊了个羊");
this.setSize(450,800);
this.setLocationRelativeTo(null);//居中
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//添加组件的方法,可以添加自己定义的组件都当前的窗口中
this.getContentPane().add(brand,BorderLayout.CENTER);
this.setResizable(false);
this.setVisible(true);
//启动自动刷新线程
autoRefresh();
}
//等等
二、涉及知识点
(一)java面向对象------继承
(二)java Swing编程
(三)java IO编程
三、知识点讲解
(一)java面向对象------继承
1、继承概述
WHY: 多个类中存在相同属性和行为时,(重复的代码)将这些内容抽取到单独一个类中,这个类就是父类,那么多个子类无需再定义这些属性和行为,只要 继承那一个类即可。如图所示:
其中,多个类可以称为子类 ,单独那一个类称为父类 、超类(superclass)或者 基类。
继承描述的是事物之间的所属关系,这种关系是: is-a 的关系。例如,图中兔子属于食草动物,食草动物属于动
物。可见,父类更通用,子类更具体。我们通过继承,可以使多种事物之间形成一种关系体系。
HOW: 子类 extends 父类
2、继承概念
继承 :就是子类继承父类的属性 和行为,使得子类对象具有与父类相同的属性、相同的行为。子类可以直接
访问父类中的非私有的属性和方法。
面相对象三大特征:封装(安全性)、继承(复用性)、多态(可扩展性)
思维方式、认知、
3、继承的特点
子类自动拥有父类非私有的成员
子类也可以拥有自己的成员
4、继承的好处
提高代码的复用性。
类与类之间产生了关系,是多态的前提。
5、继承的格式
通过 extends 关键字,可以声明一个子类继承另外一个父类,定义格式如下:
格式
java
class 父类 { ... }
class 子类 extends 父类 { ... }
代码演示
java
//父类
public class Person {
private String name;
public void eat(){
System.out.println("吃饭");
}
public void sleep(){
System.out.println("睡觉");
}
}
再新建一个Student.java类,继承Person类;
java
//子类
public class Student extends Person {
private String name;
}
再新建一个Teacher.java类,继承Person类;
java
//子类
public class Teacher extends Person {
private String name;
}
再新建一个测试类PersonTest.java, 可以运行的。
java
/*
* 定义测试类
*/
public class PersonTest {
public static void main(String[] args) {
Student s = new Student();
s.eat();
s.sleep();
Teacher t = new Teacher();
t.eat();
t.sleep();
}
}
使用idea创建项目:
eclipse里有workspace的概念,工作空间,workspace下面是项目;
idea里是 Project,相当于eclipse的workspace,idea里的项目是module模块的概念。
第一步:创建一个空项目,File -- > New --->Project...
第二步:创建模块module,选择项目名称---new--->module...;相当于eclise的项目。
第三步: 项目最终效果图
6、继承中成员访问的特点
子类访问父类非私有成员
java
public class Father {
//私有的成员变量
private int num = 10;
public int num2 = 20;
//私有的成员方法
private void mothod(){
System.out.println(num);
System.out.println(num2);
}
public void show(){
System.out.println(num);
System.out.println(num2);
}
}
再新建一个子类:
java
public class Son extends Father {
//子类也可以有自己的东西
public void function(){
//子类不能访问父类中私有的成员变量
// System.out.println(num);
System.out.println(num2);
}
}
再新建一个运行类:
java
public class SonTest {
public static void main(String[] args) {
Son s = new Son();
// s.num =200; //子类不能访问父类中的私有的成员变量
s.num2 = 100;
// s.mothod(); //子类不能访问父类中的私有的成员方法
s.function(); //也可以访问自己的方法
s.show();
}
}
7、成员变量
1 成员变量不重名
如果子类父类中出现不重名的成员变量,这时的访问是没有影响的。代码如下:
java
//父类
public class Father {
int num = 10;
}
再新建一个子类:
java
//子类
public class Son extends Father {
//子类成员变量
int num2 = 20;
//子类成员方法
public void function(){
// 访问父类中的num,
System.out.println("Fu num="+num); //10
// 访问子类中的num2
System.out.println("Zi num2="+num2); // 20
}
}
再新建一个运行类:
java
//测试类
public class SonTest {
public static void main(String[] args) {
Son s = new Son();
s.function();
}
}
2 成员变量重名
如果子类父类中出现重名的成员变量,这时的访问是有影响的。代码如下
java
//父类
public class Father {
int num = 10;
}
再新建一个子类:
java
//子类
public class Son extends Father {
int num = 20;
//子类成员方法
public void function(){
//如果子类成员变量的名与父类成中变量名一样,就近原则
System.out.println("num="+num); //20
}
}
再新建一个测试类:
java
//测试
public class SonTest {
public static void main(String[] args) {
Son s = new Son();
s.function();
}
}
子父类中出现了同名的成员变量时,在子类中需要访问父类中非私有成员变量时,需要使用super关键字,修饰父类成员变量,类似于之前学过的this
使用格式
java
【super.父类成员变量名】
代码演示
java
// 注意:在子类里修改一下代码,不用新建一个Son类。
public class Son extends Father {
int num = 20;
//子类成员方法
public void function(){
//如果子类成员变量的名与父类成中变量名一样,就近原则
// System.out.println("Fu num="+num); //20
//我就想访问父类中的成员变量,怎么办? 用super
System.out.println(super.num);//此时访问的就是父类的成员变量 10
}
}
注意
Fu类中的成员变量是非私有的,子类中可以直接访问。若Fu类中的成员变量私有了,子类是不能
直接访问的。通常编码时,我们遵循封装的原则,使用private修饰成员变量,那么如何访问父类的私有成员
变量呢?对!可以在父类中提供公共的getXxx方法和setXxx方法。
3 成员方法
3.2.1 成员方法不重名
如果子类父类中出现不重名的成员方法,这时的调用是没有影响的。对象调用方法时,会先在子类中查找有没有对
应的方法,若子类中存在就会执行子类中的方法,若子类中不存在就会执行父类中相应的方法。代码如下:
注意:新建一个软件包,避免文件名的重名。
java
//父类
public class Father {
public void show(){
System.out.println("我是父类Father");
}
}
//子类
public class Son extends Father {
public void show2(){
System.out.println("我是子类son");
}
}
//测试
public class SonTest {
public static void main(String[] args) {
Son s = new Son();
s.show();//调用父类方法
s.show2();//调用子类方法
}
}
3.2.2 方法重写(Override))
如果子类父类中出现重名的成员方法,这时的访问是一种特殊情况,叫做方法重写(Override)。
什么是方法的重写
方法重写:子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者复写。声明不变,重新实现。
总结:
代码演示
java
//父类
public class Father {
public void show(){
System.out.println("我是父类Father");
}
public void method(){
System.out.println("我是父类method");
}
}
//子类
public class Son extends Father {
public void show2(){
System.out.println("我是子类Father");
}
public void method(){
System.out.println("我是子x类method");
}
}
//测试
public class SonTest {
public static void main(String[] args) {
Son s = new Son();
s.show();//调用父类方法
s.show2();//调用子类方法
System.out.println("===================");
//方法重写:子类中出现了与父类中的一模一样的方法
//子类重写了父类的方法
s.method();
}
}
3.2.3 方法重写的应用场景
子类可以根据需要,定义特定于自己的行为。既沿袭了父类的功能名称,又根据子类的需要重新实现父类方法,从而进行扩展增强。比如新的手机增加来电显示头像的功能,代码如下
代码演示
java
class Phone {
public void sendMessage(){
System.out.println("发短信");
}
public void call(){
System.out.println("打电话");
}
public void showNum(){
System.out.println("来电显示号码");
}
}
//智能手机类
class NewPhone extends Phone {
//重写父类的来电显示号码功能,并增加自己的显示姓名和图片功能
public void showNum(){
//调用父类已经存在的功能使用super
super.showNum();
//增加自己特有显示姓名和图片功能
System.out.println("显示来电姓名");
System.out.println("显示头像");
}
}
public class ExtendsDemo06 {
public static void main(String[] args) {
// 创建子类对象
NewPhone np = new NewPhone();
// 调用父类继承而来的方法
np.call();
// 调用子类重写的方法
np.showNum();
}
}
注意
【super.父类成员方法】,表示调用父类的成员方法
【super.父类成员变量名】,表示调用父类的成员变量
【super()】,表示访问父类中的无参构造
【super( 88 )】, 表示访问父类中的有参构造
3.2.4 方法重写的注意事项
markdown
1. 子类方法重写父类方法,必须要保证权限大于等于父类权限,最好修饰权限一样。
2. 子类方法重写父类方法,返回值类型、方法名和参数列表都要一模一样。
辉腾:速腾、迈腾 类:模板 对象:具体的一个实体,变量:是一块存储空间的名称
win + R 运行窗口 notepad,calc, cmd,mspaint
8、构造方法执行特点
构造方法的特点:
- 构造方法和类名相同
- 构造方法没有返回值
- 构造方法不能有return语句
- 构造方法可以重载但是不能被重写(如果两个类的构造方法一样,那么创建对象的时候创建的是子类还是父类对象?)
- 构造方法核心功能是完成对象的初始化
- 如果自己不写构造方法,java环境会创建一个默认空的构造方法,如果我们编写一个构造方法,则默认不会创建
3.3.1 描述
1.构造方法的名字是与类名一致的。所有子类是无法继承父类构造方法的。
2.构造方法的作用是初始化成员变量的。所以子类的初始化过程中,必须先执行父类的初始化动作。子类的构造方法中默认有一个super() , 表示调用父类的构造方法,父类成员变量初始化后,才可以给子类使用。
3.3.2 代码演示
注意新建一个软件包,在包里分别创建三个Java类。
java
//父类
public class Father {
private int num;
//父类的构造方法
public Father(){
System.out.println("父类的构造方法");
}
public Father(int num) {
this.num = num;
}
public void show1(){
System.out.println(num);
}
}
新建一个子类:
java
//子类
public class Son extends Father {
//子类无参构造方法
public Son(){
// 子类构造方法中的第一行默认有 super() ,给父类进行初始化的
// 作用:因为继承必须先调用父类的构造方法,父类成员变量初始化后,才可以给子类使用。
super();
System.out.println("子类的构造方法");
}
//子类有参构造方法
public Son(int num2) {
super(34);
this.num2 = num2;
}
public void show2(){
System.out.println(num2);
}
}
新建一个测试类:
java
//测试
public class Test {
public static void main(String[] args) {
//在每次创建子类对象时,都会先初始化父类构造方法,再创建其子类对象本身。
Son s = new Son();
Son s = new Son();//每一次实例子类对象,都会先访问父类的无参构造 (这里两次)
//访问有参构造
Son s = new Son(2000);
s.show1();
s.show2();
}
}
在每次创建子类对象时,先初始化父类空间,再创建其子类对象本身。目的在于子类对象中包含了其对应的父类空间,便可以包含其父类的成员,如果父类成员非private修饰,则子类可以随意使用父类成员。代码体现在子类的构造方法调用时,一定先调用父类的构造方法。
3.3.3 访问构造方法的注意事项
java
* 在子类构造方法中的第一行默认有 super() ,给父类进行初始化的
* 在子类构造方法中可以手动调用父类其他重载的构造方法
格式: super(参数列表);
* super 是写在子类的构造方法的第一行.
9、super和this
4.1 super和this的含义
super:前提:继承关系 。 代表父类的存储空间标识(可以理解为父亲的引用)。
this:代表当前对象的引用(谁调用就代表谁)。
4.2 super和this的用法
访问成员
java
this.成员变量 ‐‐ 本类的
this.成员方法名() ‐‐ 本类的
super.成员变量 ‐‐ 父类的
super.成员方法名() ‐‐ 父类的
代码演示
java
class Animal {
public void eat() {
System.out.println("animal : eat");
}
}
//重载在1个类,重写在父子类(2个类)
class Cat extends Animal {
public void eat() {
System.out.println("cat : eat");
}
public void eatTest() {
this.eat(); // this 调用本类的方法
super.eat(); // super 调用父类的方法
}
}
public class ExtendsDemo08 {
public static void main(String[] args) {
Animal a = new Animal();
a.eat();
Cat c = new Cat();
c.eatTest();
}
}
访问构造
java
this(...) ‐‐ 本类的构造方法
super(...) ‐‐ 父类的构造方法
子类的每个构造方法中均有默认的super(),调用父类的空参构造。手动调用父类构造会覆盖默认的super()。
super()和this()都必须是在构造方法的第一行,所以不能同时出现。
markdown
super和this的区别?
super的用法,前提:一定要有继承关系,子类无法访问父类的成员,通过super关键字来找父类引用
super.成员变量 子类访问的父类中的成员变量
super.成员方法 子类访问的父类中的成员方法
super() 子类访问父类的无参构造方法
super("xx") 子类访问父类中有参构造方法
this的用法 代表当前对象的引用(谁调用this就代表谁)
this.成员变量 本类的成员变量
this.成员方法 本类的成员方法
10、继承的特点
java
/*
Java中继承的特点:
A:Java只支持单继承,不支持多继承。有些语言是支持多继承,格式:extends 类1,类2,...
B:Java支持多层继承(继承体系)
*/
class Father(){}
class Mother(){}
class son extends Father(){} // 正确
class son2 extends Father , Mother {} // 不正确
Java只支持单继承,不支持多继承
java
//一个类只能有一个父类,不可以有多个父类。
class C extends A{} //ok
class C extends A,B... //error
Java支持多层继承(继承体系)
java
class A{}
class B extends A{}
class C extends B{}
子类和父类是一种相对的概念
一个父类可以有很多个子类
java
class Animal{}
class Dog extends Animal{}
class Cat extends Animal{}
class Pig extends Animal{}
5.1 代码演示
新建一个软件包,分别创建四个java类。
java
//爷爷
public class GrandFather {
public void show(){
System.out.println("爷爷");
}
}
//父亲
public class Father extends GrandFather {
public void method(){
System.out.println("父亲");
}
}
//儿子
public class Son extends Father { }
//测试
public class Test {
public static void main(String[] args) {
Son s = new Son();
s.show();// 间接的继承爷爷的方法
s.method();//继承了父亲的方法
}
}
(二)java Swing编程
java程序的分类: javadoc 帮助文档
- DOS命令行程序
- 窗口GUI (Graphical User Interface)图形界面程序,并不是java的优势,C# 微软公司 VisualBasic Delphi(2000年)
- 服务器端应用程序,这个java的优势,淘宝、京东、美团这些大型互联网公司都是java技术体系为主。
Swing是Java基础类的一部分,是一个为Java设计的GUI工具包。
Swing包含了诸多图形用户界面(GUI)器件,提供了许多比awt更好的屏幕显示元素。
一个 Java的图形界面,是由各种不同类型的"元素"(诸如窗口、菜单栏、对话框、标签、按钮、文本框等)所组成的,它们被统一称之为组件(Component)。他们之间的继承关系如下图所示:
1. 窗口组件
JFrame和JDialog属于窗口类组件,可以独立显示,一个图形界面至少需要一个窗口,而绝大多数的图形用户界面都采用JFrame作为窗口。JFrame是可以独立显示的窗口组件。一个窗口组件通常含有标题、图标、操作按钮(关闭、最小化、最大化)等内容。了解一个类:构造方法、属性、常用方法。人品、财产、颜值;颜值、人品、性格
a.JFrame的构造方法
构造方法 | 语法 | 功能 |
---|---|---|
无参构造方法 | JFrame() | 创建一个没有标题的窗口对象 |
含参构造方法 | JFrame(String s) | 创建一个标题为"s"的窗口对象 |
b.JFrame的常用方法
方法 | 功能 |
---|---|
void setTitle(String s) | 设置窗口的标题 |
void setSize(int width, int height) | 设置窗口的大小 |
void setLocation(int x, int y) | 设置窗口的位置 |
void setBounds(int x, int y, int width, int height) | 同时设置窗口的位置和大小 |
void setVisible(boolean b) | 设置窗口是否可见,默认不可见 |
void setResizable(boolean b) | 设置窗口是否可以调整大小,默认可调整 |
void dispose() | 销毁窗口, 释放窗口占用的资源,调用setVisible(true)则可重构 |
void pack() | 调整窗口的大小, 使其适合子组件的大小和布局 |
void setDefaultCloseOperation(int operation) | 设置窗口关闭按钮点击后的默认操作 |
tip:setDefaultCloseOperation方法的参考值:
- WindowConstants.DO_NOTHING_ON_CLOSE: 不执行任何操作
- WindowConstants.HIDE_ON_CLOSE: 隐藏窗口, 调用setVisible(true)则可重构
- WindowConstants.DISPOSE_ON_CLOSE: 销毁窗口, 释放窗口占用的资源
- WindowConstants.EXIT_ON_CLOSE: 结束窗口所在的应用程序
c.实例展示
java
import javax.swing.*;
public class JFrameTest {
public static void main(String[] args) {
JFrame jFrame = new JFrame();
jFrame.setTitle("学生管理系统");
jFrame.setSize(500,250);
jFrame.setLocationRelativeTo(null);//居中对齐
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setVisible(true);
}
}
添加组件:
java
import javax.swing.*;
import java.awt.*;
public class JButtonTest {
public static void main(String[] args) {
JFrame jFrame = new JFrame("学生管理系统");
jFrame.setSize(500,250);
jFrame.setLocationRelativeTo(null);//居中对齐
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setLayout(new FlowLayout());//流动,流式布局
JButton jButton = new JButton("添加");
jFrame.add(jButton);
jFrame.setVisible(true);
}
}
2. 布局组件
为了将Java Swing的各种组件添加到面板容器中(JPanel),需要给面板容器指定布局管理器(LayoutManager),明确各个组件之间的排列布局方式。本章将只着重介绍以下三种常用的布局管理器,想要了解其他布局管理器可以参考官方API文档。
布局管理器 | 相关介绍 |
---|---|
FlowLayout | 流式布局,按组件加入的顺序水平方向排列,排满一行换下一行继续排列 |
BorderLayout | 边界布局,把窗口按方位分为5个区域,每个区域放置一个组件 |
2.1 流式布局
按组件加入的顺序水平方向排列,排满一行换下一行继续排列。
java
import java.awt.*;
import javax.swing.*;
public class FlowLayoutTest {
public static void main(String[] args) {
JFrame jf = new JFrame("这是一个JFrame");
jf.setLayout(new FlowLayout(FlowLayout.LEFT));
jf.setSize(250, 250);
jf.setLocation(400, 300);
//面板
JPanel jp = new JPanel(new FlowLayout());
JButton btn01 = new JButton("按钮01");
JButton btn02 = new JButton("按钮02");
JButton btn03 = new JButton("按钮03");
JButton btn04 = new JButton("按钮04");
JButton btn05 = new JButton("按钮05");
jp.add(btn01);
jp.add(btn02);
jp.add(btn03);
jp.add(btn04);
jp.add(btn05);
//把面板放到JFrame窗口
jf.setContentPane(jp);
jf.setVisible(true);
jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
}
更多细致内容在此不展开,可以查阅官方API文档仔细学习: Class JFrame
(三)java IO编程
1. 什么是IO
生活中,你肯定经历过这样的场景。当你编辑一个文本文件,忘记了ctrl+s
,可能文件就白白编辑了。当你电脑上插入一个U盘,可以把一个视频,拷贝到你的电脑硬盘里。那么数据都是在哪些设备上的呢?键盘、内存、硬盘、外接设备等等。
我们把这种数据的传输,可以看做是一种数据的流动,按照流动的方向,以内存为基准,分为输入input
和输出output
,即流向内存是输入流,流出内存的输出流。人剑合一,人码合一
Java中I/O操作主要是指使用java.io
包下的内容,进行输入、输出操作。输入 也叫做读取 数据,输出 也叫做作写出数据。
2. IO的分类
根据数据的流向分为:输入流 和输出流。
- 输入流 :把数据从
其他设备
上读取到内存
中的流。 - 输出流 :把数据从
内存
中写出到其他设备
上的流。
根据数据的类型分为:字节流 和字符流 ,从操作的粒度,byte 字符:汉字、英文字符、标点符号;1字符=3字节
- 字节流 :以字节为单位,读写数据的流。字节可以读写所有数据,用记事本打开如果你看不懂,就用字节
- 字符流 :以字符为单位,读写数据的流。字符一般只操作文本,用记事本打开如果你能看懂,就用字符
3. IO的流向说明图解
4. 文件对象
(1) java.io.File
类:文件和文件目录路径的抽象表示形式,与平台无关;Car--小汽车 Computer 电脑 File---文件或目录
(2)File
类中涉及到关于文件或文件目录的创建、删除、重命名、修改时间、文件大小等方法,并未涉及到写入或读取文件内容的操作。如果需要读取或写入文件内容,必须使用IO
流来完成。
(3) 想要在Java程序中表示一个真实存在的文件或目录,那么必须有一个File
对象,但是Java程序中的一个File
对象,可能没有一个真实存在的文件或目录。
(4) File
对象可以作为参数传递给流的构造器,指明读取或写入的"终点"。
java
import java.io.File;
import java.util.Date;
public class FileTest {
public static void main(String [] args){
File file1 = new File("hello.txt");
//File file2 = new File("d:\\io\\hi.txt");
File file2 = new File("/Users/kongfanyu/2.png");
System.out.println(file1.getAbsolutePath());
System.out.println(file1.getPath());
System.out.println(file1.getName());
System.out.println(file1.getParent());
System.out.println(file1.length());
System.out.println(new Date(file1.lastModified()));
System.out.println();
System.out.println(file2.getAbsolutePath());
System.out.println(file2.getPath());
System.out.println(file2.getName());
System.out.println(file2.getParent());
System.out.println(file2.length());
System.out.println(file2.lastModified());
}
}
5. 字节流
一切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,都一个一个的字节,那么传输时一样如此。所以,字节流可以传输任意文件数据。在操作流的时候,我们要时刻明确,无论使用什么样的流对象,底层传输的始终为二进制数据 。
文件读取:
java
import java.io.FileInputStream;
import java.io.IOException;
public class FISRead {
public static void main(String[] args) throws IOException {
// 使用文件名称创建流对象. reader writer字符流
FileInputStream fis = new FileInputStream("hello.txt");
// 定义变量,作为有效个数
int len;
// 定义字节数组,作为装字节数据的容器
byte[] b = new byte[1024];
// 循环读取
while (( len= fis.read(b))!=-1) {
// 每次读取后,把数组的有效字节部分,变成字符串打印
System.out.println(new String(b,0,len));// len 每次读取的有效字节个数
}
// 关闭资源
fis.close();
}
}
图片复制:
java
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Copy {
public static void main(String[] args) throws IOException {
// 1.创建流对象
// 1.1 指定数据源
FileInputStream fis = new FileInputStream("/Users/kongfanyu/2.png");
// 1.2 指定目的地
FileOutputStream fos = new FileOutputStream("test_copy.jpg");
// 2.读写数据
// 2.1 定义数组
byte[] b = new byte[1024];
// 2.2 定义长度
int len;
// 2.3 循环读取
while ((len = fis.read(b))!=-1) {
// 2.4 写出数据
fos.write(b, 0 , len);
}
// 3.关闭资源
fos.close();
fis.close();
}
}
四、代码实现
基于以上知识点的讲解,我们实现今天的功能,创建窗体添加一张牌。首先是牌的设计:
- 第一个属性是name,String类型,存储当前牌的名字,name属性有俩个作用,第一,在消除框有个基本的规则是三个相同的牌就消除掉,牌是否相同的判断依据就是name属性。第二,通过name属性找到图片文件,我们在项目的根目录下创建imgs文件夹来存放游戏的素材文件,从原来的项目拷贝过来。
- 第二个属性 isGray,是否置灰,boolean
实现代码:
java
package cn.yunhe.model;
import javax.swing.*;
import java.awt.*;
//JComponent 组件
public class Brand extends JComponent{
private String name;//牌的名称
private boolean isGray;//是否置灰
private Image image; //彩色图片
private Image grayImage;//灰色图片
//x,y左上角坐标
private int x = 0;
private int y = 0;
//宽高
private int width = 50;
private int height = 50;
// new
public Brand(String name){
this.name = name;
this.image = Toolkit.getDefaultToolkit().getImage("imgs//"+name + ".png");
this.grayImage = Toolkit.getDefaultToolkit().getImage("imgs//"+name+"_gray.png");
}
//重写
@Override
public void paint(Graphics g) {
if (this.isGray == true) {
//绘制灰色图片 直线 矩形
g.drawImage(this.grayImage,this.x,this.y,null);
} else {
//绘制彩色图片
g.drawImage(this.image,this.x,this.y,null);
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Boolean getGray() {
return isGray;
}
public void setGray(Boolean gray) {
isGray = gray;
}
public Image getImage() {
return image;
}
public void setImage(Image image) {
this.image = image;
}
public boolean isGray() {
return isGray;
}
public void setGray(boolean gray) {
isGray = gray;
}
}
注意以下四个属性不用生成getter/setter方法,否则影响后续的执行:
java
private int x = 0;
private int y = 0;
//宽高
private int width = 50;
private int height = 50;
启动类:
java
package cn.yunhe.view;
import cn.yunhe.model.Brand;
import javax.swing.*;
import java.awt.*;
public class StartGame extends JFrame {
private Brand brand = new Brand("刷子");
public StartGame() {
this.setTitle("云和数据版-羊了个羊");
this.setSize(450,800);
this.setLocationRelativeTo(null);//居中
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//添加组件的方法,可以添加自己定义的组件都当前的窗口中
//brand.setGray(true);
this.getContentPane().add(brand);//桌布<桌面的大小
this.setVisible(true);
//启动自动刷新线程
//autoRefresh();
}
public static void main(String[] args) {
new StartGame();
}
}
执行效果:
五、本章总结
本章重点讲解实现创建窗体、显示窗体、添加组件,完成基础功能。涉及到的知识点包括:java面向对象---继承、
java Swing编程技术、java IO编程技术。下去完成本章案例和项目模块。
六、布置作业
-
完成本章的知识点案例,包括继承的案例、FileTest案例,FISRead案例,Copy案例,JFrameTest案例,JButtonTest案例,FlowLayoutTest案例。
-
完成本章的项目案例。