¿Cómo usar KeyListener con JFrame?

5 minutos de lectura

avatar de usuario
usuario3183679

Entonces, estaba tratando de hacer que un rectángulo se moviera con un KeyEvent (KeyListener) y cada vez que trato de presionar la tecla, el rectángulo no se mueve.

El rectángulo está dibujado, pero cada vez que golpeo el left y right llaves, no pasa nada. Tengo dos clases, una es mi clase principal con keyEvents y el marco y la otra, dibuja el rectángulo y mantiene la función para mover el rectángulo.

Aquí está mi código:

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JFrame;


public class mainFrame extends JFrame implements KeyListener{

mainDraw Draw = new mainDraw();

public void keyPressed(KeyEvent e) {

    int key = e.getKeyCode();

    if(key == KeyEvent.VK_D){

        Draw.moveRight();
    }
}

public void keyReleased(KeyEvent e) {


}
public void keyTyped(KeyEvent e) {}

public mainFrame()
{
    addKeyListener(this);
    setFocusable(true);
    setFocusTraversalKeysEnabled(false);
}

public static void main(String[] args) {

    mainFrame M1 = new mainFrame();

    mainDraw Draw = new mainDraw();

    JFrame frame = new JFrame("Square Move Practice");


    //frame
    frame.setVisible(true);
    frame.setResizable(false);
    frame.setSize(600, 600);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(Draw);

}
}

Y ahora la segunda clase:

import java.awt.Color;
import java.awt.Graphics;

import javax.swing.JComponent;

public class mainDraw extends JComponent{

public int x = 50;
public int y = 50;

public void paint(Graphics g){

    g.drawRect(x, y, 50, 50);
    g.fillRect(x, y, 50, 50);
    g.setColor(Color.BLACK);
}

public void moveRight()
{
    x = x + 5;
    y = y + 0;
    repaint();
}

}

Por favor, dime cómo puedo mover el rectángulo. ¡Gracias por adelantado!

El rectángulo no se mueve porque no estás usando JFrame correctamente. tienes que asignar frame para new mainFrame() en lugar de ignorar el instanciado mainFrame objeto.

Hay varios otros problemas como señala @MadProgrammer.

Aquí está el código que soluciona algunos de los problemas:

marco principal.java

import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;


public class mainFrame extends JFrame implements KeyListener{
    private mainDraw draw;

    public void keyPressed(KeyEvent e) {
        System.out.println("keyPressed");
    }

    public void keyReleased(KeyEvent e) {
        if(e.getKeyCode()== KeyEvent.VK_RIGHT)
            draw.moveRight();
        else if(e.getKeyCode()== KeyEvent.VK_LEFT)
            draw.moveLeft();
        else if(e.getKeyCode()== KeyEvent.VK_DOWN)
            draw.moveDown();
        else if(e.getKeyCode()== KeyEvent.VK_UP)
            draw.moveUp();

    }
    public void keyTyped(KeyEvent e) {
        System.out.println("keyTyped");
    }

    public mainFrame(){
        this.draw=new mainDraw();
        addKeyListener(this);
        setFocusable(true);
        setFocusTraversalKeysEnabled(false);
    }

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                mainFrame frame = new mainFrame();
                frame.setTitle("Square Move Practice");
                frame.setResizable(false);
                frame.setSize(600, 600);
                frame.setMinimumSize(new Dimension(600, 600));
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.getContentPane().add(frame.draw);
                frame.pack();
                frame.setVisible(true);
            }
        });
    }
}

mainDraw.java

import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JComponent;

public class mainDraw extends JComponent {

    public int x = 50;
    public int y = 50;

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawRect(x, y, 50, 50);
        g.fillRect(x, y, 50, 50);
        g.setColor(Color.BLACK);
    }

    public void moveRight() {
        x = x + 5;
        repaint();
    }

    public void moveLeft() {
        x = x - 5;
        repaint();
    }

    public void moveDown() {
        y = y + 5;
        repaint();
    }

    public void moveUp() {
        y = y - 5;
        repaint();
    }
}

Por cierto, usa SwingUtilities para poner el código de actualización de interfaz gráfica de usuario porque los objetos oscilantes no son seguros para subprocesos.

avatar de usuario
programador loco

Hay al menos tres problemas…

En primer lugar…

Tu mainFrame clase extends desde JFramepero en tu main método, creas una instancia de él y lo ignoras, creando tu propio JFrame.

los KeyListener está registrado en la instancia de mainFramees decir, se ha ignorado.

deberías deshacerte de extends JFrame ya que solo está confundiendo el problema

En segundo lugar…

KeyListener solo responderá a eventos clave cuando el componente en el que está registrado sea enfocable Y tenga un enfoque directo, lo que lo hace poco confiable.

En su lugar, debe utilizar el API de enlaces de teclas con el Draw panel, esto le permitirá superar los problemas de enfoque.

En tercer lugar…

Has roto la cadena de pintura, esto significa que cuando el rectángulo se mueva, lo que se pintó anteriormente seguirá estando.

Debe abstenerse de anular paint y en su lugar usar paintComponent. Hay muchas razones para esto, pero en general, pinta en segundo plano, se llama actualizaciones de componentes secundarios.

Por último, asegúrese de que está llamando super.paintComponent antes de hacer cualquier otra cosa, para asegurarse de que Graphics el contexto está preparado para pintar

Echa un vistazo a Realización de pintura personalizada para más detalles

Debe agregar su oyente en la clase mainDraw, no en su mainFrame.

Es una buena práctica no manejar eventos de teclas y mouse en Frames y Windows.

o/

Estaba tratando de implementar oyentes de acceso directo a todo el marco y no tuve éxito. Finalmente encontré una manera. Si desea configurar el oyente incluso cuando se enfoca en otro componente, debe agregar oyentes a todos los componentes.

Aquí está mi código,

Llama a esto en tu constructor:

setShortcutListener(this); // this = JFrame when you call in in constructor

Método setShortcutListener (marco JFrame):

private void setShortcutListener(JFrame frame) {
    List<Component> comp_list = Common.getAllComponents(frame);
    for (Component component : comp_list) {
        component.addKeyListener(getShortcutKeyListener());
    }
}

Método getAllComponents(marco); Class Common es solo una clase,

public static List<Component> getAllComponents(final Container c) {
    Component[] comps = c.getComponents();
    List<Component> compList = new ArrayList<Component>();
    for (Component comp : comps) {
        compList.add(comp);
        if (comp instanceof Container) {
            compList.addAll(getAllComponents((Container) comp));
        }
    }
    return compList;
}

Método getShortcutKeyListener() :

public static KeyListener getShortcutKeyListener() {
    KeyListener listener = new KeyListener() {

        @Override
        public void keyReleased(KeyEvent evt) {
            if (evt.getKeyCode() == KeyEvent.VK_F3) {
                // What you do when F3 key pressed
            } else if (evt.getKeyCode() == KeyEvent.VK_F2) {
                // What you do when F2 key pressed
            } 
        }

        @Override
        public void keyTyped(KeyEvent e) {
            // Do nothing
        }

        @Override
        public void keyPressed(KeyEvent e) {
            // Do nothing
        }
    };
    return listener;
}

Creo que tenemos formas más fáciles que esta, pero este código funciona exactamente como se esperaba. Los oyentes clave funcionan en cualquier lugar en forma.

Espero que esta respuesta ayude a alguien. Gracias.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad