无法从jpanel中删除组件



我重构了代码,生成了一个最小的、可复制的示例。

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

下面是完整的代码。

在运行程序之前,您需要下载一个映像并将其添加到resources文件夹=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应该只创建一个JLabelONCE,这也被称为"懒惰加载"。。。

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来触发新的绘制过程(我也建议使用revalidate,但您没有使用任何布局管理器,所以它对您没有任何帮助(

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

最新更新