Java课程设计题目七:魔板游戏

1 设计要求

磨板游戏是款经典的智力游戏。具体要求如下:

① 魔板由3X3或4X4个格子组成。对于3X3魔板,在前8个格子里随机放置8个编号为18的方块,最后一个格子是未放置方块的空格子:对于4X4的魔板,在前15个格子单随机放置15个编号为115的方块,最后个格 子是未放置方块的空格子。

② 用鼠标单击任何与空格子水平或垂直相邻的方块都可以把该方块移入空格子,而当前方块移动之前所在的格子成为空格子。通过不断地移动方块可以将方块行行地按数字乘序排好。例如,对于3X3格子组成的魔板,要求方块最后排列的顺序是“1,2,3,4,5,6,7,8”。

③ 魔板游戏也可以使用图像来代替数字。例如,对于3X3的魔板,将幅图像分成3x3幅小图像,除去最后幅小图像(图像的右下角),将其余各幅小图像打乱顺序后放在魔板的方块上,最终目标是通过移动方块恢复原始图像,即最后各个小方块上的图像组成的顺字所形成的图像必须和原图样(除了图像的右下角,即右下角必须没有方块)。

④ 当用户按要求排列好方块后,程序弹出对话框,提示用户成功的消息。

⑤ 魔板游戏分为两个级别,用户可以通过界面上提供的菜单来选择“初级”或“高级”级别。对于“初级”级别,魔板由3X3个格子组成:对于“高级”级别,魔板由4X4个格子组成。

⑥ 魔板游戏提供幅默认图像,用户可以使用该图像来玩魔最游戏。用户也可以使用科提供的菜单选择幅新图像,然后使用这个新的图像来玩魔复游戏。

程序运行的参考效果图如图7.1所示。

java 课程设计的组成部分 java课程设计题目_java 课程设计的组成部分

图7.1 模版游戏

注意 我们按照MVC-Model View Control(模型,视图,控制器)的设计思想展开程序的设计和代码的编写。数据模型部分相当于MVC中的Model角色,视图设计部分给出的界面部分相当于MVC中的View,视图设计部分给出的事件监视器相当于MVC中的Control。

2 数据模型

根据系统设计要求在数据模型部分编写以下类。

封装模板中点有关数据的Point类。

封装模板中方块有关数据的Block类。

负责分解图像的HandleImage类。

负责验证用户是否成功的VerifySuccess类。

数据模型部分涉及的主要类的UML图如图7.2所示。

java 课程设计的组成部分 java课程设计题目_游戏_02

图7.2 主要类的UML图

点与方块类
1.Point类(点)
Point的实例是魔板中的点。x,y是Point对象中的两个int型数据,分别用来表示点的x-坐标和y-坐标。haveBlock是boolean数据,如果有方块(Block对象)在点上,该点的haveBlock数据为true,否则为false(点用block成员来存放一个Block对象的引用,表明该Block对象在当前点上)。

Point.java

Package ch7.data;
Public class Point{
int x,y;                 //在坐标系中的x-坐标和y-坐标
boolean haveBlock;       //点上是否有方块
Block block=null;          //点上的方块
public Point(){ }
public Point(int x,int y){
this.x=x;
this.y=y;
} 
public boolean isHaveBlock(){
	 return haveBlock;
}
public void setHaveBlock(boolean boo){
haveBlock=boo;
}
Public int getX(){
return x;
}
Public int getY(){
return y;
}
Public void setBlock(Block block){
this.block=block;
}
Public Block getBlock(){
return block;
}
}

2.Block类(方块)
Block类的实例是模板中的方块。方块含有魔板中的全部点的引用,也能确定自己所在的点。另外,方块可以使用move()方法在魔板的点上走动;方块可以根据需要决定是否绘制一幅图像在方块上(图像玩法);方块也可以根据需要决定是否将数字显示在方块上(数字玩法)。

Block.java

package ch7.data;
import javax.swing.*;
import java.awt.*;
public class Block extends JTextField{
point point;        //方块所在的点
object object;      //方块上的图像
point [][] allpoint;   //全部点位置
int index_i,index_j;  //点的索引
public Block(){
setEditable(fasle);
setHorizontalAlignment(JTextField.CENTER);
setFont(new Font(“Arial”,Font.BOLD,16));
setForeground(Color.blue);
}
public void setAtpoint(point p){
point=p;
}
public void set	Allpoint(point [][] point){
allPoint=point;
}
public Poins getAtPoint() {
return poirt;
}
public voc setobject(Object object){
  			this.object=object;
if(objeet inetanceol lnteqer) {
 				Integer number=(lrteger)object;
  				sat Text(lnunber.tntValue());
}
else if (object tnstancecf Enage) {
 				 repaint();
  			}
}
pubiie Object getobject() {
return object;
}
public void paintcorponent (Graphics g) {
super.paintComporent(g);
int w-get3ounds().width;
int h=getBounds().height;
try {
  				 g.drawImage((Inaqe)object,C,0,w,h,this);
 			}
catch(Rxception exp) {
public boolear move()
int m =-1,n=-1;
boolean succeasMove = false;
Point pStart =getAtPoint ();
findIndex(pStart,allPoint);
//见后面findIndex(Poiatp,Point!'i) allPoint)方法
for(int i = 0;i<allpoint.length;i++)l //得到空盒子的位置索引 "m,n"
 					 for(int j = 0;j<allpoint.i].lengch;j++)  {
if(!allPoint [i] [j].isHaveBlock ()  {
   							m=i;
    						n=j;
    					}
  					}
}
if (Math.abs(index i-m)+Math.abs (index_j-n) ==1) {
this.setAtPoint(allpoint [m] [n]);
//当前方块到达allPoint[m][n]点(空盒处)
successMove = true;
allPoint[m][n].setBlock(this);
alPoin [m][n].set HaveBlock (true);
    				PStart.setHaveBlock(false);//设置该点没有方块
    				PStart.setBlock (null) ;/ / 设置该点上的方块是 null(设置为空盒子)
  				}
 				 return successMove;
}
private void findIndex (Point p,Point [][] al1Point){
                           //寻找p在 allPoint 中的索引位置
  			for (int i=0;i<allPoint. length;i++){
     			for (int j= 0;j<allPoint[i].length;j++){
        			if (p== allPoint[i][j]){
           				index_i= i;
           				index_j= j;
           				Break;
        			}
      			}
    		}
  		}
}

分解图像与验证
1.HandleImage类(分解图像)
Handlelmage 类的实例负责分解图像,可以将一幅图像分解为若干幅小的图像,并将这些小图像存放在 Image 类型的数组中。

HandleImage.java

package ch7. data;
import java.awt.*;
import javax.swing.*;
import java.awt. image.*;
public class HandleImage extends JComponent {
  		 int imageWidth, imageHeight;
   		 Toolkit tool;
   	public HandleImage () {
     tool=getToolkit () ;
}
public Image [] getImages (Image image, int rows, int colums) {
   		Image [] blockImage=new Image[rows*colums];
   		try{
        	imageWidth=image.getwidth(this);
       		imageHeight=image.getHeight (this) ;
        	int w=imageWidth/colums;
            int h=imageHeight/rows;
            int k=0;//把图像分成k份,即 rows*colums份
            PixelGrabber pg=null;
            ImageProducer ip=null;
   			for (int i=0;i<rows;i++){
                		for (int j=0;j<colums;j++){
                    			int pixels[]=new int[w*h];//存放第k分图像像素的数组
        	  //将图像image中(j*w,i*h,w,h)矩形区域的像素放到数组pixels的第0行至第w行中
                    			pg=new PixelGrabber(image,j*w,i*h,w,h,pixels,0,w);
                    			pg.grabPixels();
                    //用数组pixels的第0行至第w行像素做图像源
                    			ip=new MemoryImageSource(w,h,pixels,0,w);
                      		blockImage[k]=tool.createImage(ip);
                    //得到宽是w,高是h的矩形Image对象
                    			k++;
                   		}
            		}
        	}
        	catch (Exception ee){ }
        		return blockImage;
    		}
	}

2.VerifySuccess类(验证)
VerifySuccess 类的实例负责验证用户是否成功地按规则完成了魔板游戏,即是否将魔板中的方块排列成规则要求的顺序。例如对于3行3列的魔板,魔板中方块上的数字顺序必须是“1,2,3,4,5,6,7,8”,同时魔板的右下角必须没有方块。对于图像魔板,最后各个小方块上的图像组成的顺序所形成的图像必须和原图一样(除了图像的右下角,即右下角必须没有方块)。

VerifySuccess.java

package ch7.data;
public class VerifySuccess{
    Point [ ] [ ] point;        //魔块中的全部点
    Object [ ] object;         //方块上应该有的数字顺序或图像顺序
public void setPoint(Point [ ] [ ] point){
        this.point=point;
 	}
public void setObject(Object [ ] object){
        this.object=object;
 	}
public boolean isSuccess(){
     	if (point[point.length-1][point[0].length-1],getBlock()!=null)
       	 //如果右下角有方块
        	return false;
        boolean boo=true;
        int k=0;
        for (int i=0; i<point.length;i++){
            if (i<point.length-1){
for (int j=0;j<point[i].length;j++){
					if (!(point[i][j].getBlock().getobject() ==object[k])){
						boo = false;
						break;
}
k++;
}
}
else{  //排除右下角的点
			for (int j = 0; j <point[i].length-1;j++){
				if (! (point[i][j].getBlock().getObject()==object[k])){
					boo=false;
					break;
}
k++;
}
}
}
return boo;
}
}

3 简单测试
我们的Java程序就是设计要求的C/S模式中的C,即客户端。按照源文件中的包语句将相关的Java源文件保存到以下目录中:
D:\ch7\date
编译各个源文件,例如:
D:>javac ch7/date/Point.java
也可以编译全部源文件:
D:>javac ch7/date/*.java
把7.2节给出的类看作一个小框架,下面用框架中的类编写一个简单的应用程序,测试魔板游戏,即在命令行表述对象的行为过程,如果表述成功(如果表述困难,说明数据模型不是很合理),那么就为以后的GUI程序设计提供了很好的对象功能测试,在后续的GUI设计中,重要的工作仅仅是为某些对象提供视图界面,并处理相应的界面事件而已。
APPTest测试了数字魔板,编译APPTest.java:
D:>javac ch7/test/APPTestOne.java
运行APPTest类,效果如图7.3所示。

java 课程设计的组成部分 java课程设计题目_System_03

图7.3 简单测试

D:>java ch7.te est.AppTestOne

AppTest.java

package ch7.test;
import ch7.data.*;
public class AppTest {
        public static void main(String [] args) {
            Point [][] point =new Point[3][3];//3 行3 列的魔板中的点//
            for(int i=0;i<point.length;i++) {
            for (int j =0;j<point[i].length;j++)
                point[i][j]=new Point();
            Block block[][] = new Block[3][3];
            for(int i=0;i<block.length;i++){ //3行3列的魔板中的方块
                for (int j = 0;j<block[i].length;j++) {
                    block[i][j] = new Block();
                    block[i][j].setAllPoint(point);
                    block[i][j].setAtPoint(point[i][j]);
                    point[i][j].setHaveBlock(true);
                    point[i][j].setBlock(block[i][j]);
                }
            }
            point[2][2].setHaveBlock(false); //右下角设置没有方块
            point[2][2].setBlock(null); //右下角设置为null方块
            VerifySuccess verifySuccess = new VerifySuccess();//负责判断是否成功//
                Integer [] number = {1,2,3,4,5,6,7,8};
                verifySuccess.setPoint(point);
                verifySuccess.setobject(number);
                block[0][0].setObject(number[0]);
                block[0][1].setobject(number[1]);
                block[0][2].setObject(number[2]);
                block[1][0].setobject(number[3]);
                block[1][1].setobject(number[7]);
                block[1][2].set0bject(number[4]);
                block[2][0].setobject(number[6]);
                block[2][1].setObject(number[5]);
                intput(point);
            System.out.println("---------");
            System.out.println("移动2次:");
            System.out.println(point[2][1].getBlock().move());
            System.out.println(point[1][1].getBlock().move());
            intput(point);
            System.out.println("成功否:"+verifySuccess.isSuccess());
            System.out.println("再移动2次:");
            System.out.println(point[1][2].getBlock().move());
            System.out.println(point[1][2].getBlock().move());

intput(point);
System.out.println("成功否:"+verifySuccess.isSuccess());
}
static void intput(point [] []  point){
int k = 0;
for(int i=0;i<point.length;i++) {
for(int j=0;j<point[i].length;j++){
String s ="";
Block bk=point[i][j].getBlock(); 
if(bk!=null){
Integer object=(Integer)bk.getobject();
 s=object.toString();
}
else
s ="#"; //表示没有方块
System.out.printf("%5s",s);
}
System.out.println();
}
}
}

4 视图设计
设计GUI程序除了使用7.2节给出的类以外,需要使用javax.swing包提供的视图(也称 Java Swing框架)以及处理视图上触发的界面事件。与7.3节中简单的测试相比,GUI 程序可以提供更好的用户界面,完成7.1节提出的设计要求。
GUI部分设计的类如下(主要类的UML图如图7.4所示)。

图7.4 主要类的UML

●PuzzlePad 类 : 其实例为魔板游戏的视图界面。
●HandleMove类:其实例负责处理PuzzlePad视图上的MouseEvent 和ActionEvent 事件。

(1)视图相关类
PuzzlePad 类是javax.swing包中Panel容器的子类,其实例就是魔板。该类使用二维数组Point来确定魔板中方块的位置,使用二维数组Block作为魔板中的方块。distance、grade、m和n是int型数据,Point对象根据distance的值进行初始化,以便确定Point对象之间的距离。m和n的值是二维数组Block和Point的行数和列数,m和n的默认值都是3。grade的值代表魔板的级别,默认值是1。PuzzlePad对象调用setlsDigitPlay()方法将魔板设置为数字玩法,调用paintComponent(Graphics)将魔板使用的图像(即image对象)绘制在魔板的右侧,如图7.5所示。

图7.5 魔板视图

PuzzlePad.java

package ch7.view;
import javax.swing.*;
import java.util.*;
import java.awt.*;
import ch7.data.Point;
import ch7.data.Block;
import ch7.data.HandleImage;
import ch7.data.VerifySuccess;
public class PuzzlePad extends JPanel{
	Point [][point];
	Block [][block;
	int	distance=56,grade,m=3,n=3;
	HandleMove handleMove;
	HandleImage handleImage;
	VerifySuccess verifySuccess;
	Image image;
	boolean isDigitplay;
	public PuzzlePad(){
		setBackground(Color.gray);
		setLayout(null);
		handleMove=new HandleMove();
		handleMove.initSpendrime();
		handleImage=new HandleImage();
		verifySuccess=new VerifySuccess();
		handleMove.setverifySuccess(verifySuccess);
}
	public HandleMove getHandleMove(){
		return handleMove;
	}
	public void setImage(Image image){
		this,image=image;
	}
	public void setGrade(int grade){
		 this.grade=grade;
		 if(grade==1){
  		   m=3; 
n=3;
}
else if(grade==2){
m=4;
n=4;
}
}
public int getGrade(){
return grade;
}
private void needInit(){
handleMove.initSpendTime(); 
removeAll();
point=new Point[m][n]; 
block=new Block[m][n];
int Hspace=distance,Vspace=distance;
for(int i=0;i<m;i++)(
for(int j=0;j<n;j++){
point[i][j]=new Point(Hspace,Vspace); 
Hspace=Hspace+distance;
}
Hspace=distance;
Vspace=Vspace+distance;
}
handleMove.setPoint(point);
verifySuccess.setPoint(point);
handleMove.setVerifySuccess(verifySuccess);
int k=0;
for(int i=0;i<m;i++){
if(i<m-1)
for(int j=0;j<n;j++){
block[i][j]=new Block();
block[i][j].setAllPoint(point);
block[i][j].addMouseListener(handleMove); 
k++;
}
else{
for(int j=0;j<n-1;j++){
block[i][j]=new Block();
block[i][j].setAllPoint(point);
block[i][j].addMouseListener(handleMove);
k++;
}
}
}
for(int i=0:i<m;i++){
if(i<m-1)
for(int j=0;j<n;j++){
add (block[i] [j]);
block[i] [j].setSize (distance,distance);
block[i] [j].setLocation (point[i] [j].getX(),point[i] [j].
getY()) ;
block[i] [j].setAtPoint (point[i][j]);
point[i] [j].setBlock (block[i] [j]);
point[i] [j].setHaveBlock (true);
}
else{
for(int j=0;j<n-1;j++){
add (block[i] [j]);
block[i] [j].setSize (distance, distance);
block[i] [j].setLocation (point[i] [j].getX(),point[i] [j].
getY());
block[i] [j].setAtPoint (point[i] [j]);
point[i] [j] .setBlock (block[i] [j]);
point[i] [j] .setHaveBlock (true) ;
}
}
}
public void setIsDigitPlay() {
needInit();
isDigitPlay=true;
ArrayList<Integer> numberList=new ArrayList<Integer>() ;
for(int k=0;k<m*n-1;k++) {
numberList.add(k+1);
}
Object [] object=numberList.toArray();
verifySuccess. setObject (object);
Collections . shuffle (numberList); / /随机排列数字
int k=0;
for(int i=0;i<m;i++){
if (i<m-1)
for (int j=0;j<n;j++){
block[i] [j] .setObject(numberList.get(k));
k++;
      		}
else{
for (int j=0;j<n-1;j++){
block[i] [j].set0bject(numberList .get(k));
k++;
}
}
}
repaint() ;
}
public void setIsImagePlay(){
needInit();
isDigitPlay=false;
ArrayList<Image>imageList=new ArrayList<Image>();
Image[ ]blockImage=handleImage.getImages(image,m,n);
for(int k=0;k<blockImage.length-1;k++{
imageList.add(blockImage[k]);
}
Object[ ]object=imageList.toArray();
verifySuccess.setobject(object);
Collections.shuffle(imageList);//随机排列图像
int k=0;
for(int i=0;i<m;i++){
if(i<m-1)
for(int j=0;j<n;j++){
block[i][j].setobject(imageList.get(k));
block[i][j].repaint();
block[i][j].setBorder(null); k++;
}
else{
for(int j=0;j<n-1;j++){
block[i][j].setobject(imageList.get(k));
block[i][j].repaint();
block[i][j].setBorder(null);
k++;
}
}
repaint();
}
public  voidpaint  Component(Graphics  g){
super.paintComponent(g);
if(isDigitPlay==false)
try{
g.drawImage(image,20+distance*(m+1),point[0][0].getY(),
distance*m,distance*n,this);
}
catch (Exception exp){ 
}
}
}

(2)事件监视器
事件监视器负责处理视图上触发的用户界面事件,以便完成相应的任务。HandleMove类是javax.swing包中JPanel容器的一个子类,并实现了MouseListener和ActionListener接口,创建的对象 handleMove 是重要成员之一。handleMove 负责监视魔板中的方块上的鼠标事件。当用户用鼠标单击方块后,handleMove对象负责通知方块调用move()方法。
另外,监视器封装VerifySuccess类的实例,以便让该实例判断用户是否成功地完成了游戏。HandleMove类还封装了javax.swing.Timer计时器。构造方法Timer(int a,Object b)创建计时器。其中,参数a的单位是毫秒,确定计时器每隔a毫秒震铃一次,参数b是计时器的监视器。计时器发生的震铃时间是ActionEvent事件。当震铃事件发生时,监视器就会监视到这个事件,就会调用actionPerformed(ActionEvent)方法。当震铃每隔a毫秒发生一次时,方法actionPerformed(ActionEvent)就被执行一次。

HandleAddAddvertisement.java

package ch7.view;
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
import ch7.data.Point;
import ch7.data.Block;
import ch7.data.HandleImage;
import ch7.data.VerifySuccess;
public class HandleMove extends JPanel implements MouseListener,ActionListener {
    Point [][] point;
    int spendTime=0;
    javax.swing.Timer recordTime;
    VerifySuccess verify;
    HandleMove(){
        recordTime=new javax.swing.Timer(1000,this);
        showTime = new JTextField(16);
        showTime.setEditable(false);
        showTime.setHorizontalAlignment(JTextField.CENTER);
        showTime.setFont(new Font("楷体_GB2312",Font.BOLD,16));
        JLabel hitMess=new JLabel("用鼠标单击方块",JLabel.CENTER);
        hitMess.setFont(new Font("楷体_GB2312",Font.BOLD,18));
        add(hitMess);
        add(showTime);
        setBackground(Color.cyan);
    }
    public void setPoint(Point [][] p){
        point=p;
    }
    public void initSpendTime(){
        recordTime.stop();
        spendTime=0;
        showTime.setText(null);
    }
    public void setVerifySuccess(VerifySuccess verify){
        this.verify=verify;
}   
 public void mousePressed(MouseEvent e){
        recordTime.start();
        Block block=null;
        block=(Block)e.getSource();
        Point startPoint=block.getAtPoint();
        int w=block.getBounds().width;
        int h=block.getbounds().height;
        if(block.move()){
            Point pEnd=blovk.getAtPoint();//得到方块移动后所在点
            int x=pEnd.getX();
            int y=pEnd.getY();
            block.setLocation(x,y);
            block.setAtPoint(pEnd);
            pEnd.setBlock(block);
            startPoint.setHaveBlock(false);
        }
    }
    public void actionPerformed(ActionEvent e){
        spendTime++;
        showTime.setText("您的用时:"+spendTime+"秒");
    }
    public void mouseReleased(MouseEvent e){
        if(verify.isSuccess()){
            recordTime.stop();
            JOptionPane.showMessageDialog(this,"您成功了!","消息框",JOptionPane.INFORMATION_MESSASGE);
        }
    }
    public void mouseEntered(MouseEvent e){}
    public void mouseEntered(MouseEvent e){}
    public void mouseEntered(MouseEvent e){}
}

5 GUI程序
将“拼图图像”文件夹存放在包名目录的父目录中(这里需要保存在D:\中),在“拼图图像”文件夹里需要有名字是default.jpg的图像(代码需要)。
按照源文件中的包语句将7.4节中相关的源文件保存到以下目录中:
D:\ch7\view
编译各个源文件,例如:
D:>javac ch7/view/PuzzlePad.java
也可以一次编译多个源文件:
D:>javac ch7/view/*.java
把7.2节和7.4节给出的类看作一个小框架,下面用框架中的类编写GUI应用程序,完成7.1节给出的设计要求。
将AppWindow.java源文件按照包名保存到以下目录中:
D:\ch7\gui
编译源文件:
D:>javac ch7/gui/AppWindow.java
运行AppWindow类(运行效果如本章开始给出的图7.1):
D:>java ch7.gui.AppWindow
AppWindow窗口有名字分别为“选择级别”和“选择图像”的菜单,级别依次为“初级”和“高级”。用户可以自己“选择一副新图像”或“使用默认像”,窗口中有单选按钮,名字依次为数字玩法和图像玩法,在同一时刻只能有一个处于选中状态。单击“开始”按钮可以开始游戏.用户单击“开始”按钮后,如果单选框数字处于被选中状态,那么程序所执行的操作就是让魔板使用数字魔板,如果单选框图像玩法被选中,那么程序所执行的操作就是让魔板使用图像魔板。这里将魔板添加到窗口的中心,将魔板的监视器添加到窗口的南侧。

AppWindow.java

package ch7.gui;
import java.awt.*;
import java.awt.event.*;
import java.swing.*;
import java.io.*;
import java.swing.filechooser.*;
import ch7.view.PuzzlePad;
public class AppWindow extends JFrame implements Actionlistener{
    PuzzlePad puzzlePad;
    JMenuBar bar;
    JMenu gradeMenu,choiceImage;
    JMenuItem oneGrade,twoGrade,newImage,defaultImage;
    JRadioButton digitPlay,imagePlay;
    ButtonGroup group=null;
    JButton startButton;
    Image image;
    Toolkit tool;
    public AppWindow(){
        tool=getToolkit();
        bar=new JMenuBar();
        gradeMenu=new JMenu("选择级别");
        choiceImage=new JMenu("选择图像");
        oneGrade=new JMenuItem("初级");
        twoGrade=new JMenuItem("高级");
        newImage=new JMenuItem("选择一幅新图像");
        defaultImage=new JMenuItem("使用默认图像"); 
        gradeMenu.add(oneGrade);
        gradeMenu.add(twoGrade);
        choiceImage.add(newImage);
        choiceImage.add(defaultImage);
        bar.add(gradeMenu);
        bar.add(choiceImage);
        setJMenuBar(bar);
        oneGrade.addActionListener(this);
        twoGrade.addActionListener(this);
        newImage.addActionListener(this);
        defaultImage.addActionListener(this);
        startButton=new JButton("开始");
        startButton.addActionListener(this);
        group=new ButtonGroup();
        digitPlay=new JRadioButton("数字玩法",true);
        imagePlay=new JRadioButton("图像玩法",false);
        group.add(digitPlay);
        group.add(imagePlay);
        puzzlePad=new PuzzlePad();
        puzzlePad.setGrade(1);
        puzzlePad.setIsDigitPlay();                
        add(puzzlePad,BorderLayout.CENTER);
        JPanel pNorth=new JPanel();
        pNorth.add(digitPlay);
        pNorth.add(imagePlay); 
        pNorth.add(startButton);
        pNorth.add(new JLabel("如果图像不能立刻显示,请再单击一次按扭"));
        add(pNorth,BorderLayout.NORTH);
        add(puzzlePad.getHandleMove(),BorderLayout.SOUTH);
        validate();
        setVisible(true);
        setBounds(100,50,550,380);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        try{
             image=tool.createImage(new File("拼图图像/default.jpg").toURI().toURL());
             puzzlePad.setImage(image);
        }
        catch(Exception exp){
} 
  	}
 public void actionPerformed(ActionEvent e){
       if(e.getSource()==startButton){
           if(digitPlay.isSelected()){
                puzzlePad.setIsDigitPlay();
           }
           else if(imagePlay.isSelected()){
              puzzlePad.setImage(image);
              puzzlePad.setIsImagePlay();
           }
       } 
       else if(e.getSource()==oneGrade){
           puzzlePad.setGrade(1);
       }
       else if(e.getSource()==twoGrade){
           puzzlePad.setGrade(2);
       }
       else if(e.getSource()==newImage){
          FileNameExtensionFilter filter = new FileNameExtensionFilter(
          "JPG & GIF Images", "jpg", "gif");
           JFileChooser chooser=new JFileChooser();
           chooser.setFileFilter(filter); 
           int state=chooser.showOpenDialog(null);
           File file=chooser.getSelectedFile();
           if(file!=null&&state==JFileChooser.APPROVE_OPTION){
              try{
               image=tool.createImage(file.toURI().toURL());
               puzzlePad.setImage(image);
              }
              catch(Exception exp){}  
           }
      }
      else if(e.getSource()==defaultImage){
          try{
              image=tool.createImage(new File("拼图图像/default.jpg").toURI().toURL());
              puzzlePad.setImage(image);
            }
          catch(Exception exp){
}  
      }
  }
  public static void main(String args[]){
      new AppWindow();
  }  
}

6 程序发布
用户可以使用jar.exe命令制作JAR文件来发布软件。
(1)清单文件
编写以下清单文件(用记事本保存时需要将保存类型选择为“所有文件(.)”。
ch7.mf
Manifest-Version: 1.0
Main-Class:ch7.gui.AppWindow
Created-By: 1.8
将ch.7mf保存到D:,即保存在包名所代表的目录的上一层目录中。
注意 清单中的Manifest-Version和1.0之间、Main-Class和主类ch7.gui.AppWindow之间以及Created-By和1.8之间必须有且只有一个空格。

(2)用批处理文件发布程序
在命令行中使用jar命令创建JAR文件。
D:>jar cfm PuzzleGame.jar ch7.mf ch7/data/.class ch7/view/.class ch7/
gui/.class
其中,参数c表示要生成一个新的JAR文件,f表示要生成的JAR文件的名字,m表示清单文件的名字。如果没有任何错误提示,在D:\下将产生一个名字是PuzzleGame.jar的文件。
编写以下puzzle.bat,用记事本保存该文件时需要将保存类型选择为“所有文件(
.*)”。
puzzle.bat
path.\jre\bin
pause
javaw -jar PuzzleGame.jar
将该文件保存到自己命名的某个文件夹中,例如名字是2000的文件夹中。然后将PuzzleGame.jar以及JRE(即调试程序使用的JDK安装目录下的JRE子目录)复制到2000文件夹中,将“拼图图像”文件夹也复制到2000文件夹中。
可以将2000文件夹作为软件发布,也可以用压缩工具将2000文件夹下的所有文件压缩成.zip或.jar文件发布。用户解压后双击puzzle.bat即可运行程序。
如果客户计算机上肯定有JRE,可以不把JRE复制到2000文件夹中,同时去除.bat文件中的“path.\jre\bin”内容。
7 课设题目
(1)改进魔板游戏
在学习本章代码的基础上改进魔板游戏,为程序增加任何合理的并有能力完成的功能,但至少要增加下列所要求的功能。
1、对相应的级别增加“英雄榜”功能(建议用户看第8 章的英雄榜一—chs.data.RccordOrShowRccord、 ch8.view.Record 和 ch8.view ShowRecord 类)。当用户成功排列魔板中的方块后,如果成绩能排进前3名就弹出一个对话框,将用户的成绩保存到 “英雄榜”。
2、能查看“英雄榜”。
3、在HandleMove 中增加播放音乐的功能模块,当用户移动方块后程序播放简短的一声音乐(可参见第8 章的 ch8.view.PlayMusic 类)。用Java 可以编写播放.au、aiff…wav、midi,rim 格式的音频。假设音频文件 hello.au 位于应用程序的当前目录中,对有关插放音乐的知识总 结如下:

➢创建 File 对象(File 类属于 java.io包)
File musicFile=new File(“hel1o.au”);

➢获取 URI对象 (URI 类属于 java.net 包)
URI uri=musicFile.toURI ();

➢获取 URL对象(URL 类属于java.net 包)
URI url=uri. toURI ();

➢创建音频对象(AudioClip类和Applet类属于java.applet包)
AudioClip clip=Applet.newAudioClip(url);

➢播放、循环与停止
clip.play()开始攝放,
clip.1oop ()福环播放,
clip.stop()停止播放。

4、将魔板游戏改成魔饭过关游戏,比如“10 关魔板”。用图像决定难度,因为有些图像好拼图,有些比较困难。用户过了一关后程序就可以自动出现下一关,也可以询问用户是否继续下一关。
(2)自定义题目
通过老师指导或自己查找资料自创一个题目。