gpt4 book ai didi

java - 无法从 jpanel 中删除组件

转载 作者:行者123 更新时间:2023-12-02 08:51:02 26 4
gpt4 key购买 nike

我重构了我的代码以生成一个最小的、可重现的示例。

问题 - 我无法从面板中删除卡(我已在出现问题的代码中进行了注释,请参阅“ClearCardEventListener”类)。

完整代码如下。

在运行程序之前,您需要下载一个图像并将其添加到资源文件夹 = https://ibb.co/MNccGS0

  1. 运行程序
  2. 点击“添加卡片”按钮(这将在面板上添加 2 颗红心图像图标)
  3. 点击“清除卡”按钮(这就是问题所在,我无法从面板中删除卡)

    package debug.debug;

    import java.awt.Insets;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.List;

    import javax.swing.ImageIcon;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;

    public class App extends JFrame {
    public static void main(String[] args) {
    App app = new App();

    Insets insets = app.getInsets();
    app.setSize(300 + insets.left + insets.right,
    300 + insets.top + insets.bottom);
    }

    JPanel panel;
    JButton clearCardButton;
    JButton addCardButton;

    List<Card> playerCards = new ArrayList<Card> ();

    Deck deck = new Deck();

    public App() {
    setTitle("BlackJack Game");
    setVisible(true);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setLocationRelativeTo(null);
    panel = new JPanel();
    add(panel);
    panel.setLayout(null);
    addCardButton = new JButton("Add card");
    clearCardButton = new JButton("Clear card");

    panel.add(addCardButton);
    panel.add(clearCardButton);

    addCardButton.addActionListener(new AddCardEventListener(this, this.deck));
    clearCardButton.addActionListener(new ClearCardEventListener(this, this.deck));

    addCardButton.setBounds(150, 50, addCardButton.getPreferredSize().width, addCardButton.getPreferredSize().height);
    clearCardButton.setBounds(150, 100, clearCardButton.getPreferredSize().width, clearCardButton.getPreferredSize().height);

    }

    public JPanel getPanel() {
    return panel;
    }

    public void addPlayerCard(Card card) {
    playerCards.add(card);
    }

    public List<Card> getPlayerCards() {
    return playerCards;
    }

    public List<JLabel> getPlayerCardLabels() {

    List<JLabel> playerCardLabels = new ArrayList<JLabel> ();

    for (int i = 0; i<this.getPlayerCards().size(); i++) {
    playerCardLabels.add(this.getPlayerCards().get(i).getCardLabel());

    }

    return playerCardLabels;
    }

    }

    class AddCardEventListener implements ActionListener {

    private App app;
    private Deck deck;

    AddCardEventListener(App app, Deck deck) {
    this.app = app;
    this.deck = deck;
    }

    public void actionPerformed(ActionEvent arg0) {

    // Player gets a card
    app.addPlayerCard(deck.getCard());

    // Display that player's card
    app.getPanel()
    .add(app.getPlayerCards().get(0).getCardLabel()).setBounds(0, 0, 72, 96);

    }

    }

    class ClearCardEventListener implements ActionListener {

    private App app;
    private Deck deck;

    ClearCardEventListener(App app, Deck deck) {
    this.app = app;
    this.deck = deck;
    }

    public void actionPerformed(ActionEvent arg0) {

    System.out.println("DEBUG: " + app.getPlayerCards().get(0).getCardLabel());

    /***
    *
    * NOT ABLE TO REMOVE CARD, WHY ???
    *
    */

    app.getPlayerCards().get(0).getCardLabel().setIcon(null);
    app.getPlayerCards().get(0).getCardLabel().revalidate();
    app.getPlayerCards().get(0).getCardLabel().repaint();

    app.getPanel().remove(app.getPlayerCards().get(0).getCardLabel());

    }

    }

    class Card {

    private String suit;
    private String rank;
    private int value;

    public void setSuit(String suit) {
    this.suit = suit;
    }
    public void setRank(String rank) {
    this.rank = rank;
    }
    public void setValue(int value) {
    this.value = value;
    }
    public String getSuit() {
    return suit;
    }
    public String getRank() {
    return rank;
    }
    public int getValue() {
    return value;
    }

    // Hardcoded for debugging, so every card image is a 2 of hearts
    public JLabel getCardLabel() {
    return new JLabel(new ImageIcon(getClass()
    .getResource("/cards/2h.png")));
    }
    }

    class Deck {

    private final String RANKS[] = {
    "Ace",
    "Deuce",
    "Three",
    "Four",
    "Five",
    "Six",
    "Seven",
    "Eight",
    "Nine",
    "Ten",
    "Jack",
    "Queen",
    "King"
    };
    private final String SUITS[] = {
    "Spades",
    "Hearts",
    "Diamonds",
    "Clubs"
    };

    private Card[] deck;
    static private int cardPosition = 0;

    public Deck() {
    deck(); // Create the deck
    shuffle(); // shuffle the deck
    }

    public Card[] deck() {
    deck = new Card[52];

    for (int x = 0; x<deck.length; x++) {
    String rankTemp = RANKS[x % 13];
    String suitTemp = SUITS[x / 13];
    deck[x] = new Card();
    deck[x].setRank(rankTemp);
    deck[x].setSuit(suitTemp);
    deck[x].setValue((x % 13) + 1);
    if (deck[x].getValue() > 10)
    deck[x].setValue(10);
    else if (deck[x].getValue() == 1)
    deck[x].setValue(11);
    }

    return deck;
    }

    public void shuffle() {
    Collections.shuffle(Arrays.asList(deck()));
    }

    public Card[] getDeck() {
    return deck;
    }

    public Card getCard() {
    return deck[cardPosition++];
    }

    }

最佳答案

问题#1

每次调用 Card#getCardLabel 时,它都会创建一个新的 JLabel 实例...

class Card {

// Hardcoded for debugging, so every card image is a 2 of hearts
public JLabel getCardLabel() {
return new JLabel(new ImageIcon(getClass()
.getResource("/cards/2h.png")));
}
}

这意味着当您这样做时...

app.getPanel().add(app.getPlayerCards().get(0).getCardLabel()).setBounds(0, 0, 72, 96);

还有...

System.out.println("DEBUG: " + app.getPlayerCards().get(0).getCardLabel());

还有...

app.getPlayerCards().get(0).getCardLabel().setIcon(null);
app.getPlayerCards().get(0).getCardLabel().revalidate();
app.getPlayerCards().get(0).getCardLabel().repaint();

app.getPanel().remove(app.getPlayerCards().get(0).getCardLabel());

每次调用实际上都是创建一个 JLabel 的新实例,因此屏幕上的实例与您尝试修改的实例无关。

因此,您的 Card#getCardLabel 应该仅创建一个 JLabel 一次,这也称为“延迟加载”...

class Card {

private JLabel label;

//...

// Hardcoded for debugging, so every card image is a 2 of hearts
public JLabel getCardLabel() {
if (label == null) {
// Simple image for demonstration purposes
BufferedImage img = new BufferedImage(100, 150, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = img.createGraphics();
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, 100, 150);
g2d.setColor(Color.RED);
g2d.drawLine(0, 0, 100, 150);
g2d.drawLine(100, 0, 0, 150);
g2d.dispose();

label = new JLabel(new ImageIcon(img));
}

return label;
}
}

问题#2

Swing 是惰性的(好吧,它是“优化的”),这意味着添加或删除组件本身不会触发布局或绘制过程。这样做是为了让您可以对 UI 进行大量更改,而不是让它尝试更新每个更改,这会非常慢。

这意味着当您添加或删除组件时,您还应该调用 repaint 来触发新的绘制 channel (我还建议 revalidate,但您'没有使用任何布局管理器,所以它不会为你做任何事情)

app.getPanel().remove(app.getPlayerCards().get(0).getCardLabel());
app.getPanel().repaint();

关于java - 无法从 jpanel 中删除组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60765375/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com