【面向对象课程项目:纸牌】Java实例学习(三):对自己代码的修正与加壳(仍然要对比源码)

前言:通过前面两篇日志:

【面向对象课程项目:纸牌】Java实例学习(一):优秀源码的分析

【面向对象课程项目:纸牌】Java实例学习(二):优秀源码与自己模型的对比


我们了解到了自己的项目中存在的问题,也了解到了在整个架构上的缺陷.既然架构上的缺陷,也可以提出新的方案进行修改.套用某个大牛的一句话"简单的东西总是比复杂的东西更高效,也更优美"(忘了是谁说的了=  =||).问题在于,投入的沉没成本,没有办法把他完全抛却,而且如果完全重写代码,会导致自己的自信心进一步受挫(等于枪毙了自己的编程思路,这是正在成长过程中的我最为忌讳的...).所以我决定在原有的命令行模式上加壳.另外,如果按照自己的思路写完后,才能体会到为什么自己的效率底下,而学姐的代码优秀,这个对比必须由一个完全由自己编写的代码来 提供样板.  但是以后如果真的要自己写东西,一定要在脑子里面打好草稿,才能够慢慢成长.对比下这两篇文章(1.编程能力的四种境界 ;2.程序员的四大境界)中描述的状态自己还处在 第一个阶段.无意识无知.要成长,还有相当长的路要走,相当多的文档要看.

一.对原来的模型中几个必要的修正

  1. 先看看这个在第二篇文章中提到的漏洞,关于移动牌堆的逻辑方法,应该放在包含各个 数据结构 的GameModel类中! 根据数据和相应的特质方法封装成一个类的原则,在命令行的代码中,应该只出现调用,而不应该出现凌乱的,让人摸不着头脑的switch语句.这个是非常不合时宜的.破坏了封装性的Command类完成了苦逼的 获取命令和 对应参数的的工作,还要去实现移动牌堆的任务.这个错误的思路,直接影响了我第一次加壳的尝试:我竟然愚蠢的认为,在 GUI版本的纸牌中,command类应该得以保留,而每一次点击形成一个命令,交给command流来进行处理! 相当愚蠢的饶了一大圈...这完全都是因为当时开发的时候,模块划分不够明确和 谨慎.如果不是因为写这篇日志,重新开始审视  设计模式,我不会发现这个一步错步步错的 结果.   看看修改后的GameModel代码:
    package com.Cards.model;
    
    /**
     * @author Rock Lee
     * @version 2012-10-21 17:33:31
     * @proposal to establish a game model for the game,leaving all the possible
     *           interfaces to control the game
     * 
     * */
    public class GameModel
    {
    
    	public final static int LISTS_NUM = 7;
    	public final static int STACKS_NUM = 4;
    
    	public CardHeap heap = null;
    	public CardList lists[] = null;
    	public CardStack stacks[] = null;
    	public CardDeck deck = null;
    
    	public GameModel()
    	{
    		this.initialize();
    	}
    
    	private void initialize()
    	{
    		heap = new CardHeap();
    		lists = new CardList[LISTS_NUM];
    		stacks = new CardStack[STACKS_NUM];
    
    	}
    
    	public void newGame()
    	{
    		heap.initialize();// get a new set of cards
    		heap.shuffle();
    		for (int i = 0; i < lists.length; i++)
    		{// 7 times to get 7 Card Lists
    
    			lists[i] = new CardList();
    			for (int j = 0; j < i + 1; j++)
    			{// i+1 times to give out the enough Cards to build list[i]
    				Card tmp = heap.giveOutOneCard();
    				lists[i].addOneCard(tmp);
    			}
    			lists[i].turnLastCard();// turn the end card in the list
    		}
    		for (int i = 0; i < stacks.length; i++)
    		{// 4 times to get 4 stacks
    			stacks[i] = new CardStack(CardSetting.COLOR[i]);
    		}
    		// only one deck to set up
    		// All the cards left in the heap sent to deck
    		deck = new CardDeck();
    		while (!heap.isEmpty())
    		{
    			Card tmp = heap.giveOutOneCard();
    			tmp.setVisiable(true);
    			deck.addOneCard(tmp);
    		}
    		this.print();
    	}
    
    	public void print()
    	{
    		System.out
    				.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
    		System.out.println("The Status of Deck is :\n\t"
    				+ deck.getCurrentGroup());
    
    		System.out.println("The Status of 7 lists are:");
    		for (int i = 0; i < lists.length; i++)
    		{
    			System.out.println("\t" + lists[i] + "\n");
    		}
    
    		System.out.println("The Status of 4 stacks are:");
    		for (int i = 0; i < stacks.length; i++)
    		{
    			System.out.println("\t" + stacks[i]);
    		}
    		System.out
    				.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
    	}
    
    	/*
    	 * 参见command中的ltl
    	 * 
    	 * from: 0~6 to :0~6
    	 */
    	public void listToList(int from, int to)
    	{
    		lists[from].moveTo(lists[to]);
    		this.print();
    	}
    
    	/*
    	 * 参见commmand中的rpd
    	 * 
    	 * to :0~3
    	 */
    	public void deckToStack(int to)
    	{
    		Card tmp = deck.peekOneCard();
    		if (stacks[to].allowToPush(tmp))
    		{
    			stacks[to].push(deck.getOneCard());
    		}
    		this.print();
    	}
    
    	/*
    	 * 参见 command中的rpl
    	 * 
    	 * form: 0~6 to : 0~3
    	 */
    	public void listToStack(int from, int to)
    	{
    		Card tmp = lists[from].peekOneCard();
    		if (stacks[to].allowToPush(tmp))
    		{
    			stacks[to].push(lists[from].getOneCard());
    		}
    		this.print();
    	}
    
    	/*
    	 * 参见 command中的dtl
    	 * 
    	 * to: 0~6
    	 */
    	public void deckToList(int to)
    	{
    		Card tmp = deck.peekOneCard();
    
    		if (lists[to].allowToAdd(tmp))
    		{
    			lists[to].addOneCard(deck.getOneCard());
    		}
    		this.print();
    
    	}
    
    	/*
    	 * 显示下一组
    	 * */
    	public void nextDeckToShow()
    	{
    		deck.getNextGroup();
    		print();
    	}
    
    }
    
    这样看起来自然多了.以后像LIST_SIZE,这样的变量,能来看源码的人一看就懂.这样鸡肋的常量,以后在修正的时候,必要的时候再予以添加...

二.加壳代码的具体思路

  1. 修正完上面的部分以后,我们接下来看看整个加壳的思路.
    先看看布局图:!fuckinglayout!
    1. 时刻提醒自己注意,View部分只是用于回显 对model的修改
    2. 被点击后,调用各个被封装在GameModel中的方法,这里有两个选择,各个ViewCard进行监听  或者是使用 ViewGame中单独挂载一个监听类进行事件的监听. 最终向model传递改变指令
  2. 问题:  首先,我们考虑Card,也就是上图中的□ 应该以什么方式显示?   其次,如何 记录点击?
    1. 对于问题一,每一个□,都应该对应一个实例.我们应该写一个通用的父类,子类实现其重绘的方法.这个是思路的一种,要求把每一个ViewCard的图片标签,都直接贴到ViewGame的面板上;另外一种实现思路便是使用 和第二篇文章的代码一样,每一个对象都是JLayerdPane的一个实例的子对象.这样便可以工作.这两个思路直接影响了整个架构,但是思路有一点是一致的:将每一张牌 对应绘制到 相应的 位置上..
    2. 对于问题而,以前写 黑白棋的时候,似乎用的都是getSources来获得一个触发事件的对象 的指针.但这里点击的没有处理方法的JLabel,似乎有些不合适,而每个牌堆的牌太多,这个处理机制我觉得不够合适,于是乎放弃....另一种方案,在每一个pile都挂载上一个监听器,在模型□被点击时,像父类中添加记录,并处理下一步的工作...(这个方法要在ViewModel中实现内部匿名类)
    3. 但是有没有什么更适合我这个 渣渣的办法呢?既然我采取的思路,是直接向 整个大ViewGame这个panel中添加label组件,那么就应该 把对应的监听器放在整个panel上. 我的考虑参照了当时开发黑白棋的一种 使用JLable作为棋盘格的 思路:也即使用绝对坐标来实现.但这样一来,几乎无法 以panel的某一打牌来进行操作,拖拽的功能就必须放弃考虑了.  如此同时,也不必在意 □的实现了.
  3. 接下来,在每个ViewPile的子类中,给出在整个Panel绝对布局 中某个组件的坐标,用对应的drawXXX(x,y)类似的方法内,绘制到ViewGame中.当游戏需要刷新的时候,我们只需要对drawXXX进行重新调用即可.
  4. 具体实现中的几个问题,首先,ViewGame用什么Cotainer来盛放?其次 倘若model修改成功之后.重新drawXXX之时,原来的图片如何处理? Java中有没有对某个rectangle为脏区的处理方案? 或者简单的刷一刷背景,覆盖即可?写的时候,这些都是值得考虑的问题.

三.具体源码与详解

  1. 上一下ViewCard的源码,我门要记住的,ViewCard只是一个封装好了Card模型的JLabel,用来设置相应的图片而已.
    package com.Cards.view;
    
    import javax.swing.ImageIcon;
    import javax.swing.JLabel;
    
    import com.Cards.model.Card;
    import com.Cards.model.GameModel;
    
    /**
     * @author Rock Lee
     * @version 2012-11-28 8:53:09
     * @see com.Cards.model.Card.java
     * @aim A modified version to support the View of the Game Basic Part of the
     *      Cards.
     * @note This class should be considered as a JLabel!!! with some special fields
     *       for Card...
     * 
     * */
    public class ViewCard extends JLabel
    {
    
    	private static final long serialVersionUID = 1L;
    	private Card model_card = null;
    	private ImageIcon cardFace = null;
    
    	public ViewCard(Card card)
    	{
    		this.setOpaque(false);
    		// TODO build a viewCard,using JLabel
    
    		this.model_card = card;
    		this.prepareCardFace();
    	}
    
    	/*
    	 * 如果说,整个model_card给的参数一开始就是null,那么就给他一个空框的图片
    	 * 
    	 * 可见,不可见分开考虑
    	 */
    	private void prepareCardFace()
    	{
    
    		if (this.model_card == null)
    		{// there is no card in this place right now
    			this.cardFace = ViewSetting.EMPTY_IMAGE;
    		}
    
    		else if (!this.model_card.isVisible())
    		{// get the cardFace ImageIcon for the JLabel<not Visible>
    			this.cardFace = ViewSetting.BACK_IMAGE;
    		} else
    		{
    			// System.out.println(this.model_card);
    
    			this.cardFace = ViewSetting.getImageIconForCard(this.model_card);
    		}
    		this.setIcon(cardFace);
    	}
    
    	public Card getModelCard()
    	{
    		return this.model_card;
    	}
    
    }
    

  2. 作为ViewCard初始化的支持类:ViewSetting
    package com.Cards.view;
    
    import javax.swing.ImageIcon;
    
    import com.Cards.model.Card;
    
    public class ViewSetting
    {
    	public final static ImageIcon BACK_IMAGE = new ImageIcon(
    			ViewSetting.class.getResource("/image/back.png"));
    	public final static ImageIcon EMPTY_IMAGE = new ImageIcon(
    			ViewSetting.class.getResource("/image/empty.png"));
    
    	public static ImageIcon getImageIconForCard(Card model_card)
    	{
    		ImageIcon cardFace = null;
    		if (model_card.getColor().equals("♥"))
    		{
    			cardFace = new ImageIcon(ViewSetting.class.getResource("/image/"
    					+ "h" + model_card.getNum() + ".png"));
    		} else if (model_card.getColor().equals("♠"))
    		{
    			cardFace = new ImageIcon(ViewSetting.class.getResource("/image/"
    					+ "s" + model_card.getNum() + ".png"));
    
    		} else if (model_card.getColor().equals("♦"))
    		{
    			cardFace = new ImageIcon(ViewSetting.class.getResource("/image/"
    					+ "d" + model_card.getNum() + ".png"));
    
    		} else if (model_card.getColor().equals("♣"))
    		{
    			cardFace = new ImageIcon(ViewSetting.class.getResource("/image/"
    					+ "c" + model_card.getNum() + ".png"));
    		}
    		//System.out.println(cardFace);
    		return cardFace;
    	}
    
    	public final static int COMPONET_DISTANCE = 20;
    
    	public final static int CARD_WIDTH = 100;
    	public final static int CARD_HEIGHT = 150;
    }
    


  3. ViewPile.java 这是一个抽象类,他的工作就是将对应的model 数组形成相应的ViewCard 数组,等待下一步的绘制.实际上这两步的工作可以放到同一个方法调用中,但是由于我放到了两个方法中,我不得不去再维护一个ArrayList<ViewCard> viewCardList的属性,每次都要删除内容,重新装载,删除内容,重新装载..效率实在是不怎么高.如果把这个作为一个零时变量,就不用在下面的fillList代码中,每次都要clear()一下咯.
    package com.Cards.view;
    
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Iterator;
    
    import javax.swing.JLayeredPane;
    import javax.swing.JPanel;
    import javax.swing.text.LayeredHighlighter;
    
    import com.Cards.model.Card;
    
    public abstract class ViewPile 
    {
    	ArrayList<ViewCard> viewCardList=null;
    	Collection<Card> pileModel=null;
    
    	JPanel mainnGameContainer=null;
    	
    	
    	public ViewPile(Collection<Card> pileModel,JPanel container)
    	{
    		this.mainnGameContainer=container;
    		
    		viewCardList=new ArrayList<ViewCard>();
    		this.pileModel=pileModel;
    		this.fillList();
    		
    	}
    
    	/*
    	 * 将model中的一张张牌 初始化 作 ViewCard的数组
    	 * 并放入viewCardList,为下一步的准备
    	 * */
    	public void fillList()
    	{
    		//清理原有的内容,避免上一轮绘制的模型list被重复添加
    		viewCardList.clear();
    		
    		
    		Iterator<Card> iter=pileModel.iterator();
    		while(iter.hasNext())
    		{
    			ViewCard tmp=new ViewCard(iter.next());
    			viewCardList.add(tmp);
    		}
    	}
    	
    	abstract public void paintPile(int x,int y);
    }
    
    另外解释一下构造方法中的JPanel.这个就是用于添加各个ViewCard的 容器,在ViewGame中初始化一个ViewPile对象的时候,这个实参就是 this
  4. 看看ViewPileDeck类,其他的ViewPileList和ViewPileStack都是大同小异.
    package com.Cards.view;
    
    import java.util.Collection;
    
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    
    import com.Cards.model.Card;
    
    public class ViewPileDeck extends ViewPile
    {
    
    	public JLabel control = null;
    
    	public ViewPileDeck(Collection<Card> pileModel, JPanel container)
    	{
    		super(pileModel, container);
    	}
    
    	/* 展示model deck中要显示的那三张牌 */
    	@Override
    	public void paintPile(int x, int y)
    	{
    		super.fillList();
    		x += 10;
    		y += 10;
    
    		control = new JLabel(ViewSetting.BACK_IMAGE);
    		control.setBounds(x, y, 100, 150);// 用于点击的那个label
    
    		// 这真是神奇!setLocation 不管用,而setBounds则可以!?
    
    		super.mainnGameContainer.add(control);
    
    		x += 170;
    		for (int i = 0; i < viewCardList.size(); i++)
    		{
    			viewCardList.get(i).setBounds(x + 20 * i, y, 100, 150);
    
    			// 这一句掉了!不要理所当然的认为有 画笔去绘制这个组件!没有,因为我们通过的是add Label的,没有重画
    			super.mainnGameContainer.add(viewCardList.get(i), 0); // setLocation
    																	// 是将位置设置为相对于父组件的位置
    			// 但是,必须要添加到一个父组件(Container)中,才能得到显示
    
    		}
    
    	}
    
    }
    
    这里有几个地方要解释一下,control指的是哪个可以不断点击,以获得下一组三张牌的 JLabel. 之所以要每一次paint都要刷新一遍list,(filllist下),是因为上面的原因..这个的确是个败笔,代码可以进一步精简,这里就不给出了=  =.
  5. 当时一开始使用setLocation方法老是不出现图片...一直弄不明白为什么.网上查阅资料以后,知道了setLocation 实质是调用setBounds的.但是为啥setBounds能够将图片正确显示,而setLocation不能呢?我查阅类库源码仍然不解,后来单步调试,看绘制过程,找到的原因: 在没有设置ViewCard的JLabel的高宽的时候,setLocation调用 setBounds使用的是setBounds(x,y,0,0)..如果细心,就会发现学姐的代码中有这么一部分:
    	public CardW(Card c)
    	{
    		super();
    		this.card=c;
    		setFaceUp(card.isFaceUp());
    		setBounds(0,0,MainWindow.POKERWIDTH, MainWindow.POKERHEIGHT);
    	}
    	
    病根就在这.不自己写写,永远不知道setLocation必须先自己设计好组件的大小囧
  6. package com.Cards.view;
    
    import java.util.Collection;
    
    import javax.swing.JLabel;
    import javax.swing.JLayeredPane;
    import javax.swing.JPanel;
    
    import com.Cards.model.Card;
    
    public class ViewPileList extends ViewPile
    {
    	//没有将组件添加进来?! 必须要显式的调用add
    	public ViewPileList(Collection<Card> pileModel,JPanel container)
    	{
    		super(pileModel,container);
    	}
    
    	@Override
    	public void paintPile(int x, int y)
    	{
    		super.fillList();
    		
    		x+=10;y+=10;
    		for (int i = 0; i < viewCardList.size(); i++)
    		{
    			
    			viewCardList.get(i).setBounds(x,y+30*i,100,150);
    			//viewCardList.get(i).setLocation(x,y+30*i);
    			
    			super.mainnGameContainer.add(viewCardList.get(i),0);
    		}
    	}
    
    }
    
    这是ViewPileList,注意一下这里的super.mainGameContainer.add().参数中给了一个0...因为当时如果直接使用普通的add调用.我们会悲剧的发现:后面添加的组件反而被前面的组件盖住,放到了底下.查阅APIc,发现了这么一段既然默认是-1,添加到尾部,我给一个0吧.这样就解决了后面的组件被前面的覆盖了问题.(实际上这个地方还有一个处理方法,就是用JLayeredPane,像学姐一样,对每一个组件添加的时候,添加到不同的层即可  setLayer(cw,i))
  7. ViewPileStack,没什么好说的
    package com.Cards.view;
    
    import java.util.Collection;
    
    import javax.swing.JLayeredPane;
    import javax.swing.JPanel;
    
    import com.Cards.model.Card;
    
    public class ViewPileStack extends ViewPile
    {
    	public ViewPileStack(Collection<Card> pileModel,JPanel container)
    	{
    		super(pileModel,container);
    	}
    
    	@Override
    	/*给定起始坐标,将目标CardView绘制出来*/
    	public void paintPile(int x, int y)
    	{
    		super.fillList();
    		x+=10;y+=10;
    		
    		//显示已经收割的牌堆中,最上面一张牌
    		ViewCard tmp=viewCardList.isEmpty()?new ViewCard(null):viewCardList.get(viewCardList.size()-1);
    		tmp.setBounds(x, y,100,150);
    		
    		super.mainnGameContainer.add(tmp);
    	}
    }
    

  8. 接下来看看让整个协同工作的类,我没有做任何美化工作,已经懒得进一步去写了=.  =
    package com.Cards.view;
    
    import java.awt.Graphics;
    import java.awt.Image;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    
    import com.Cards.model.*;
    
    import javax.swing.JLabel;
    import javax.swing.JLayeredPane;
    import javax.swing.JPanel;
    import javax.swing.text.View;
    
    public class ViewGame extends JPanel
    
    {
    	private ViewPileDeck viewDeck = null;
    	private ViewPileStack[] viewStacks = null;
    	private ViewPileList[] viewLists = null;
    
    	boolean isClicked = false;
    	int fromPosition = 0, toPosition = 0;
    
    	final int STACK_INDEX_BASE = 1;
    	final int LIST_INDEX_BASE = 5;
    
    	private GameModel gameModel = null;
    
    	public ViewGame(GameModel gameModel)
    	{
    		this.setLayout(null);// 设置为绝对布局
    
    		this.gameModel = gameModel;
    
    		// 初始化几个部件
    		viewDeck = new ViewPileDeck(gameModel.deck.getStackShown(), this);
    
    		// stacks
    		viewStacks = new ViewPileStack[4];
    		for (int i = 0; i < viewStacks.length; i++)
    		{
    			viewStacks[i] = new ViewPileStack(gameModel.stacks[i].getStack(),
    					this);
    		}
    
    		// lists
    		viewLists = new ViewPileList[7];
    		for (int i = 0; i < viewLists.length; i++)
    		{
    			viewLists[i] = new ViewPileList(gameModel.lists[i].getLinkedList(),
    					this);
    		}
    
    		this.repaint();
    
    		this.addMouseListener(new MyMouseAdapter());
    	}
    
    	@Override
    	public void paint(Graphics g)
    	{
    		
    		this.removeAll();
    		this.setOpaque(false);
    		int x = 0, y = 0;
    
    		viewDeck.paintPile(x, y);
    
    		x = 3 * (ViewSetting.COMPONET_DISTANCE + ViewSetting.CARD_WIDTH);
    		for (int i = 0; i < viewStacks.length; i++)
    		{
    			viewStacks[i].paintPile(x + i
    					* (ViewSetting.COMPONET_DISTANCE + ViewSetting.CARD_WIDTH),
    					y);
    		}
    
    		x = 0;
    		y = ViewSetting.CARD_HEIGHT + 30;
    
    		for (int i = 0; i < viewLists.length; i++)
    		{
    			viewLists[i].paintPile(x + i
    					* (ViewSetting.COMPONET_DISTANCE + ViewSetting.CARD_WIDTH),
    					y);
    		}
    		super.paint(g);
    	}
    
    	class MyMouseAdapter extends MouseAdapter
    	{
    		@Override
    		public void mouseClicked(MouseEvent e)
    		{
    			int x = e.getX() - 10, y = e.getY() - 10;
    			if (-1==getComponentPosition(x, y))
    			{
    				gameModel.nextDeckToShow();
    			}
    			if (isClicked)// 如果前面一次已经点击
    			{
    				isClicked = false;
    
    				// 获得此次点击的组件标号
    				ViewGame.this.toPosition = getComponentPosition(x, y);
    
    				if (toPosition >= 1 && toPosition <= 4)
    				{// 表示要收割
    					if (fromPosition == 0)
    					{// rpd
    						gameModel.deckToStack(toPosition - STACK_INDEX_BASE);
    					}
    
    					else if (fromPosition >= 5 && fromPosition <= 11)
    					{// rpl
    						gameModel.listToStack(fromPosition - LIST_INDEX_BASE,
    								toPosition - STACK_INDEX_BASE);
    					}
    				} 
    				else if (toPosition >= 5 && toPosition <= 11)
    				{// 向某个 list移动
    					if (fromPosition == 0)
    					{// dtl
    						gameModel.deckToList(toPosition - LIST_INDEX_BASE);
    					} else if (fromPosition >= 5 && toPosition <= 11
    							&& fromPosition != toPosition)
    					{// ltl
    						gameModel.listToList(fromPosition - LIST_INDEX_BASE,
    								toPosition - LIST_INDEX_BASE);
    					}
    
    				}
    
    			}
    
    			else
    			{// 尚未有有效点击被记录,则记录下本次点击
    
    				isClicked = true;
    				ViewGame.this.fromPosition = this.getComponentPosition(x, y);
    			}
    
    			ViewGame.this.repaint();
    
    		}
    
    		/*
    		 * 注意这里的 index -1 代表 controlLabel 0 代表 deck 1~4 代表 stacks 5~11 代表 lists
    		 */
    		public int getComponentPosition(int x, int y)
    		{
    			int result = 0;
    			if (y <= ViewSetting.CARD_HEIGHT)
    			{// deck 或 stack的点击
    				result = x
    						/ (ViewSetting.COMPONET_DISTANCE + ViewSetting.CARD_WIDTH);
    				switch (result)
    				{
    				case 0:
    					return -1;
    				case 1:
    				case 2:
    					return 0;
    
    				case 3:
    				default:
    					return ((result-3) + STACK_INDEX_BASE);	//注意此处,result-3 为实际在stacks中的下标
    				}
    			}
    
    			else
    			{// 点击的是list部分
    				result = x
    						/ (ViewSetting.COMPONET_DISTANCE + ViewSetting.CARD_WIDTH);
    				return (result + LIST_INDEX_BASE);
    
    			}
    
    		}
    
    	}
    }
    

    由于每一次返回的时候,我们都要找到对应的 组件标号(即Layout那一幅图中的哪个部分,上面的STACK_INDEX_BASE就是为了区别到底是 识别哪一组的一个小trick,因为0~3和0~6有重叠的地方,处理加上一个常量值,再在 对应调用处理方法的时候把这个常量剪掉就行了)
  9. MainWindow.java 没有用involkedLater的队列,我觉得这个实在是没有必要...但是掌握还是需要的喂喂!!囧
    package com.Cards.view;
    
    import javax.swing.JFrame;
    import com.Cards.model.GameModel;
    
    public class MainWindow extends JFrame
    {
    
    	ViewGame viewPanel=null;
    	GameModel myModel=null;
    	
    	public MainWindow(String title)
    	{
    		super(title);
    		myModel=new GameModel();
    		myModel.newGame();
    		viewPanel=new ViewGame(myModel);
    		
    		this.add(viewPanel);
    		
    		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    		
    	}
    
    	public static void main(String[] args)
    	{
    		MainWindow myTest=new MainWindow("fucking paper!");
    		myTest.setSize(900,600);
    		myTest.setVisible(true);
    		
    	}
    
    }
    

    看看效果图吧..阿西莫多的fuckingpaper!!!
  10. 最后还是忍不住吐槽了一下囧....说脏话了,各位看官对不起啦!
    这里是 自己的源码,其中Card2.0为 命令行版,其中有半成品的图形界面(不能工作),不要理会他就是了;Card3.0为已经添加了图形界面的源码版本,地址戳我.



  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值