【问题标题】:How to add JLabel of KeyListener object in Jframe of Main class如何在 Main 类的 Jframe 中添加 KeyListener 对象的 JLabel
【发布时间】:2021-12-12 13:36:12
【问题描述】:

我对这种 Java 编码有点陌生。问题是我有一个不同的 KeyListener 类和一个图像,如果用户按下一个键,我想显示,但图像来自 JLabel,我想将它添加到主类的 JFrame 但我不明白如何我会那样做。 是的,我确实看到了另一个问题,这个问题: How I add a JLabel to a JFrame on another class? 但我不能在我的代码中执行建议的方法,因为在 main 方法中调用 Key Listener 时只会在调用时处理 KeyListening 部分: jframe.add(new KeyListener()) 类似的东西,但图像不会添加是因为它包含在 JLabel 中,而 JLabel 未添加到 JFrame。 这是我的 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);
      }
    }
}

这是我的主要方法

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);
    }
}

有人可以建议一种在用户按键时添加该图像的方法吗?

【问题讨论】:

  • 1.不要将KeyListener 添加到JTextField,这只是个坏主意。如果要监视JTextField 的输入,请在字段的Document 上使用DocumentListener。如果要监视“常规”键盘输入,请改用key bindings API。 2. 不要在 Event Dispatching Thread 中调用Thread.sleep,这只会导致无穷无尽的问题(和愤怒的用户)
  • 你的问题的“答案”是,你需要在你的“key handler”和主程序之间有某种观察者,所以“key handler”可以生成适当的事件,“main”程序可以响应并采取行动
  • 那么我需要添加什么观察者?我是新手,所以我不太了解
  • 我看到了键绑定 API,但该操作仅限于 java.swing.Action,而我需要一个图像显示操作。
  • 你错过了理解 API 的本质 - 由一个关键事件触发的 Action 依次触发其他类型的操作(即观察者回调)。 Action 只是作为一种机制来“包含”触发键时应该发生的事情

标签: java swing keylistener


【解决方案1】:

您问题的“基本”答案是,您需要使用某种“观察者模式”。

目的是,您的“按键处理程序”将监视某种键盘输入,当某些触发器发生(按下特定键)时,它将通知所有感兴趣的观察者所述动作。

Swing 将这些称为“侦听器”,因此,您已经看到了它们的实际作用。

  1. 不要将KeyListener 添加到JTextField,这只是个坏主意。如果您想监控JTextField 的输入,请在字段的Document 上使用DocumentListener。如果您想监控“常规”键盘输入,请改用key bindings API
  2. 不要在 Event Dispatching Thread 中调用 Thread.sleep,这只会导致无穷无尽的问题(和愤怒的用户)

以下示例使用键绑定 API 来监控 QWESDZXC作为8个方向的简单表示。

该示例使用了一个简单的“侦听器”,它通知相关方已按下某个方向。您不限于单一方法,例如,您可以将方法直接映射到特定操作,即 keyHandlerPerformExit,当触发某些“退出”键序列时调用它。

该示例还允许Action 直接触发对KeyHanderListener 的回调,同样,您不需要这样做,您可以让Action 回调KeyHandler 中的一个方法然后它可以执行一些额外的计算或操作,然后根据你想要做什么,然后通知监听器

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);
            }

        }

    }
}

【讨论】:

  • 所以我现在得到了这段代码,但它显示了输入和操作映射部分所需的标识符和分号`class component extends JComponent { JLabel y; AbstractAction smth = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { try { BufferedImage x = ImageIO.read(this.getClass().getResource("文件路径")); y = 新 JLabel(新 ImageIcon(x)); } 捕捉 (IOException e) { } } }; y.getInputMap().put(KeyStroke.getKeyStroke("ESCAPE"), "z"); y.getActionMap().put("z", smth); } `
  • 您在e 周围有相互冲突的声明。 e 被定义为ActionEventIOException。此外,基于 sn-p,您正在尝试在执行上下文(即构造函数或方法)之外执行代码
  • 所以我得到了 e 部分,但是对于执行上下文部分之外的代码,解决方案是什么?
  • @HamLemon 您需要放入方法或构造函数 - 这是基本的 Java 101
  • 哦,对不起,谢谢@MadProgrammer
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-04-10
  • 1970-01-01
  • 1970-01-01
  • 2013-11-17
  • 2012-06-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多