【问题标题】:Last image on JLabel is shown for all after adding JLayeredPane in loop在循环中添加 JLayeredPane 后,将显示 JLabel 上的最后一张图片
【发布时间】:2015-06-19 11:55:11
【问题描述】:

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

我正在开发一款纸牌游戏。

下面的方法接受一个 Card 对象作为参数,并返回一个 JLayeredPane 和一个带有卡片图像的 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 类中的以下方法也可能会产生问题。

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;
}

【问题讨论】:

  • 1) 为了尽快获得更好的帮助,请发布MCVE(最小完整可验证示例)或SSCCE(简短、自包含、正确示例)。 2) 例如,获取图像的一种方法是热链接到在this Q&A 中看到的图像。
  • @AndrewThompson 我不知道 MCVE。我会把问题放在 MCVE 中;)
  • @AndrewThompson 按照您在第二条评论中的建议进行了更改。
  • 猜测一下,您的 for 循环阻塞了 EDT;见Concurrency in SwingHow to Use Swing Timers
  • 为什么要绘制图标而不是设置 JLabel 的图标?

标签: java swing bufferedimage


【解决方案1】:

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

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

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);
    }
};

paintComponent 方法中使用它时必须将其声明为final。

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

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

【讨论】:

  • 我想我应该尝试做一些事情而不覆盖paintComponent 方法。你有什么建议?
  • 您可以将cardImageIcon 转换为局部变量。我已经更新了答案。
  • g.drawImage(cardImageIcon.getImage(), 0, 0, null); 最好是g.drawImage(cardImageIcon.getImage(), 0, 0, this);,因为每个JComponent 都是一个 ImageObserver ..
  • 或者你可以只使用 JLabel 构造函数,它将 Icon 作为构造函数中的参数
【解决方案2】:

考虑到所有建议,我更改了card.getImageIcon()。相反,我现在使用的是getCardImagePane(),它在将图像设置为 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);
    }
}

谢谢大家。请告诉我是否可以做得更好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-02
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 2018-05-23
    相关资源
    最近更新 更多