在循环中添加 JLayeredPane 后,将显示 JLabel 上的最后一张图像

Last image on JLabel is shown for all after adding JLayeredPane in loop

抱歉标题不好,想不出更好的了。

我正在制作纸牌游戏。

下面的方法将 Card object 作为参数,returns 我将 JLayeredPane 与 JLabel 一起使用,该 JLabel 具有卡片图像。

private JLayeredPane getCardPane(Card card) {
    JLayeredPane cardPane = new JLayeredPane();

    GridBagLayout gblCardPane = new GridBagLayout();
    cardPane.setLayout(gblCardPane);

    cardImageIcon = card.getImageIcon();

    JLabel lblCard = new JLabel() {
        @Override
        public void paintComponent(Graphics g) {
            g.drawImage(cardImageIcon.getImage(), 0, 0, null);
            super.paintComponent(g);
        }
    };

    GridBagConstraints gbcLblCard = new GridBagConstraints();
    cardPane.add(lblCard,gbcLblCard);

    return cardPane;
}

我有一个像下面这样的部分,将我手中的所有卡片添加到另一个 JLayeredPane jlpMyCards:

for (int i = 0; i < hand.getCardCount(); i++) {
    JLayeredPane thisCard = getCardPane(hand.getCard(i));

    //JOptionPane.showMessageDialog(null,thisCard);

    jlpMyCards.add(thisCard);
}

最后将 jlpMyCards 添加到框架中。

在渲染帧上,我看到所有卡片在手(根据计数),但所有卡片都显示加载的最后一张图像。 - 为什么?

我尝试用

打印卡片
JOptionPane.showMessageDialog(null,thisCard);

弹出对话框显示正确的图像。

注意:我猜 Card class 中的以下方法也可能会造成问题。

public ImageIcon getImageIcon() {
    BufferedImage img = null;
    try {
        img = ImageIO.read(new File(this.getClass().getResource(
                    getValueAsString().toLowerCase() + "_of_"+ 
                    getSuitAsString().toLowerCase() + ".png").toURI()));
        //Rescaling Image
        Image dimg = img.getScaledInstance(100, 146, Image.SCALE_SMOOTH);
        return new ImageIcon(dimg);
    } catch (IOException e) {
        e.printStackTrace();
    } catch (URISyntaxException e) {
        e.printStackTrace();
    }
    return null;
}

在循环的每次迭代中,您将值分配给字段 cardImageIcon。并且在渲染所有标签时调用 getImage()(在它们的 paintComponent 方法中)相同的 cardImageIcon 对象(在上次迭代期间设置)。

您可以将其作为局部变量,而不是将其保留为字段:

final ImageIcom cardImageIcon = card.getImageIcon();

JLabel lblCard = new JLabel() {
    @Override
    public void paintComponent(Graphics g) {
        g.drawImage(cardImageIcon.getImage(), 0, 0, null);
        super.paintComponent(g);
    }
};

重要的是将其声明为 final 以便在 paintComponent 方法中使用它。

也许您可以只使用 JLabel 构造函数,该构造函数将 Icon 作为构造函数中的参数:

JLabel lblCard = new JLabel(card.getImageIcon());

考虑到所有建议,我更改了 card.getImageIcon()。相反,我现在使用 getCardImagePane() 其中 returns 一个 JLayeredPane 在设置图像后。

下面是我现在使用的代码:

public CardImagePane getCardImagePane(boolean small) {
    return new CardImagePane(this.getClass().getResource(
            getValueAsString().toLowerCase() + "_of_"
                    + getSuitAsString().toLowerCase() + ".png"), small);
}

class CardImagePane extends JLayeredPane {

    private static final long serialVersionUID = 6829613165978637891L;

    private Image image;

    public CardImagePane(URL imgURL, boolean small) {
        Image tempImg = new ImageIcon(imgURL).getImage();
        this.image = tempImg.getScaledInstance(Constants.CARD_WIDTH,
                Constants.CARD_HEIGHT, Image.SCALE_SMOOTH);

        Dimension size = new Dimension(small ? Constants.CARD_WIDTH_SMALL
                : Constants.CARD_WIDTH, Constants.CARD_HEIGHT);
        setPreferredSize(size);
        setMinimumSize(size);
        setMaximumSize(size);
        setSize(size);
        setLayout(null);
    }

    public void paintComponent(Graphics g) {
        g.drawImage(image, 0, 0, null);
    }
}

感谢大家。请告诉我是否可以做一些更好的事情。