【问题标题】:How to use key bindings on JLabel? [duplicate]如何在 JLabel 上使用键绑定? [复制]
【发布时间】:2015-04-18 09:53:59
【问题描述】:

我是使用 java 编码的初学者(也使用英语),我正在尝试使用 eclipse 制作乒乓球游戏。 我的问题是我不知道如何通过按键盘上的不同键来移动我的 2 个球拍(JLabel)。 我第一次尝试使用 KeyListener 但我没有成功,所以现在我尝试使用 keyBinding,我阅读了很多教程但我不太了解。

那么我怎样才能通过按箭头键简单地让我的两个球拍移动。

这里是部分代码:

import java.awt.Color;
import javax.swing.*;
import java.awt.event.*;

public class Pongg extends JPanel implements KeyListener {


private JLabel Racket1;                   // <----- Déclaration des JLabel/JLayeredPane ici pour pouvoir les utiliser (KeyListener)
private JLabel Racket2;                   //


public Pongg() {


    //Création de la fenetre
    JFrame fenetre = new JFrame("Fenetre");
    fenetre.setLocationRelativeTo (null);
    fenetre.setVisible(true);
    fenetre.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    fenetre.setSize(1000,600);

    //Box Main + JLayeredPane (fond noir)
    Box main=Box.createVerticalBox();
    JLayeredPane Fond = new JLayeredPane();
    Fond.setBackground(Color.black);        
    Fond.setOpaque(true);
    Fond.setVisible(true);

    main.add(Fond);
    fenetre.add(main);

    //Plateformes
    JLabel Racket1 = new JLabel();
    JLabel Racket2 = new JLabel();      

    //--->Racket 1 :        
    Racket1.setBounds(50, 200, 16, 100);   //<----- setBounds (Placer position du JLabel x,y + taille de la plateforme x,y)
    Racket1.setBackground(Color.white);
    Racket1.setOpaque(true);



    //--->Racket 2 :

    Racket2.setBounds(900, 200, 16, 100);
    Racket2.setBackground(Color.white);
    Racket2.setOpaque(true);

    Fond.add(Racket1); 
    Fond.add(Racket2);

EDDIT:这里我尝试用 keyListener 来做(我不知道如何用 keyBinding 来做):

private Set appuye = new HashSet();

    public void keyTyped(KeyEvent e) {
    }

    public void keyPressed(KeyEvent e) {
        appuye.add(e.getKeyCode()); // On ajoute le nombre correspondant à la touche pressée à la liste
            if (appuye.contains(KeyEvent.VK_UP)) { // la liste contient-elle cette touche ? (c'est un int static, donc utilisable à partir de la classe, même sans objet)
                Racket1.setLocation(Racket1.getX(), Racket1.getY() - 16);
            }
            if (appuye.contains(KeyEvent.VK_DOWN)) {
                Racket1.setLocation(Racket1.getX(), Racket1.getY() + 16);
            }
            if (appuye.contains(KeyEvent.VK_A)) {
                Racket2.setLocation(Racket2.getX(), Racket2.getY() - 16);
            }
            if (appuye.contains(KeyEvent.VK_Q)) {
                Racket2.setLocation(Racket2.getX(), Racket2.getY() + 16);
            }
    }

    public void keyReleased(KeyEvent e) {
        appuye.remove(e.getKeyCode()); // Lorsque la touche est relachée, on retire son numéro de la liste.

}           

【问题讨论】:

  • 你认为第三次幸运......
  • 我希望是的,我在此代码上待了 3 天。
  • I have no idea how to do it with keyBinding) - 你不知道如何使用键绑定是什么意思?我在上一个问题中给了你完整的工作代码!您是否按照我给您的链接进行操作?你下载了示例代码吗?该代码甚至使用了两个标签来代表您的球拍。
  • 是的,我说过因为键绑定比 keylistener 更复杂,而且在阅读了您发送给我的代码后,我并不真正了解如何使用键绑定,但 MadProgrammer 帮助我将 keyBindings 调整为我的程序和现在我更好地了解它是如何工作的,但感谢您的回答
  • @Silver,那么您对给出的答案的后续问题在哪里?你不明白代码的哪一部分?我们怎么能读懂你的想法来猜测你不明白的东西?该代码还创建了一个自定义Action。然后它在 KeyStroke 和 Action 之间创建一个绑定。如果您完全无视所提供的帮助,并在不解释您对所提供的帮助感到困惑的地方就同一主题提出 3 个问题时,这会很烦人。

标签: java swing jlabel key-bindings key-events


【解决方案1】:

键绑定和KeyListener是有区别的,一般来说,键绑定是首选。

请参阅How to write a KeyListenerHow to use key bindings 了解更多详情

要使用键绑定 API,您首先需要的是某种 Action 来响应键绑定。既然你只想让两个JLabels 上下移动,这其实很简单...

public class MoveAction extends AbstractAction {

    private JLabel label;
    private int yDelta;

    public MoveAction(JLabel label, int yDelta) {
        this.label = label;
        this.yDelta = yDelta;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("...");
        Point p = label.getLocation();
        p.y += yDelta;
        label.setLocation(p);

        label.getParent().repaint();
    }

}

接下来您需要做的是使用Action 注册击键(将它们绑定在一起)

InputMap im = Racket1.getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = Racket1.getActionMap();

im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), "Left.down.up");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0), "Left.down.down");
am.put("Left.down.up", new MoveAction(Racket1, -4));
am.put("Left.down.down", new MoveAction(Racket1, 4));

例如...

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Pongg extends JPanel {

    private JLabel Racket1;                                  // <----- Déclaration des JLabel/JLayeredPane ici pour pouvoir les utiliser (KeyListener)
    private JLabel Racket2;                                  //

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

            JFrame frame = new JFrame("Testing");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(new Pongg());
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
        });
    }

    public Pongg() {

        setLayout(new BorderLayout());

        //Box Main + JLayeredPane (fond noir)
        JLayeredPane Fond = new JLayeredPane();
        Fond.setBackground(Color.black);
        Fond.setOpaque(true);
        Fond.setVisible(true);

        add(Fond);

        //Plateformes
        JLabel Racket1 = new JLabel();
        JLabel Racket2 = new JLabel();

        //--->Racket 1 :                
        Racket1.setBounds(50, 200, 16, 100);     //<----- setBounds (Placer position du JLabel x,y + taille de la plateforme x,y)
        Racket1.setBackground(Color.white);
        Racket1.setOpaque(true);

        //--->Racket 2 :
        Racket2.setBounds(900, 200, 16, 100);
        Racket2.setBackground(Color.white);
        Racket2.setOpaque(true);

        Fond.add(Racket1);
        Fond.add(Racket2);

        InputMap im = Racket1.getInputMap(WHEN_IN_FOCUSED_WINDOW);
        ActionMap am = Racket1.getActionMap();

        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), "Left.down.up");
        am.put("Left.down.up", new MoveAction(Racket1, -4));
    }

    @Override
    public Dimension getPreferredSize() {

        return new Dimension(1000, 600);

    }



    public class MoveAction extends AbstractAction {

        private JLabel label;
        private int yDelta;

        public MoveAction(JLabel label, int yDelta) {
            this.label = label;
            this.yDelta = yDelta;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("...");
            Point p = label.getLocation();
            p.y += yDelta;
            label.setLocation(p);

            label.getParent().repaint();
        }

    }
}

【讨论】:

  • 感谢您花时间帮助我,我将尝试使用您提供的信息。
  • 只是一些我不明白的事情:我们放置 public static void main(String[] args) { 的顺序是否重要?我真的不明白你为什么把 JFrame 放在 public static void main(String[] args) { 最后 Event.Queue 是为了同时使用两个动作?
  • static void main 在你的主类中的位置并不重要,我个人喜欢它在顶部,所以我可以看到入口点。我在main 方法中创建了框架,因为JPanel 不应该创建它自己的框架,至少不在构造函数中,因为您永远不知道您可能想要放置组件的位置。 EventQueue.invokeLater 确保在 EDT 的上下文中创建 UI,以防止可能出现的问题和违反 Swing 的单线程性质
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-09-12
  • 1970-01-01
  • 2011-09-19
  • 2011-09-20
  • 2023-02-09
  • 2014-01-17
相关资源
最近更新 更多