How to remove a JLabel when I click a certain key on the keyboard?

后端 未结 1 1574
悲&欢浪女
悲&欢浪女 2021-01-28 06:55

So I have a GUI, a Tile class and a method class. I created four tiles in my Game class which consists of Tiles that has contains a letter and a color in each of them. I now wan

相关标签:
1条回答
  • 2021-01-28 07:39
    • Your game is the "controller", it's responsible for managing the functionality and communication between the model and view.
    • Your view should be a representation of your model
    • Your model (and possibly your view) should be providing event notification support, to which you controller will need to monitor, in order to manage the requirements and logic.

    To start with, you code is in mess. You are making to much use of static and it's not going to help you.

    For example, I re-worked your Tile class to look more like this.

    public class Tile extends JLabel {
    
        public static Font font = new Font("Serif", Font.BOLD, 39);
    
        private char _c;
    
        public Tile(char c, Color background) {
            setBackground(background);
            setOpaque(true);
            _c = c;
            setText(convert());
    
        }
    
        public static char randomLetter() {
            Random r = new Random();
            char randomChar = (char) (97 + r.nextInt(25));
            return randomChar;
        }
    
        public char getChar() {
            return _c;
        }
    
        public String convert() {
            return String.valueOf(getChar());
        }
    }
    

    Rather then calling randomLetter each time you called getChar or convert, you should only be using it when you actually need a new character, otherwise you'll never know what the Tile's character actually is/was to begin with

    Next, we need some kind of observer contract for the mode, so it can tell us when things have changed, for example.

    public interface ModelListener {
        public void tileWasRemoved(Tile tile);
    }
    

    It's nothing special, but this provides a means for the Model to provide notification when a Tile is removed and which Tile was actually removed.

    Next, I updated the Model so that it actual "models" something. The Model now maintains a list of Tiles and provides functionality for adding and removing them. It also provides support for the ModelListener and event triggering

    public class Model {
    
        private ArrayList<Tile> list = new ArrayList<Tile>();
        private List<ModelListener> listeners = new ArrayList<>(25);
    
        public Model() {
        }
    
        public void addModelListener(ModelListener listener) {
            listeners.add(listener);
        }
    
        public void removeModelListener(ModelListener listener) {
            listeners.remove(listener);
        }
    
        protected void fireTileRemoved(Tile tile) {
            for (ModelListener listener : listeners) {
                listener.tileWasRemoved(tile);
            }
        }
    
        public void removeByChar(char value) {
            Iterator<Tile> iterator = list.iterator();
            while (iterator.hasNext()) {
                Tile tile = iterator.next();
                if (value == tile.getChar()) {
                    fireTileRemoved(tile);
                    iterator.remove();
                }
            }
        }
    
        private void add(Tile tile) {
            list.add(tile);
        }
    
        private Iterable<Tile> getTiles() {
            return Collections.unmodifiableList(list);
        }
    }
    

    Next, I went to the Game and updated it so it adds Tiles to the Model and uses the Model data to setup the UI. It then registers the KeyListener and ModelListener

    public Game() {
        model = new Model();
        model.add(new Tile(Tile.randomLetter(), Color.WHITE));
        model.add(new Tile(Tile.randomLetter(), Color.RED));
        model.add(new Tile(Tile.randomLetter(), Color.GREEN));
        model.add(new Tile(Tile.randomLetter(), Color.YELLOW));
    
        JFrame frame = new JFrame();
        frame.getContentPane().setLayout(new GridLayout(4, 1));
        frame.setSize(500, 800);
        frame.setVisible(true);
    
        for (Tile tile : model.getTiles()) {
            frame.add(tile);
        }
    
        model.addModelListener(new ModelListener() {
            @Override
            public void tileWasRemoved(Tile tile) {
                frame.remove(tile);
                frame.revalidate();
                frame.repaint();
            }
        });
        frame.getContentPane().addKeyListener(this);
        frame.getContentPane().setFocusable(true);
        frame.getContentPane().requestFocusInWindow();
    }
    

    And finally, the keyTyped event now asks the Model to remove a Tile of the given key...

    @Override
    public void keyTyped(KeyEvent e) {
        model.removeByChar(e.getKeyChar());
    }
    

    As a proof of concept...

    import java.awt.Color;
    import java.awt.EventQueue;
    import java.awt.Font;
    import java.awt.GridLayout;
    import java.awt.event.KeyEvent;
    import java.awt.event.KeyListener;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Random;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class Game implements KeyListener {
    
        public static void main(String[] args) {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                        ex.printStackTrace();
                    }
    
                    new Game();
                }
            });
        }
    
        private Model model;
    
        public Game() {
            model = new Model();
            model.add(new Tile(Tile.randomLetter(), Color.WHITE));
            model.add(new Tile(Tile.randomLetter(), Color.RED));
            model.add(new Tile(Tile.randomLetter(), Color.GREEN));
            model.add(new Tile(Tile.randomLetter(), Color.YELLOW));
    
            JFrame frame = new JFrame();
            frame.getContentPane().setLayout(new GridLayout(4, 1));
            frame.setSize(500, 800);
            frame.setVisible(true);
    
            for (Tile tile : model.getTiles()) {
                frame.add(tile);
            }
    
            model.addModelListener(new ModelListener() {
                @Override
                public void tileWasRemoved(Tile tile) {
                    frame.remove(tile);
                    frame.revalidate();
                    frame.repaint();
                }
            });
            frame.getContentPane().addKeyListener(this);
            frame.getContentPane().setFocusable(true);
            frame.getContentPane().requestFocusInWindow();
        }
    
        @Override
        public void keyPressed(KeyEvent e) {
        }
    
        @Override
        public void keyReleased(KeyEvent e) {
        }
    
        @Override
        public void keyTyped(KeyEvent e) {
            model.removeByChar(e.getKeyChar());
        }
    
        public interface ModelListener {
    
            public void tileWasRemoved(Tile tile);
        }
    
        public class Model {
    
            private ArrayList<Tile> list = new ArrayList<Tile>();
            private List<ModelListener> listeners = new ArrayList<>(25);
    
            public Model() {
            }
    
            public void addModelListener(ModelListener listener) {
                listeners.add(listener);
            }
    
            public void removeModelListener(ModelListener listener) {
                listeners.remove(listener);
            }
    
            protected void fireTileRemoved(Tile tile) {
                for (ModelListener listener : listeners) {
                    listener.tileWasRemoved(tile);
                }
            }
    
            public void removeByChar(char value) {
                Iterator<Tile> iterator = list.iterator();
                while (iterator.hasNext()) {
                    Tile tile = iterator.next();
                    if (value == tile.getChar()) {
                        fireTileRemoved(tile);
                        iterator.remove();
                    }
                }
            }
    
            private void add(Tile tile) {
                list.add(tile);
            }
    
            private Iterable<Tile> getTiles() {
                return Collections.unmodifiableList(list);
            }
        }
    
        public static class Tile extends JLabel {
    
            public static Font font = new Font("Serif", Font.BOLD, 39);
    
            private char _c;
    
            public Tile(char c, Color background) {
                setBackground(background);
                setOpaque(true);
                _c = c;
                setText(convert());
    
            }
    
            public static char randomLetter() {
                Random r = new Random();
                char randomChar = (char) (97 + r.nextInt(25));
                return randomChar;
            }
    
            public char getChar() {
                return _c;
            }
    
            public String convert() {
                return String.valueOf(getChar());
            }
        }
    
    }
    

    How ever...

    As a general rule of thumb, KeyListener is a pain to work with and you should be making use of the key bindings API instead, for example

    import java.awt.AWTKeyStroke;
    import java.awt.Color;
    import java.awt.EventQueue;
    import java.awt.Font;
    import java.awt.GridLayout;
    import java.awt.event.ActionEvent;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Random;
    import javax.swing.AbstractAction;
    import javax.swing.Action;
    import javax.swing.ActionMap;
    import javax.swing.InputMap;
    import javax.swing.JComponent;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.KeyStroke;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class Game {
    
        public static void main(String[] args) {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                        ex.printStackTrace();
                    }
    
                    new Game();
                }
            });
        }
    
        private Model model;
    
        public Game() {
            model = new Model();
            model.add(new Tile(Tile.randomLetter(), Color.WHITE));
            model.add(new Tile(Tile.randomLetter(), Color.RED));
            model.add(new Tile(Tile.randomLetter(), Color.GREEN));
            model.add(new Tile(Tile.randomLetter(), Color.YELLOW));
    
            JFrame frame = new JFrame();
            frame.getContentPane().setLayout(new GridLayout(4, 1));
            frame.setSize(500, 800);
            frame.setVisible(true);
    
            for (Tile tile : model.getTiles()) {
                frame.add(tile);
                KeyStroke ks = KeyStroke.getKeyStroke(tile.getChar());
                String name = "typed." + tile.getChar();
                Action action = new TileAction(model, tile.getChar());
    
                registerKeyBinding((JComponent)frame.getContentPane(), name, ks, action);
            }
    
            model.addModelListener(new ModelListener() {
                @Override
                public void tileWasRemoved(Tile tile) {
                    frame.remove(tile);
                    frame.revalidate();
                    frame.repaint();
                }
            });
        }
    
        public void registerKeyBinding(JComponent parent, String name, KeyStroke ks, Action action) {
            InputMap im = parent.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
            ActionMap am = parent.getActionMap();
    
            im.put(ks, name);
            am.put(name, action);
        }
    
        public class TileAction extends AbstractAction {
    
            private Model model;
            private char value;
    
            public TileAction(Model model, char value) {
                this.model = model;
                this.value = value;
            }
    
            @Override
            public void actionPerformed(ActionEvent e) {
                model.removeByChar(value);
            }
    
        }
    
        public interface ModelListener {
    
            public void tileWasRemoved(Tile tile);
        }
    
        public class Model {
    
            private ArrayList<Tile> list = new ArrayList<Tile>();
            private List<ModelListener> listeners = new ArrayList<>(25);
    
            public Model() {
            }
    
            public void addModelListener(ModelListener listener) {
                listeners.add(listener);
            }
    
            public void removeModelListener(ModelListener listener) {
                listeners.remove(listener);
            }
    
            protected void fireTileRemoved(Tile tile) {
                for (ModelListener listener : listeners) {
                    listener.tileWasRemoved(tile);
                }
            }
    
            public void removeByChar(char value) {
                Iterator<Tile> iterator = list.iterator();
                while (iterator.hasNext()) {
                    Tile tile = iterator.next();
                    if (value == tile.getChar()) {
                        fireTileRemoved(tile);
                        iterator.remove();
                    }
                }
            }
    
            private void add(Tile tile) {
                list.add(tile);
            }
    
            private Iterable<Tile> getTiles() {
                return Collections.unmodifiableList(list);
            }
        }
    
        public static class Tile extends JLabel {
    
            public static Font font = new Font("Serif", Font.BOLD, 39);
    
            private char _c;
    
            public Tile(char c, Color background) {
                setBackground(background);
                setOpaque(true);
                _c = c;
                setText(convert());
    
            }
    
            public static char randomLetter() {
                Random r = new Random();
                char randomChar = (char) (97 + r.nextInt(25));
                return randomChar;
            }
    
            public char getChar() {
                return _c;
            }
    
            public String convert() {
                return String.valueOf(getChar());
            }
        }
    
    }
    

    See How to Use Key Bindings for more details.

    0 讨论(0)
提交回复
热议问题