Невозможно удалить компонент из jpanel - PullRequest
0 голосов
/ 20 марта 2020

Я произвел рефакторинг своего кода для создания минимального воспроизводимого примера.

Проблема: я не могу вынуть карту из панели (я прокомментировал код, в котором возникает проблема, см. Класс " 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 Ответ

1 голос
/ 20 марта 2020

Задача # 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 является ленивым (хорошо, он «оптимизирован»), что означает, что добавление или удаление компонентов само по себе не вызывает макет или краска проходит. Это сделано для того, чтобы вы могли вносить значительные изменения в пользовательский интерфейс и не пытаться обновлять каждое изменение, что будет очень медленным.

Это означает, что когда вы добавляете или удаляете компонент, вы должны также вызвать repaint, чтобы вызвать новый проход рисования (я бы также порекомендовал revalidate, но вы не используете никаких менеджеров компоновки, поэтому он ничего не сделает для вас)

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