这段时间,为了复习Java2的GUI编程,参考有关资料,写了一个扫雷的小程序,只是写得很清楚,希望能给大家一些帮助!呵呵 /** * @(#)Block.java *该类用于创建Block对象,将其放到游戏区的每个格子里面,里面存放着该“格子”的一些属性: * ************************* * ——1. String name -->是雷时,存入“雷” * 属性 ——|-2. boolean boo -->是雷时,为true,否则为false。我称为“雷性” * ——3. int number -->用于存储周边,九回宫格内周边八个方格内的雷数 * ************************* * ——1. void setName(String name) -->设置name * |-2. void setNumber(int i) -->设置周边雷数 * 方法 ——|-3. int getNumber() -->得到周边雷数 * |-4. String getName() -->得到name * |-5. boolean isMine() -->判断雷性 * ——6. void setIsMine(boolean boo) -->设置雷性 * *********************** * * @author 宋俊林 * @version 1.00 2009/4/25 */ public class Block { String name; //是雷时,存入“雷” int number; //用于存储周边,九回宫格内周边八个方格内的雷数 boolean boo = false; //是雷时,为true,否则为false。我称为“雷性” //设置name public void setName(String name){ this.name = name; } //得到name public String getName(){ return name; } //设置周边雷数 public void setNumber(int i){ this.number = i; } //得到周边雷数 public int getNumber(){ return number; } //设置雷性 public void setIsMine(boolean boo){ this.boo = boo; } //判断雷性 public boolean isMine(){ return boo; } } /** * @(#)MineFrame.java * * 该类是主窗体类,该类将以Block类的实例和BlockView类的实例作为成员,并负责二者之间的交互 * * @author 宋俊林 * @version 1.00 2009/4/25 */ import java.awt.*; import java.awt.event.*; import javax.swing.*; public class MineFrame extends JFrame implements ActionListener{ JButton reStart; Block block[][]; BlockView blockView[][]; LayMines lay; int row=10,colum=12,mineCount=22; int colorSwitch = 0; JPanel pCenter,pNorth; public MineFrame() { reStart = new JButton("重新开始"); //做一个restart按钮 pCenter = new JPanel(); //中心主游戏区面板 pNorth = new JPanel(); //上部控制面板 pNorth.setBackground(Color.gray); block = new Block[row][colum]; for(int i=0;i<row;i++){ //实例化一个Block数组 for(int j=0;j<colum;j++){ block[i][j]=new Block(); } } lay = new LayMines(); lay.layMinesForBlock(block,mineCount); blockView = new BlockView[row][colum]; pCenter.setLayout(new GridLayout(row,colum)); for(int i=0;i<row;i++){ for(int j=0;j<colum;j++){ blockView[i][j] = new BlockView(); //实例化一个blockView数组 blockView[i][j].setName(block[i][j].getName()); pCenter.add(blockView[i][j]); blockView[i][j].getBlockCover().addActionListener(this); //给每一小格添加监听器 } } reStart.addActionListener(this); //给reStart添加监听器 pNorth.add(reStart); //将组件添加到窗口中 add(pNorth,BorderLayout.NORTH); add(pCenter,BorderLayout.CENTER); setSize(200,232); setVisible(true); //pack(); addWindowListener(new WindowAdapter(){ //添加窗口关闭事件的监听 public void windowClosing(WindowEvent e){ System.exit(0); } }); validate(); } public void actionPerformed(ActionEvent e){ JButton source = (JButton)e.getSource(); if(source!=reStart){ int m = -1,n=-1; for(int i=0;i<row;i++){ for(int j=0;j<colum;j++){ //判断事件对象,如果是格子[i][j],则翻开,并将该对象存储到[m][n] if(source==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++){ //如果[m][n]是雷,则游戏停止,移除所有格子的事件监听,按钮动作失效 //同时翻开所有是雷的按钮 blockView[i][j].getBlockCover().removeActionListener(this); if(block[i][j].isMine()) blockView[i][j].seeBlockName(); } } }else{ if(block[m][n].getNumber()>0) blockView[m][n].seeBlockName(); else{ //如果所采处雷数为0,则翻开周边 if(block[m][n].getNumber()==0){ 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++){ blockView[k][t].seeBlockName(); } } } } } } if(source==reStart){ for(int i=0;i<row;i++){ for(int j=0;j<colum;j++){ block[i][j].setIsMine(false); } } lay.layMinesForBlock(block,mineCount); for(int i=0;i<row;i++){ for(int j=0;j<colum;j++){ blockView[i][j].setName(block[i][j].getName()); blockView[i][j].seeBlockCover(); blockView[i][j].getBlockCover().addActionListener(this); } } } } public static void main(String args[]){ new MineFrame(); } } /** * @(#)BlockView.java * * 该类是为Block类创建视图,注意,要实现扫雷效果,则需要将试图分为两层,表层是按钮,底层是标签, * 所以要用到CardLayout布局。另外,想在一个个格子里面放多各元件,得考虑用Panel容器,所以该视图类 * 继承自Panel * * @author 宋俊林 * @version 1.00 2009/4/25 */ import java.awt.*; import javax.swing.*; public class BlockView extends JPanel { JLabel blockName; JButton blockCover; CardLayout card; BlockView(){ //在构造器中初始化各属性 card = new CardLayout(); setLayout(card); blockName = new JLabel(); blockCover = new JButton(); add("cover",blockCover); //将blockCover添加到层面板 add("name",blockName); //将blockname添加到层面板 } public void setName(String name){ //设置blockName的text blockName.setText(name); } public String getName(){ //得到blockName的text return blockName.getText(); } public void seeBlockName(){ //显示blockName card.show(this,"name"); validate(); } public void seeBlockCover(){ //显示blockCover card.show(this,"cover"); validate(); } public JButton getBlockCover(){ //得到blockCover return blockCover; } } /** * @(#)LayMines.java * * * 我感觉这个类时扫雷的算法核心,只要搞定这个类,其他都不是问题,该类只有一个主方法 * *---> void layMinesForBlock(Block block[][],int mineCount) * * 其中: * * 1.参数block[][]数组存放着整个游戏区的方格的block对象,一个方格对应一个 * * 同时,用二维数组也为实现扫描周边的九回宫格统计雷数提供支持 * * 2.参数mineCount来存放你想生成的类的个数 * * 3.这里还用到了集合LinkedList,来存储block[][]中的所有block对象, * * * @author 宋俊林 * @version 1.00 2009/4/25 */ import java.util.LinkedList; public class LayMines { public void layMinesForBlock(Block block[][],int mineCount){ int row = block.length; int column = block[0].length; LinkedList<Block> list = new LinkedList<Block>(); //创建list(用到范型) for(int i=0;i<row;i++){ for(int j=0;j<column;j++){ list.add(block[i][j]); //利用循环,将block都加到列表list里 } } while(mineCount>0){ int size = list.size(); int randomIndex=(int)(Math.random()*size); //生产随机数,将这些随机数对应的block对象的属性设为是雷的属性 Block b = list.get(randomIndex); //根据随机数,取对应的block对象 b.setName("雷"); //将name设为‘雷’ b.setIsMine(true); //将雷性设为true list.remove(randomIndex); //将list中是雷的节点删除,以免设置雷重复 mineCount--; } for(int i=0;i<row;i++){ for(int j=0;j<column;j++){ if(!block[i][j].isMine()){ //如果block[i][j]不是雷是执行下面的统计操作,扫描周边 int mineNumber = 0; /** * 我感觉下面是核心的核心,扫描周围的八个(但是在游戏区的边界上,可能不足八个格子),所以这里扫描是就得处理边界问题 *这里为防止越界,用的是比较大小取值的方法,很精妙“Math.max(j-1,0)”;下面是扫描图: * [———————————————————————————] * [(i-1,j-1)|(i-1,j)|(i-1,j+1)] * [———————————————————————————] * [ (i,j-1) | (i,j) | (i,j+1)] * [———————————————————————————] * [(i+1,j-1)|(i+i,j)|(i+1,j+1)] * [———————————————————————————] */ 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].setName(""+mineNumber); //将name存为number后边会进行显示 block[i][j].setNumber(mineNumber); //将周边的雷数存入number中 } } } } }