Reputation:
I'm trying to get a rectangle in my JFrame to move when I press a given key on the keyboard, but I'm seemingly having a hard time doing that. Here's my code:
package TestPackage;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JComponent;
public class Mainframe extends JComponent implements KeyListener
{
private static final long serialVersionUID = 1L;
int x = 350;
int y = 250;
public static void main (String[] args)
{
JFrame frame = new JFrame ("Mainframe");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.setSize (800, 600);
frame.setFocusable (true);
frame.getContentPane().setBackground (Color.WHITE);
frame.getContentPane().add (new Mainframe());
frame.addKeyListener (new Mainframe());
frame.setVisible (true);
}
public void paint (Graphics graphics)
{
graphics.setColor (Color.BLACK);
graphics.fillRect (x, y, 100, 100);
}
public void keyPressed (KeyEvent event)
{
if (event.getKeyCode() == KeyEvent.VK_A)
{
x++;
repaint();
}
else if (event.getKeyCode() == KeyEvent.VK_D)
{
y++;
repaint();
}
}
public void keyReleased (KeyEvent event) {}
public void keyTyped (KeyEvent event) {}
}
I'm sure it's a problem with my KeyListener, as everything else works perfectly. Does anybody know what I'm doing wrong? Thanks.
Upvotes: 2
Views: 1149
Reputation: 347194
MainFrame
, one you add to the frame and one you use as the JFrame
's KeyListener
, this means that any modifications the KeyListener
instance makes to the x/y
values, won't be seen by the instance on the UIKeyListener
, it has too many focus related issues, use the Key Bindings API which was designed to overcome these issues. See How to Use Key Bindingspaint
(and especially if you're not going to call super.paint
), instead, you should override the paintComponent
method (and call super.paintComponent
). See Painting in AWT and Swing and Performing Custom Painting for more detailsFor example...
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
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.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Mainframe extends JComponent {
private static final long serialVersionUID = 1L;
int x = 350;
int y = 250;
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("Mainframe");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 600);
frame.setFocusable(true);
frame.getContentPane().setBackground(Color.WHITE);
frame.getContentPane().add(new Mainframe());
frame.setVisible(true);
}
});
}
public Mainframe() {
bindKeyWith("y.up", KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), new VerticalAction(-1));
bindKeyWith("y.down", KeyStroke.getKeyStroke(KeyEvent.VK_S, 0), new VerticalAction(1));
bindKeyWith("x.left", KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), new HorizontalAction(-1));
bindKeyWith("x.right", KeyStroke.getKeyStroke(KeyEvent.VK_D, 0), new HorizontalAction(1));
}
protected void bindKeyWith(String name, KeyStroke keyStroke, Action action) {
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(keyStroke, name);
am.put(name, action);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); //To change body of generated methods, choose Tools | Templates.
g.setColor(Color.BLACK);
g.fillRect(x, y, 100, 100);
}
public abstract class MoveAction extends AbstractAction {
private int delta;
public MoveAction(int delta) {
this.delta = delta;
}
public int getDelta() {
return delta;
}
protected abstract void applyDelta();
@Override
public void actionPerformed(ActionEvent e) {
applyDelta();
}
}
public class VerticalAction extends MoveAction {
public VerticalAction(int delta) {
super(delta);
}
@Override
protected void applyDelta() {
int delta = getDelta();
y += delta;
if (y < 0) {
y = 0;
} else if (y + 100 > getHeight()) {
y = getHeight() - 100;
}
repaint();
}
}
public class HorizontalAction extends MoveAction {
public HorizontalAction(int delta) {
super(delta);
}
@Override
protected void applyDelta() {
int delta = getDelta();
x += delta;
if (x < 0) {
x = 0;
} else if (x + 100 > getWidth()) {
x = getWidth() - 100;
}
repaint();
}
}
}
Upvotes: 1
Reputation: 7104
make your main like this and it will work
public static void main (String[] args)
{
JFrame frame = new JFrame ("Mainframe");
JComponent test = new Mainframe();
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.setSize (800, 600);
frame.setFocusable (true);
frame.getContentPane().setBackground (Color.WHITE);
frame.getContentPane().add (test);
frame.addKeyListener ((KeyListener) test);
frame.setVisible (true);
}
Upvotes: 0