1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > 扫雷游戏-Java课程设计

扫雷游戏-Java课程设计

时间:2021-04-14 10:56:25

相关推荐

扫雷游戏-Java课程设计

扫雷游戏

一、data1、Bolck2、LayMines3、PeopleScoutMine4、ViewForBlock5、RecordOrShowRecord 二、测试三、View1、BlockView2、MineArea3、Record读/写英雄榜的视图4、ShowRecord 四、GUI程序

一、data

1、Bolck

Block类:其实例是雷区中的方块。

Block的实例是雷区中的方块,方块可以是雷也可以不是雷。如果方块是雷,该方块的isMine属性值就是true, 否则是false。 当方块的isMine 属性值是false 时,该方块的aroundMineNumber属性值是和该方块相邻且是雷的方块数目(一个方块最多可以有8个相邻的方块)。当该方块的isMine属性值是true 时,minelcon 属性值是一个Imagelcon图标的实例(地雷的样子)。

比如说:aroundMineNumber=1,说明它周围的8个方块中,有一个是地雷。

用来获取、设置成员变量。

package ch8.data;import javax.swing.ImageIcon;//Block方块public class Block {String name; //名字,比如"雷"或数字int aroundMineNumber;//如果不是类,此数据是周围雷的数目。Mine地雷ImageIcon mineIcon; //雷的图标public boolean isMine=false; //是否是雷boolean isMark=false;//是否被标记boolean isOpen=false;//是否被挖开ViewForBlock blockView; //方块的视图//这里不是接口创建对象,是接口声明了一个引用。public void setName(String name) {this.name=name; }public String getName() {return name;}public void setAroundMineNumber(int n) {aroundMineNumber=n;}public int getAroundMineNumber() {return aroundMineNumber;}public boolean isMine() {return isMine;} public void setIsMine(boolean b) {isMine=b;}public void setMineIcon(ImageIcon icon){mineIcon=icon;}public ImageIcon getMineicon(){return mineIcon;}public boolean getIsOpen() {return isOpen;} public void setIsOpen(boolean p) {isOpen=p;}public boolean getIsMark() {return isMark;} public void setIsMark(boolean m) {isMark=m;}public void setBlockView(ViewForBlock view){blockView = view;blockView.acceptBlock(this);//确定是哪个方块的视图} public ViewForBlock getBlockView(){return blockView ;}}

2、LayMines

LayMines类:其实例负责在雷区布雷。即随机设置某些方块是雷。

package ch8.data;import java.util.LinkedList;import javax.swing.ImageIcon;//布置雷区的类public class LayMines {ImageIcon mineIcon;//ImageIcon类是图片图标类。根据图片绘制图标。public LayMines() {// 这是一个构造函数mineIcon=new ImageIcon("扫雷图片/mine.gif");}public void initBlock(Block [][] block){//初始化雷区for(int i=0;i<block.length;i++) {for(int j=0;j<block[i].length;j++)block[i][j].setIsMine(false);//当方块的isMine 属性值是false时,该方块的aroundMineNumber属性值是和该方块相邻且是雷的方块数目} }public void layMinesForBlock(Block [][] block,int mineCount){//在雷区布置mineCount个雷initBlock(block); //先都设置是无雷int row=block.length;int column=block[0].length;// LinkedList集合数据存储的结构是链表结构。方便元素添加、删除的集合。// 是一个双向链表// 这里创建了Block类型的LinkedList集合LinkedList<Block> list=new LinkedList<Block>(); for(int i=0;i<row;i++) {for(int j=0;j<column;j++)list.add(block[i][j]);} while(mineCount>0){//开始布雷int size=list.size(); // list返回节点的个数int randomIndex=(int)(Math.random()*size);Block b=list.get(randomIndex);b.setIsMine(true);//设置方块是雷b.setName("雷");b.setMineIcon(mineIcon);list.remove(randomIndex); //list删除索引值为randomIndex的节点mineCount--;} for(int i=0;i<row;i++){//检查布雷情况,标记每个方块周围的雷的数目for(int j=0;j<column;j++){if(block[i][j].isMine()){block[i][j].setIsOpen(false);block[i][j].setIsMark(false);}else {int mineNumber=0;for(int k=Math.max(i-1,0);k<=Math.min(i+1,row-1);k++) {for(int t=Math.max(j-1,0);t<=Math.min(j+1,column-1);t++){if(block[k][t].isMine())mineNumber++; }}block[i][j].setIsOpen(false); //是否被挖开block[i][j].setIsMark(false); //是否被标记block[i][j].setName(""+mineNumber);block[i][j].setAroundMineNumber(mineNumber); //设置该方块周围的雷数目}} } }}

3、PeopleScoutMine

PeopleScoutMine类的实例负责在雷区扫雷。该实例使用方法StackgetNoMineAroundBlock(Block bk)寻找不是雷的方块,并将找到的方块压入堆栈,然后返回该堆栈。

如果参数bk不是雷,但bk相邻的方块中有方块是雷,那么找到的不是雷的方块就是bk。如果bk不是雷,但bk相邻的方块中没有任何一个方块是雷,那么就把相邻的方块作为getNoMineAroundBlock(Block bk)方法的参数继续调用该方法,即PeopleScoutMine类的实例用递归方法寻找一个方块周围区域内不是雷的方块,并将这些方块压入堆栈,返回该堆栈。该实例使用方法public boolean verifyWin()判断用户是否扫雷成功。如果剩余的、没有揭开的方块数目刚好等于雷区的总雷数,该方法返回true,否则返回false.

package ch8.data;import java.util.Stack;public class PeopleScoutMine {public Block [][] block; //雷区的全部方块Stack<Block> notMineBlock; //存放一个方块周围区域内不是雷的方块int m,n ; //方块的索引下标int row,colum; //雷区的行和列int mineCount; //雷的数目// 构造方法,public PeopleScoutMine(){notMineBlock = new Stack<Block>();// 寻找不是雷的方块,并将找到的方块压入堆栈}public void setBlock(Block [][] block,int mineCount){this.block = block;this.mineCount = mineCount;row = block.length;colum = block[0].length;}// 什么是bk?如果参数bk不是雷,但bk相邻的方块中有方块是雷,那么找到的不是雷的方块就是bk。public Stack<Block> getNoMineAroundBlock(Block bk){//得到方块bk附近区域不是雷的方块notMineBlock.clear();for(int i=0;i<row;i++) {//寻找bk在雷区block中的位置索引for(int j=0;j<colum;j++) {if(bk == block[i][j]){m=i;n=j;break;}}}if(!bk.isMine()) {//方块不是雷show(m,n); //见后面的递归方法}return notMineBlock;}public void show(int m,int n) {//如果周围雷的数目>0,并且没有被挖开过。if(block[m][n].getAroundMineNumber()>0&&block[m][n].getIsOpen()==false){// 将它挖开,将将不是雷的方块压栈block[m][n].setIsOpen(true);notMineBlock.push(block[m][n]); //将不是雷的方块压栈return;// 寻找不是雷的方块,并将找到的方块压入堆栈,然后返回该堆栈。}else if(block[m][n].getAroundMineNumber()==0&&block[m][n].getIsOpen()==false){/*如果bk不是雷,但bk相邻的方块中没有任何一个方块是雷,那么就把相邻的方块作为getNoMineAroundBlock(Block bk)方法的参数继续调用该方法,即PeopleScoutMine类的实例用递归方法寻找一个方块周围区域内不是雷的方块,并将这些方块压入堆栈,返回该堆栈。*/block[m][n].setIsOpen(true);notMineBlock.push(block[m][n]); //将不是雷的方块压栈for(int k=Math.max(m-1,0);k<=Math.min(m+1,row-1);k++) {for(int t=Math.max(n-1,0);t<=Math.min(n+1,colum-1);t++)show(k,t);} }}public boolean verifyWin(){boolean isOK = false;int number=0;for(int i=0;i<row;i++) {for(int j=0;j<colum;j++) {if(block[i][j].getIsOpen()==false)number++;}}/*使用方法public boolean verifyWin()判断用户是否扫雷成功。如果剩余的、没有揭开的方块数目刚好等于雷区的总雷数,胜利!该方法返回true,否则返回false.*/if(number==mineCount){isOK =true;}return isOK;}}

4、ViewForBlock

方块需要一个外观提供给游戏的玩家,以便玩家单击方块或标记方块进行扫雷。ViewForBlock接口封装了给出视图的方法,

例如void acceptBlock(Block block)方法确定该视图为哪个Block实例提供视图。

实现ViewFor接口的类将在视图(View) 设计部分给出,见稍后8.4节中的BlockView类。

package ch8.data;public interface ViewForBlock {public void acceptBlock(Block block); //确定是哪个方块的视图public void setDataOnView(); //设置视图上需要显示的数据public void seeBlockNameOrIcon(); //显示图标方块上的名字或图标public void seeBlockCover(); //显示视图上负责遮挡的组件public Object getBlockCover();//得到视图上的遮挡组件}

5、RecordOrShowRecord

使用内置Derby数据库record存放玩家的成绩(有关内置Derby数据库的知识点可参见本书的第3章)。数据库使用表存放成绩,即表示英雄榜。

表中的字段p_ name的值是玩家的名字,字段P_time 是玩家的用时。玩家只要排进前3名就可以进入英雄榜,英雄榜上原有的第3名就退居到第4名(英雄榜记录着曾经的扫雷英雄)。

RecordOrShowRecord类的实例可以向英雄榜插入记录或查看英雄榜。

有关知识:

try{Class.forName(“org.apache.derby.jdbc.EmbeddedDriver”);

derby是apache的一个开源数据库产品,有丰富的特性。它支持client/server模式外,也支持embedded模式,即只需一个包含embedded driver的jar包,就可以在代码内启动及关闭数据库。在小项目中使用嵌入式的数据库也是一个不错的选择。

这里使用jdbc来连接derby进行操作并无特别之处。只需要将embedded driver包derby.jar包含进class_path,将创建driver实例,使用通常jdbc代码即可访问。

顺便记一下jdbc访问数据库的过程,尽管以上代码可以演示说明:

(1)所有相关类及接口都在包java.sql中。另外还有javax.sql,都是扩展内容

(2)由DriverManager获得到要连接数据库的Connection

(3)Connection创建Statement或PreparedStatement

(4)Statement或PreparedStatement执行sql语句,有可能返回ResultSet结果集。可以对ResultSet进行遍历访问

(5)若有insert/update/delete等数据操作,需调用Connection的commit().(如果设置为不自动提交)

(6)conn.close()断开与数据库的连接。

package ch8.data;import java.sql.*;public class RecordOrShowRecord{Connection con;// Connection接口代表与特定的数据库的连接.要对数据表中的数据进行操作,首先要获取数据库连接.String tableName ;int heroNumber = 3; //英雄榜显示的最多英雄数目public RecordOrShowRecord(){//构造方法try{Class.forName("org.apache.derby.jdbc.EmbeddedDriver");}catch(Exception e){}}// 设置数据库表名,人名,时间public void setTable(String str){tableName = "t_"+str;connectDatabase();//连接数据库try {Statement sta = con.createStatement();String SQL="create table "+tableName+"(p_name varchar(50) ,p_time int)";sta.executeUpdate(SQL);//创建表con.close();}catch(SQLException e) {//如果表已经存在,将触发SQL异常,即不再创建该表}}public boolean addRecord(String name,int time){boolean ok = true;if(tableName == null)ok = false;//检查time是否达到标准(进入前heroNumber名),见后面的verifyScore方法:int amount = verifyScore(time);//如果数量大于等于3名,不加入英雄榜if(amount >= heroNumber) {ok = false; }else {connectDatabase(); //连接数据库try {String SQL ="insert into "+tableName+" values(?,?)";PreparedStatement sta = con.prepareStatement(SQL);sta.setString(1,name);sta.setInt(2,time);sta.executeUpdate();con.close();ok = true;}catch(SQLException e) {ok = false;}}return ok;}// 查询数据库记录public String [][] queryRecord(){if(tableName == null)return null;String [][] record = null;Statement sql; ResultSet rs;try {sql=con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);String str = "select * from "+tableName+" order by p_time ";rs=sql.executeQuery(str);boolean boo =rs.last(); if(boo == false)return null;int recordAmount =rs.getRow();//结果集中的全部记录record = new String[recordAmount][2];rs.beforeFirst();int i=0;while(rs.next()) {record[i][0] = rs.getString(1);record[i][1] = rs.getString(2);i++;}con.close();}catch(SQLException e) {}return record;}//连接数据库private void connectDatabase(){try{String uri ="jdbc:derby:record;create=true";con=DriverManager.getConnection(uri); //连接数据库,如果不存在就创建}catch(Exception e){} }//判断英雄榜记录是不是已经超过3个了private int verifyScore(int time){if(tableName == null)return Integer.MAX_VALUE ;connectDatabase(); //连接数据库Statement sql; ResultSet rs;int amount = 0;String str ="select * from "+tableName+" where p_time < "+time;try {sql=con.createStatement();rs=sql.executeQuery(str);while(rs.next()){amount++;} con.close();}catch(SQLException e) {}return amount;}}

二、测试

把8.2节给出的类看作一个小框架,下面用框架中的类编写一个简单的应用程序,测试扫雷,即在命令行表述对象的行为过程,如果表述成功(如果表述困难,说明数据模型不是很合理) ,那么就为以后的GUI程序设计提供了很好的对象功能测试,

在后续的GUI设计中,重要的工作仅仅是为某些对象提供视图界面,并处理相应的界面事件而已。

package ch8.test;import ch8.data.*;import java.util.Stack;public class AppTest {public static void main(String [] args) {Block block[][] = new Block[5][10]; //雷区for(int i=0;i<block.length;i++) {for(int j = 0;j<block[i].length;j++) {block[i][j] = new Block();}}LayMines layMines = new LayMines(); //布雷者PeopleScoutMine peopleScoutMine = new PeopleScoutMine(); //扫雷者layMines.layMinesForBlock(block,10); //在雷区布10个雷System.out.println("雷区情况:");intputShow(block);peopleScoutMine.setBlock(block,10); //准备扫雷 Stack<Block> stack = peopleScoutMine.getNoMineAroundBlock(block[0][0]);//扫雷if(block[0][0].isMine()){System.out.println("我的天啊,踩着地雷了啊");return;}System.out.println("扫雷情况:");intputProcess(block,stack);System.out.println("成功了吗:"+peopleScoutMine.verifyWin());if(block[3][3].isMine()){System.out.println("我的天啊,踩着地雷了啊");return;}stack = peopleScoutMine.getNoMineAroundBlock(block[3][3]);//扫雷System.out.println("扫雷情况:");intputProcess(block,stack);System.out.println("成功了吗:"+peopleScoutMine.verifyWin());}static void intputProcess(Block [][] block,Stack<Block> stack){int k = 0;for(int i=0;i<block.length;i++) {for(int j = 0;j<block[i].length;j++){if(!stack.contains(block[i][j])&&block[i][j].getIsOpen()==false){System.out.printf("%2s","■ "); //输出■表示未挖开方块}else {int m = block[i][j].getAroundMineNumber();//显示周围雷的数目System.out.printf("%2s","□"+m);}}System.out.println();} }static void intputShow(Block [][] block){int k = 0;for(int i=0;i<block.length;i++) {for(int j = 0;j<block[i].length;j++){if(block[i][j].isMine()){System.out.printf("%2s","#"); //输出#表示是地雷}else {int m = block[i][j].getAroundMineNumber();//显示周围雷的数目System.out.printf("%2s",m);}}System.out.println();} }}

三、View

设计GUI程序除了使用8.2节给出的类以外,需要使用javaxswing包提供的视图(也称Java Swing框架)以及处理视图上触发的界面事件。与8.3节中简单的测试相比,GUI 程序可以提供更好的用户界面,完成8.1 节提出的设计要求。

1、BlockView

BlockView类是javax.swing.JPanel 的子类,其实例为方块(Block)提供视图,以便用户通过该视图与Block对象交互。BlockView 对象使用一个标签和按钮为Block对象提供视图,标签和按钮按照卡片布局(CardLayout) 层叠在一起,

**在默认状态下按钮遮挡住标签,即标签在按钮的下面。**用户单击视图中的按钮后,如果Block对象是雷,BockView对象中的标签显示的是雷的图标;如果Block 对象不是雷,标签显示的是和当前方块相邻且是雷的方块总数。

BlockView类中的setDataOnView(方法设置视图中需要显示的数据。

例如,

如果Block对象的isMine属性为true (方块是雷),那么setDataOnView0方法就将blockNameOrIcon标签的文本设置为Block对象的name属性的值,同时将blockNameOrIcon标签的图标设置为Block对象的minelcon属性指定的图标。

如果Block对象的isMine属性为false(方块不是雷),.就将blockNameOrIcon标签的文本设置为Block对象的aroundMineNumber属性的值,即周围雷的数目(效果如图8.5所示)。

seeBlockNameOrIcon()方法让用户看见视图中的标签,无法看见按钮;

seeBlockCover()方法让用户看见视图中的按钮,无法看见标签。

package ch8.view;import javax.swing.*;import java.awt.*;import ch8.data.*;public class BlockView extends JPanel implements ViewForBlock{JLabel blockNameOrIcon; //用来显示Block对象的name、number和mineIcon属性JButton blockCover;//用来遮挡blockNameOrIcon.CardLayout card; //卡片式布局Block block ; //被提供视图的方块BlockView(){//构造方法// 设置卡片式布局card=new CardLayout();setLayout(card);blockNameOrIcon=new JLabel("",JLabel.CENTER);blockNameOrIcon.setHorizontalTextPosition(AbstractButton.CENTER);blockNameOrIcon.setVerticalTextPosition(AbstractButton.CENTER); blockCover=new JButton();add("cover",blockCover);//按钮add("view",blockNameOrIcon);//标签// 用按钮遮挡标签}// 确定是哪个方块的视图public void acceptBlock(Block block){this.block = block;}public void setDataOnView(){if(block.isMine()){blockNameOrIcon.setText(block.getName());blockNameOrIcon.setIcon(block.getMineicon());}else {//如果不是雷,此数据是周围雷的数目。Mine地雷int n=block.getAroundMineNumber();if(n>=1)//有雷的话,JLabel的text为nblockNameOrIcon.setText(""+n);else//没有雷的话,JLabel的text为空blockNameOrIcon.setText(" ");}}public void seeBlockNameOrIcon(){//让用户看见视图中的标签,无法看见按钮;card.show(this,"view");validate();}public void seeBlockCover(){//让用户看见视图中的按钮,无法看见标签。card.show(this,"cover");validate();//确保组件具有有效的布局。此类主要适用于在 Container 实例上进行操作。可以不写//当提交一个表单时,响应的baiactionfrom会先按照你写的validate方法对表单数du据进行验证.//如果不正确则会返回到提交页面,并且可以显示错误信息.}public JButton getBlockCover() {return blockCover;} }

2、MineArea

MineArea是javax swing.JPanel的子类,其实例是雷区(效果如图8.6所示),雷区同时

指定自己作为当前视图上界面事件的事件监视器。用户单击方块视图触发ActionEvent事件

后,如果方块是雷,用户就输掉了扫雷游戏,程序播放雷爆炸的声音;如果不是雷,雷区就

让扫雷者开始扫雷(找出周围不是雷的方块)。

用户在方块上右击,可以将某个方块标记(用小红旗)为是雷(但不一定真是雷,看探

雷水平),再次单击可取消所作的标记。

用户扫雷成功:剩余的、没有揭开的方块数目刚好等于雷区的总雷数,则由Record的实

例负责判断用户是否可上英雄榜。

package ch8.view;import java.awt.*;import java.awt.event.*;import javax.swing.*;import ch8.data.*;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Stack;public class MineArea extends JPanel implements ActionListener,MouseListener{//先弄两个面板,然后通过边界布局(Border),布局到上面和中间。JButton reStart; //从新开始按钮Block [][] block; //雷区的方块BlockView [][] blockView;//方块的视图LayMines lay; //负责布雷PeopleScoutMine peopleScoutMine; //负责扫雷int row,colum,mineCount,markMount;//雷区的行数、列数以及地雷个数和用户给出的标记数ImageIcon mark; //探雷作的标记String grade; //游戏级别 JPanel pCenter,pNorth,pSouth; //布局用的面板JTextField showTime,showMarkedMineCount; //显示用时和探雷作的标记数目(不一定是雷哦)Timer time;//计时器int spendTime=0; //扫雷的用时Record record; //负责记录到英雄榜PlayMusic playMusic; //负责播放雷爆炸的声音PlayMusic2 playMusic2; //负责点击没雷时的声音JLabel bjTimeLabel = new JLabel("00:00:00");JButton bjTimeButton = new JButton("兄弟看看时间,别玩的太晚!");public MineArea(int row,int colum,int mineCount,String grade) {record = new Record(); //负责保存成绩到英雄榜reStart=new JButton("重新开始");//JButtonmark=new ImageIcon("扫雷图片/mark.png"); //探雷标记ImageIcontime=new Timer(1000,this);//计时器,每个一秒触发ActionEvent事件一次showTime=new JTextField(5);//JTextFieldshowMarkedMineCount=new JTextField(5);//JTextField。探雷作的标记数目showTime.setHorizontalAlignment(JTextField.CENTER);//设置居中显示showMarkedMineCount.setHorizontalAlignment(JTextField.CENTER);showMarkedMineCount.setFont(new Font("Arial",Font.BOLD,16));//设置字体showTime.setFont(new Font("Arial",Font.BOLD,16));pCenter=new JPanel();//中心面板pNorth=new JPanel();//上面面板pSouth=new JPanel();//下面面板lay=new LayMines(); //创建布雷者peopleScoutMine = new PeopleScoutMine(); //创建扫雷者initMineArea(row,colum,mineCount,grade); //初始化雷区,见下面的initMineArea方法reStart.addActionListener(this);pNorth.add(new JLabel("剩余雷数:"));pNorth.add(showMarkedMineCount);pNorth.add(reStart);pNorth.add(new JLabel("用时:"));pNorth.add(showTime);pSouth.add(bjTimeLabel);pSouth.add(bjTimeButton);//lambda表达式是一个匿名函数,代替匿名的内部类bjTimeButton.addActionListener( (e)->{beiJingTime();});setLayout(new BorderLayout());//设置边界布局add(pNorth,BorderLayout.NORTH);//将面板加入到边界布局当中add(pCenter,BorderLayout.CENTER);add(pSouth,BorderLayout.SOUTH);playMusic = new PlayMusic(); //负责播放触雷爆炸的声音playMusic.setClipFile("扫雷图片/mine.wav");playMusic2 = new PlayMusic2(); //负责播放触雷爆炸的声音playMusic2.setClipFile("扫雷图片/真正技术.wav");}//这是一个方法,用来显示目前的北京时间public void beiJingTime(){SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");String timestr = sdf.format(new Date());bjTimeLabel.setText( timestr );}public void initMineArea(int row,int colum,int mineCount,String grade){//雷区的行数、列数以及地雷个数、游戏级别pCenter.removeAll();//移除中心面板东西spendTime=0;//设置时间为0markMount=mineCount;this.row=row;this.colum=colum;this.mineCount=mineCount; this.grade=grade; block=new Block[row][colum];//设置雷区的方块for(int i=0;i<row;i++){for(int j=0;j<colum;j++)block[i][j]=new Block();}lay.layMinesForBlock(block,mineCount);//布雷peopleScoutMine.setBlock(block,mineCount); //准备扫雷 blockView=new BlockView[row][colum]; //创建方块的视图pCenter.setLayout(new GridLayout(row,colum));//中心面板通过网格布局GridLayout来说实现。for(int i=0;i<row;i++) {for(int j=0;j<colum;j++) {blockView[i][j]=new BlockView(); block[i][j].setBlockView(blockView[i][j]); //方块设置自己的视图blockView[i][j].setDataOnView(); //将block[i][j]的数据放入视图pCenter.add(blockView[i][j]);blockView[i][j].getBlockCover().addActionListener(this);//注册监视器blockView[i][j].getBlockCover().addMouseListener(this);//鼠标监听器blockView[i][j].seeBlockCover(); //初始时盖住block[i][j]的数据信息blockView[i][j].getBlockCover().setEnabled(true);blockView[i][j].getBlockCover().setIcon(null);}}showMarkedMineCount.setText(""+markMount); repaint();/*如果你需要某个部件刷新一下界面,记得调用repaint().它是在图形线程后追加一段重绘操作,是安全的!是系统真正调用的重绘!*/}public void setRow(int row){this.row=row;}public void setColum(int colum){this.colum=colum;}public void setMineCount(int mineCount){this.mineCount=mineCount;}public void setGrade(String grade) {this.grade=grade;}//点击事件发生时,被系统自动调用/*(1)创建监听器对象listener(2)将监听器对象交给按钮(3)当按钮被点击时,Swing框架会调用监听器对象里的方法,进行事件处理。*/public void actionPerformed(ActionEvent e) {if(e.getSource()!=reStart&&e.getSource()!=time) {time.start(); int m=-1,n=-1; for(int i=0;i<row;i++) {//找到单击的方块以及它的位置索引for(int j=0;j<colum;j++) {if(e.getSource()==blockView[i][j].getBlockCover()){m=i;n=j;break;}}} if(block[m][n].isMine()) {//用户输掉游戏for(int i=0;i<row;i++) {for(int j=0;j<colum;j++) {blockView[i][j].getBlockCover().setEnabled(false);//用户单击无效了if(block[i][j].isMine())blockView[i][j].seeBlockNameOrIcon(); //视图显示方块上的数据信息}}time.stop();spendTime=0; //恢复初始值markMount=mineCount;//恢复初始值playMusic.playMusic(); //播放类爆炸的声音}else {//扫雷者得到block[m][n]周围区域不是雷的方块Stack<Block> notMineBlock =peopleScoutMine.getNoMineAroundBlock(block[m][n]);while(!notMineBlock.empty()){Block bk = notMineBlock.pop();ViewForBlock viewforBlock = bk.getBlockView();viewforBlock.seeBlockNameOrIcon();//视图显示方块上的数据信息System.out.println("ookk");playMusic2.playMusic();//播放未点击到雷的声音}}}if(e.getSource()==reStart) {initMineArea(row,colum,mineCount,grade);repaint();validate();}if(e.getSource()==time){spendTime++;showTime.setText(""+spendTime);}if(peopleScoutMine.verifyWin()) {//判断用户是否扫雷成功time.stop();record.setGrade(grade); record.setTime(spendTime);record.setVisible(true); //弹出录入到英雄榜对话框}}public void mousePressed(MouseEvent e){//探雷:给方块上插一个小旗图标(再次单击取消)JButton source=(JButton)e.getSource();/*getSource():获得你目前这个事件的事件源,比如有一个按钮事件,你点击一个按钮,在处理事件中你用e.getSource(),就是获得这个按钮.JButton a=(JButton)e.getSource();把事件源转换成你点击的那个对象类。这样你的a就可以用JButton里面的变量与方法了。*/for(int i=0;i<row;i++) {for(int j=0;j<colum;j++) {if(e.getModifiers()==InputEvent.BUTTON3_MASK&&/*JAVA 反射机制中,Field的getModifiers()方法返回int类型值表示该字段的修饰符。*/source==blockView[i][j].getBlockCover()){if(block[i][j].getIsMark()) {source.setIcon(null);block[i][j].setIsMark(false);markMount=markMount+1;showMarkedMineCount.setText(""+markMount);}else{source.setIcon(mark);block[i][j].setIsMark(true);markMount=markMount-1;showMarkedMineCount.setText(""+markMount);}} }}}public void mouseReleased(MouseEvent e){}//假设鼠标在A点被按下,然后一直不松开,然后移动到B点松开,此时触发的是 mouseReleased 事件public void mouseEntered(MouseEvent e){}//是鼠标刚进入组件的时候调用(只调用一次)public void mouseExited(MouseEvent e){}//是鼠标刚进入组件的时候退出public void mouseClicked(MouseEvent e){}//假设鼠标一直停留在A点,往下按然后放开,此时触发的是 mouseClicked 事件}

3、Record读/写英雄榜的视图

Record类是javax .swing.JDialog的子类,其实例是对话框,提供用户输入姓名的界面。用户输入姓名后对话框自动获得用户的成绩,然后委托RecordOrShowRecord的实例检查用户是否可上英雄榜。如果可以上英雄榜,就将用户姓名和绩录入英雄榜,否则提示用户不能上榜(效果如图8.7所示)

package ch8.view;import javax.swing.*;import java.awt.event.*;import ch8.data.RecordOrShowRecord;public class Record extends JDialog implements ActionListener{int time=0;String grade=null;//等级String key=null;String message=null;JTextField textName; JLabel label=null; JButton confirm,cancel;public Record(){//这是一个构造方法setTitle("记录你的成绩");this.time=time; this.grade=grade;setBounds(100,100,240,160);//设置弹出窗口的效果setResizable(false);//设置此窗体是否可由用户调整大小。// resizeable值为false时,表示生成的窗体大小是由程序员决定的,用户不可以自由改变该窗体的大小。setModal(true);//modal-指定 dialog是否阻止在显示的时候将内容输入其他窗口。//也就是说,“有模式”意味着该窗口打开时其他窗口都被屏蔽了,在此情况下,点击程序的其他窗口是不允许的。confirm=new JButton("确定");cancel=new JButton("取消");textName=new JTextField(8);textName.setText("匿名");confirm.addActionListener(this);cancel.addActionListener(this);setLayout(new java.awt.GridLayout(2,1));//设置网格布局label=new JLabel("输入您的大名看是否可上榜");add(label);JPanel p=new JPanel();//p面板p.add(textName);p.add(confirm);p.add(cancel);add(p);setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);//设置用户在此窗体上发起 "close" 时默认执行的操作。//调用任意已注册的 WindowListener 对象后自动隐藏该窗体。}public void setGrade(String grade){this.grade=grade;}public void setTime(int time){this.time=time;}//点击事件发生时,被系统自动调用/*(1)创建监听器对象listener(2)将监听器对象交给按钮(3)当按钮被点击时,Swing框架会调用监听器对象里的方法,进行事件处理。*/public void actionPerformed(ActionEvent e){if(e.getSource()==confirm){String name = textName.getText();//获取单行文本内容writeRecord(name,time);setVisible(false);//setVisible(true);//方法的意思是说数据模型已经构造好了,// 允许JVM可以根据数据模型执行paint方法开始画图并显示到屏幕上了,并不是显示图形,而是可以运行开始画图了}if(e.getSource()==cancel){setVisible(false);} }public void writeRecord(String name,int time){RecordOrShowRecord rd = new RecordOrShowRecord();//使用内置Derby数据库record存放玩家的成绩//数据库使用表存放成绩,即表示英雄榜。rd.setTable(grade);//将数据库等级作为参数传入方法中。设置数据库表名,人名,时间//传入名字和时间,增加记录boolean boo= rd.addRecord(name,time);if(boo){JOptionPane.showMessageDialog//JOptionPane是一种对话框的便捷使用形式(null,"恭喜您,上榜了","消息框", JOptionPane.WARNING_MESSAGE);//showMessageDialog 显示消息对话框}else {JOptionPane.showMessageDialog(null,"成绩不能上榜","消息框", JOptionPane.WARNING_MESSAGE); } }}

4、ShowRecord

ShowRecord类是javax.swing.JDialog的子类,其实例是对话框,提供显示英雄榜的界面,可以按成绩从高到低显示曾经登上过英雄榜的英雄们(效果如图8.8所示)

package ch8.view;import java.awt.*;import javax.swing.*;import ch8.data.RecordOrShowRecord;public class ShowRecord extends JDialog {String [][] record;JTextArea showMess;//一个显示纯文本的多行区域RecordOrShowRecord rd;//负责查询数据库的对象public ShowRecord() {rd = new RecordOrShowRecord();showMess = new JTextArea();showMess.setFont(new Font("楷体",Font.BOLD,15));add(new JScrollPane(showMess));//JScrollPane 管理视口、可选的垂直和水平滚动条以及可选的行和列标题视口。setTitle("显示英雄榜");setBounds(400,200,400,300);setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);//调用任意已注册 WindowListener 的对象后自动隐藏并释放该窗体。}public void setGrade(String grade){rd.setTable(grade);}public void setRecord(String [][]record){this.record=record;}public void showRecord() {showMess.setText(null);record = rd.queryRecord();//RecordOrShowRecord负责查询数据库的对象,查询数据库记录if(record == null ) {JOptionPane.showMessageDialog(null,"没人上榜呢","消息框", JOptionPane.WARNING_MESSAGE);} else {for(int i =0 ;i<record.length;i++){int m = i+1;showMess.append("\n英雄"+m+":"+record[i][0]+" "+"成绩:"+record[i][1]);showMess.append("\n--------------------------------");}setVisible(true);}}}

四、GUI程序

Derby是一个纯Java实现、开源的数据库管理系统。

AppWindow窗口中有“扫雷游戏”菜单,该菜单中有“初级”“中级”和“高级”子菜

单,3个子菜单分别有查看当前级别英雄榜的菜单项。用户选择相应级别的菜单,窗口中呈

现相应级别的雷区,选择某级别下的英雄榜菜单项可以查看该级别的英雄榜。

package ch8.gui;import java.awt.*;import javax.swing.*;import javax.swing.event.*;import java.awt.event.*;import ch8.view.MineArea;import ch8.view.ShowRecord;public class AppWindow extends JFrame implements MenuListener,ActionListener{JMenuBar bar;//菜单栏JMenu fileMenu;//菜单JMenu gradeOne,gradeTwo,gradeThree,gradeFour;//扫雷级别JMenuItem gradeOneList,gradeTwoList,gradeThreeList;//初,中,高级英雄榜,菜单项目MineArea mineArea=null;//扫雷区域ShowRecord showHeroRecord=null; //查看英雄榜public AppWindow(){bar=new JMenuBar();//创建一个菜单栏fileMenu=new JMenu("扫雷游戏");//菜单栏上命名一个gradeOne=new JMenu("初级");gradeTwo=new JMenu("中级");gradeThree=new JMenu("高级");gradeFour=new JMenu("自定义难度");gradeOneList=new JMenuItem("初级英雄榜");gradeTwoList=new JMenuItem("中级英雄榜");gradeThreeList=new JMenuItem("高级英雄榜");gradeOne.add(gradeOneList);//将菜单项,加入到菜单中gradeTwo.add(gradeTwoList);gradeThree.add(gradeThreeList);fileMenu.add(gradeOne);fileMenu.add(gradeTwo);fileMenu.add(gradeThree);fileMenu.add(gradeFour);bar.add(fileMenu);setJMenuBar(bar);gradeOne.addMenuListener(this);gradeTwo.addMenuListener(this);gradeThree.addMenuListener(this);// gradeFour.addMenuListener(this);//点击事件发生时,被系统自动调用/*(1)创建监听器对象listener(2)将监听器对象交给菜单(3)当按钮被点击时,Swing框架会调用监听器对象里的方法,进行事件处理。*///当点击到自定义难度时gradeFour.addMenuListener(new MenuListener(){@Overridepublic void menuSelected(MenuEvent menuEvent) {test3();}@Overridepublic void menuDeselected(MenuEvent menuEvent) {}@Overridepublic void menuCanceled(MenuEvent menuEvent) {}});gradeOneList.addActionListener(this);gradeTwoList.addActionListener(this);gradeThreeList.addActionListener(this);//扫雷区域mineArea=new MineArea(9,9,10,gradeOne.getText());//创建初级扫雷区add(mineArea,BorderLayout.CENTER);//将扫雷区域放在,边界布局的中间showHeroRecord=new ShowRecord();//创建英雄榜对象。查看英雄榜setBounds(300,100,500,450);//设置窗口位置和大小setVisible(true);/*setVisible(true);方法的意思是说数据模型已经构造好了,允许JVM可以根据数据模型执行paint方法开始画图并显示到屏幕上了,并不是显示图形,而是可以运行开始画图了*/setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置用户在此窗体上发起 "close" 时默认执行的操作。//使用 System exit 方法退出应用程序。仅在应用程序中使用。validate();}public void menuSelected(MenuEvent e){//在菜单上如果选择了,初级、中级、高级的情况if(e.getSource()==gradeOne){mineArea.initMineArea(9,9,10,gradeOne.getText());validate(); } else if(e.getSource()==gradeTwo){mineArea.initMineArea(13,13,30,gradeTwo.getText());validate();} else if(e.getSource()==gradeThree){mineArea.initMineArea(15,15,40,gradeThree.getText());validate();}}// 自定义难度时的简单数据输入框private void test3(){String input1 = JOptionPane.showInputDialog(this,"111行行行","18");String input2 = JOptionPane.showInputDialog(this,"222列列列","18");String input3 = JOptionPane.showInputDialog(this,"333雷雷雷","30");int a = Integer.parseInt(input1);int b = Integer.parseInt(input2);int c = Integer.parseInt(input3);mineArea.initMineArea(a, b, c, gradeThree.getText());validate();}public void menuCanceled(MenuEvent e){}//菜单取消public void menuDeselected(MenuEvent e){}//菜单取消选择/*获得你目前这个事件的事件源,比如有一个按钮事件,你点击一个按钮,在处理事件中你用e.getSource(),就是获得这个按钮,你可以这样写JButton a=(JButton)e.getSource();把事件源转换成你点击的那个对象类。这样你的a就可以用JButton里面的变量与方法了。*/public void actionPerformed(ActionEvent e){if(e.getSource()==gradeOneList){showHeroRecord.setGrade(gradeOne.getText());//设置等级,获得英雄榜内容showHeroRecord.showRecord();}else if(e.getSource()==gradeTwoList){showHeroRecord.setGrade(gradeTwo.getText());showHeroRecord.showRecord();}else if(e.getSource()==gradeThreeList){showHeroRecord.setGrade(gradeThree.getText());showHeroRecord.showRecord();}}public static void main(String args[]){new AppWindow();}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。