我重构了代码,生成了一个最小的、可复制的示例。
问题-我无法从面板中删除卡(我在出现问题的代码中进行了注释,请参阅类"ClearCardEventListener"(。
下面是完整的代码。
在运行程序之前,您需要下载一个映像并将其添加到resources文件夹=https://ibb.co/MNccGS0
- 运行程序
- 点击"添加卡片"按钮(这将在面板上添加2个心形图像图标(
-
点击"清除卡"按钮(这是问题所在,我无法从面板上移除卡(
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
ONCE,这也被称为"懒惰加载"。。。
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();