显示多个图像而不创建新变量

时间:2013-11-28 02:23:35

标签: java swing jframe

我正在用java创建一个程序来模拟一副基本卡片;没有特定的游戏,只是一个很好的老牌卡,你可以自由移动和翻转(当然,限制总共52张卡)。这是我目前的代码:

package cards;
import java.awt.Color;
import java.awt.Graphics;
import java.util.List;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
public class DeckOfCards extends JPanel{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    static final int SIZE = 500;
    public static String side = "back";
    static final int xSize = 73;
    static final int ySize = 98;
    static int x = SIZE - xSize;
    static int y = 0;
    static int i, j = 0;
    static int inDeck = 52;
    public boolean flipped = false;
    static final DeckOfCards m = new DeckOfCards();
    static final Color rgb = new Color(0, 180, 10);
    static final JFrame frame = new JFrame();
    static List<Integer> yList = new ArrayList<Integer>();
    static List<Integer> xList = new ArrayList<Integer>();
    Random random = new Random();
    int randX = random.nextInt(13) * xSize; 
    int randY = random.nextInt(4) * ySize;
    int xRand = randX;
    int yRand = randY;
    public static void main(String[] args){
        frame.setTitle("Virtual Cards");
        frame.add(m);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(SIZE, SIZE);
        frame.setResizable(false);
        m.setBackground(rgb);
        frame.setVisible(true);
    }
    public void mouseClick(){
        addMouseListener(new MouseAdapter(){
            @Override
            public void mouseClicked(MouseEvent e){
                if(((e.getX() >= x && e.getX() <= (x + xSize)) && (e.getY() >= y && e.getY() <= (y + ySize))) && (flipped == false)){
                    flipped = true;
                    side = "front";
                }else if(((e.getX() >= x && e.getX() <= (x + xSize)) && (e.getY() >= y && e.getY() <= (y + ySize))) && (flipped == true)){
                    flipped = false;
                    side = "back";
                }else if((e.getX() >= SIZE - xSize && e.getX() <= SIZE) && (e.getY() >= 0 && e.getY() <= SIZE - (SIZE - ySize)) && inDeck > 0){
                    randCardFace(random);
                    inDeck--;
                    side = "back";
                    x = SIZE - xSize;
                    y = 0;
                }
            }

        });
    }
    public void mouseMove(){
        addMouseMotionListener(new MouseMotionAdapter(){
            @Override
            public void mouseDragged(MouseEvent e){
                if(((e.getX() >= x && e.getX() <= (x + xSize)) && (e.getY() >= y && e.getY() <= (y + ySize)))){
                    x = e.getX() - (xSize / 2);
                    y = e.getY() - (ySize / 2); 
                }
            }
        });
    }
    public DeckOfCards(){
        mouseClick();
        mouseMove();
    }
    public void randCardFace(Random random){
            randX = random.nextInt(13) * xSize;
            randY = random.nextInt(4) * ySize;
    }
    @Override
    protected void paintComponent(Graphics g){
        super.paintComponent(g);
        paint(g);
    }
    public void paint(Graphics g){
        try{
            if(inDeck > 0){
                g.drawImage(ImageIO.read(getClass().getResource("images/deck.png")), SIZE - xSize, 0, null, null);
            }
            BufferedImage image = ImageIO.read(getClass().getResource("images/"+side+".png"));
            if(side != "back"){
                image = image.getSubimage(randX, randY, xSize, ySize);
            }
            g.drawImage(image, x, y, xSize, ySize, null, null);
        }catch(IOException e){
            e.printStackTrace();
        }
        m.repaint();
    }
}

然而,这个程序只允许我一次输出一张卡,直到我点击右上角的牌组并重新洗牌(用随机数发生器重新定义要读取的图像区域)。我想做的是能够在任何给定时间通过点击牌组获得0和52的任意数量的牌而不为其他牌创建51个新变量(我已经写了一些代码用于我的内容)我希望,但到目前为止,除了导致问题之外什么也没做,所以我决定从头开始并向专家询问我应该做些什么。

编辑:

在问到这个之后才意识到,这是一个比我想要发布的稍微旧的代码,并且可能还有很多其他问题。请忽略它们,因为它们已经修复。

2 个答案:

答案 0 :(得分:3)

你发布了很多问题的代码,请允许我给你一些建议。如果它不是正确的代码,请更正:

  • 您应该覆盖JPanel的paintComponent方法而不是其paint方法,除非您需要更改组件的子项和边框绘制方式的行为(您没有)。
  • 你永远不应该在paint或paintComponent中读取图像,因为这会降低渲染速度,从而编写对爬行的响应。
  • 您绝不应该在paint或paintComponent中调用repaint()
  • 您正在从paintComponent中调用paint,这会因为paint调用paintComponent而导致可怕的递归。永远不要这样做。
  • 您的代码使用静态。这将阻止它可扩展,并将限制其可修改性。
  • 您在构建GUI时没有先创建一个像样的模型。卡程序已经很好地描述了常见的模型这些包括Java版本的使用枚举,其中包含针对Suit的枚举和针对Rank的枚举。在开始使用卡片,甲板,播放器,游戏之前先获取抽象概念和类,然后再进行图像处理。

链接到有关纸牌游戏的其他一些答案和代码:

答案 1 :(得分:2)

有两种基本方法,两种方法都遵循相同的基本概念......

生成图像列表并绘制它们......

你可以......

创建一个自定义组件,专门负责绘制单张卡片。这样做的好处是,它通常易于管理和使用已有的功能。

缺点是,您需要负责布局管理(稍微)。

您可以从LayredPane开始,这样您就可以上下推动卡片(虚拟地),并允许它们放置在您想要的位置。

就个人而言,我会创建一个MouseListener / MouseMotionListener并将其注册到每个“卡片面板”,这样可以轻松控制与LayeredPane相关的卡片。 (例如,当点击它们时将它们移动到顶部)

你可以......

另一种选择是加载每张卡片图像并将它们放入List。然后基本上,你只需在paintComponent方法中通过简单地遍历列表来绘制它们。

问题是,您突然负责z顺序的整个管理并检查点击的内容。

自定义图像的绘制(例如添加边框)变得有点麻烦,因为您需要为每个图像执行此操作并确定何时。如果它们是自定义组件,这将更容易

反馈

  • 谨防过度使用static变量,这可能很快导致您进入问题区域并试图确定实际被引用的内容
  • 请勿从paint致电paintComponentpaint实际上调用了paintComponent本身,这可能会产生堆栈溢出错误
  • 不要在可能调用paintXxx的{​​{1}}方法中调用任何方法,因为绘画的工作方式,这只会让EDT简单地继续绘制您的组件,这最终会消耗你的CPU ......

详细了解Performing Custom PaintingPainting in AWT and Swing了解详情