javaswingkeylistener

How to add JLabel of KeyListener object in Jframe of Main class


I am a bit to new to this Java bit of coding. The problem is that I have a different class for KeyListener and an image that I want to display if the user presses a key, but the image is from JLabel and I want to add it in JFrame of the main class but I am not understanding how I would do that. Yes I did see another question, this one: How I add a JLabel to a JFrame on another class? but I can't do the suggested method in my code because Key Listener when called in the main method will only process the KeyListening part when called like : jframe.add(new KeyListener()) something like that, but the image will not be added because it is contained in a JLabel and JLabel is not added to JFrame. Here is my bit of Code of KeyListener:

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
import javax.swing.JTextField;
import java.awt.*;
import javax.swing.*;

class MKeyListener extends KeyAdapter
{
  static int n = 0;
    @Override
    public void keyPressed(KeyEvent event) 
    {
      if (event.getKeyCode() == KeyEvent.VK_ESCAPE) 
      {
        n += 1;
        if(n % 2 == 1)
        {
            
        }
        else
        {
            System.out.println("Not Quitting now");
        }
      }
      else if(event.getKeyCode() == KeyEvent.VK_ENTER && n % 2 == 1)
      {
          System.out.println("Quitting now...");
          try
          {
            Thread.sleep(200);
          }
          catch(Exception e)
          {
          }
          System.exit(0);
      }
    }
}

This is my Main method

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
import javax.swing.JTextField;
import java.awt.*;
import javax.swing.*;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JLabel;
import javax.swing.ImageIcon;

public class Main
{
    
    public static void main(String[] args) throws Exception 
    {
     JTextField textField = new JTextField();
     textField.addKeyListener(new MKeyListener());
     JFrame jframe = new JFrame();
     jframe.add(textField);
     jframe.setSize(1000, 1000);
     jframe.setTitle("First Development In JAVA Try : Day 3");
     jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     jframe.setVisible(true);
    }
}

Could someone please suggest a method to add that image when a user presses a key?


Solution

  • The "basic" answer to your question is, you need to use some kind of "observer pattern".

    The intention is, your "key handler" is going to monitor some kind of keyboard input, when some trigger occurs (a particular key is pressed), it will notify all interested observers of the said action.

    Swing calls these "listeners", so, you've already seen them in action.

    1. Don't add a KeyListener to a JTextField, this is just a bad idea. If you want to monitor input into the JTextField, use a DocumentListener on the field's Document. If you want to monitor "general" keyboard input, then make use of the key bindings API instead.
    2. Don't call Thread.sleep from within the Event Dispatching Thread, this is just going to cause no end of issues (and angry users)

    The following example makes use the key bindings API to monitor Q, W, E, S, D, Z, X, C as a simple representation of 8 directions.

    The example makes use of a simple "listener" which notifies the interested party that some direction has been pressed. You're not limited to a single method, you could, for example have methods mapped directly to a specific action ie, keyHandlerPerformExit which is called when some "exit" key sequence is triggered.

    The example also allows the Action to trigger a call back directly to the KeyHanderListener, again, you don't need to do this, you could have the Action call back a method in the KeyHandler and it could then perform some additional calculations or operations and then, based on what ever it is you want to do, then notify the listener

    HappyKeys

    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.KeyEvent;
    import java.util.HashMap;
    import java.util.Map;
    import javax.swing.AbstractAction;
    import javax.swing.ActionMap;
    import javax.swing.InputMap;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.KeyStroke;
    import javax.swing.Timer;
    import javax.swing.border.LineBorder;
    
    public class Test {
    
        public static void main(String[] args) {
            new Test();
        }
    
        public Test() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    JFrame frame = new JFrame();
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class TestPane extends JPanel {
    
            private Map<KeyHandler.Direction, JPanel> mapPanels;
            private KeyHandler keyHandler;
    
            public TestPane() {
                mapPanels = new HashMap<>();
                setLayout(new GridBagLayout());
                GridBagConstraints gbc = new GridBagConstraints();
                gbc.gridx = 0;
                gbc.gridy = 0;
    
                add(createPanel(KeyHandler.Direction.LEFT_UP), gbc);
                gbc.gridx++;
                add(createPanel(KeyHandler.Direction.UP), gbc);
                gbc.gridx++;
                add(createPanel(KeyHandler.Direction.RIGHT_UP), gbc);
    
                gbc.gridx = 0;
                gbc.gridy++;
                add(createPanel(KeyHandler.Direction.LEFT), gbc);
                gbc.gridx++;
                add(createPanel(), gbc);
                gbc.gridx++;
                add(createPanel(KeyHandler.Direction.RIGHT), gbc);
    
                gbc.gridx = 0;
                gbc.gridy++;
                add(createPanel(KeyHandler.Direction.LEFT_DOWN), gbc);
                gbc.gridx++;
                add(createPanel(KeyHandler.Direction.DOWN), gbc);
                gbc.gridx++;
                add(createPanel(KeyHandler.Direction.RIGHT_DOWN), gbc);
                
                keyHandler = new KeyHandler(getInputMap(WHEN_IN_FOCUSED_WINDOW), getActionMap(), new KeyHandlerListener() {
                    @Override
                    public void keyHandlerDidPress(KeyHandler.Direction direction) {
                        activate(direction);
                    }
                });
            }
            
            protected JPanel createPanel() {
                JPanel panel = new JPanel() {
                    @Override
                    public Dimension getPreferredSize() {
                        return new Dimension(50, 50);
                    }
                };
                panel.setBorder(new LineBorder(Color.DARK_GRAY));
                return panel;
            }
    
            protected JPanel createPanel(KeyHandler.Direction direction) {
                JPanel panel = createPanel();
                mapPanels.put(direction, panel);
                return panel;
            }
            
            protected void activate(KeyHandler.Direction direction) {
                JPanel panel = mapPanels.get(direction);
                panel.setBackground(Color.BLUE);
                Timer timer = new Timer(250, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        panel.setBackground(null);
                    }
                });
                timer.setRepeats(false);
                timer.start();
            }
    
        }
    
        public interface KeyHandlerListener {
    
            public void keyHandlerDidPress(KeyHandler.Direction direction);
        }
    
        public class KeyHandler {
    
            public enum Direction {
                UP, DOWN, LEFT, RIGHT,
                LEFT_UP, RIGHT_UP,
                LEFT_DOWN, RIGHT_DOWN
            }
    
            public KeyHandler(InputMap inputMap, ActionMap actionMap, KeyHandlerListener listener) {
                inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_Q, 0), "Press.leftUp");
                inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), "Press.up");
                inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_E, 0), "Press.rightUp");
                inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), "Press.left");
                inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0), "Press.right");
                inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_Z, 0), "Press.leftDown");
                inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, 0), "Press.down");
                inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, 0), "Press.rightDown");
                
                actionMap.put("Press.leftUp", new DirectionAction(Direction.LEFT_UP, listener));
                actionMap.put("Press.up", new DirectionAction(Direction.UP, listener));
                actionMap.put("Press.rightUp", new DirectionAction(Direction.RIGHT_UP, listener));
                actionMap.put("Press.left", new DirectionAction(Direction.LEFT, listener));
                actionMap.put("Press.right", new DirectionAction(Direction.RIGHT, listener));
                actionMap.put("Press.leftDown", new DirectionAction(Direction.LEFT_DOWN, listener));
                actionMap.put("Press.down", new DirectionAction(Direction.DOWN, listener));
                actionMap.put("Press.rightDown", new DirectionAction(Direction.RIGHT_DOWN, listener));
            }
    
            protected class DirectionAction extends AbstractAction {
    
                private Direction direction;
                private KeyHandlerListener listener;
    
                public DirectionAction(Direction direction, KeyHandlerListener listener) {
                    this.direction = direction;
                    this.listener = listener;
                }
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    listener.keyHandlerDidPress(direction);
                }
    
            }
    
        }
    }