I have written a sample code using KeyListener in Java,
I have created a JPanel, then set its focusable to true, I have created a KeyListener, requested a focus and then added the KeyListener to my panel. But the methods for the keyListener are never called. It seems although I have requested focus, it does not focus.
Can anyone help?
listener = new KeyLis();
this.setFocusable(true);
this.requestFocus();
this.addKeyListener(listener);
class KeyLis implements KeyListener{
#Override
public void keyPressed(KeyEvent e) {
currentver += 5;
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT : if(horizontalyInBounds()) currentPos-= 5;
break;
case KeyEvent.VK_RIGHT: if(horizontalyInBounds()) currentPos+= 5;
break;
}
repaint();
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent e) {
}
}
If any runnable code should be needed:
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class test extends JFrame {
private AreaOfGame areaOfGame;
public test()
{
super("");
setVisible(true);
this.setBackground(Color.darkGray);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.pack();
setLayout(null);
setBounds(200, 10, 400, 700);
areaOfGame = new AreaOfGame();
this.add(areaOfGame);
startGame();
}
public int generateNext()
{
Random r = new Random();
int n = r.nextInt(7);
return n;
}
public void startGame()
{
while(!areaOfGame.GameOver())
{
areaOfGame.startGame(generateNext());
}
}
public static void main(String[] args) {
new MainFrame();
}
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JPanel;
public class AreaOfGame extends JPanel {
private static final int rightside = 370;
private int bottom;
private int top;
private int currentPos;
private int currentver;
private KeyLis listener;
public AreaOfGame()
{
super();
bottom = 650;
top = 50;
setLayout(null);
setBounds(20, 50, 350, 600);
setVisible(true);
this.setBackground(Color.lightGray);
listener = new KeyLis();
this.setFocusable(true);
if(this.requestFocus(true))
System.out.println("true");;
this.addKeyListener(listener);
currentPos = 150;
currentver=0;
}
public void startGame(int n)
{
while(verticallyInBound()){
System.out.println("anything");
}
}
public boolean verticallyInBound()
{
if(currentPos<= bottom -50)
return true;
return false;
}
public boolean GameOver()
{
if(top>= bottom){
System.out.println("game over");
return true;
}
else return false;
}
public boolean horizontalyInBounds()
{
if(currentPos<=rightside && currentPos>= 20)
return true;
else return false;
}
class KeyLis implements KeyListener{
#Override
public void keyPressed(KeyEvent e) {
System.out.println("called");
currentver += 5;
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT : if(horizontalyInBounds()) currentPos-= 5; break;
case KeyEvent.VK_RIGHT: if(horizontalyInBounds()) currentPos+= 5; break;
}
repaint();
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent e) {
System.out.println("called 3");
}
}
}
I'll bet that you're requesting focus before the JPanel has been rendered (before the top level window has either had pack() or setVisible(true) called), and if so, this won't work. Focus request will only be possibly granted after components have been rendered. Have you checked what your call to requestFocus() has returned? It must return true for your call to have any chance for a success. Also it's better to use requestFocusInWindow() rather than requestFocus().
But more importantly, you shouldn't be using KeyListeners for this but rather key bindings, a higher level concept that Swing itself uses to respond to key presses.
Edit
An example of an SSCCE:
import java.awt.Dimension;
import java.awt.event.*;
import javax.swing.*;
public class TestKeyListener extends JPanel {
private KeyLis listener;
public TestKeyListener() {
add(new JButton("Foo")); // something to draw off focus
listener = new KeyLis();
this.setFocusable(true);
this.requestFocus();
this.addKeyListener(listener);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 200);
}
private class KeyLis extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT:
System.out.println("VK_LEFT pressed");
break;
case KeyEvent.VK_RIGHT:
System.out.println("VK_RIGHT pressed");
break;
}
}
}
private static void createAndShowGui() {
TestKeyListener mainPanel = new TestKeyListener();
JFrame frame = new JFrame("TestKeyListener");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Edit 2
And the equivalent SSCCE using Key Bindings:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class TestKeyBindings extends JPanel {
public TestKeyBindings() {
add(new JButton("Foo")); // something to draw off focus
setKeyBindings();
}
private void setKeyBindings() {
ActionMap actionMap = getActionMap();
int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = getInputMap(condition );
String vkLeft = "VK_LEFT";
String vkRight = "VK_RIGHT";
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), vkLeft);
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), vkRight);
actionMap.put(vkLeft, new KeyAction(vkLeft));
actionMap.put(vkRight, new KeyAction(vkRight));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 200);
}
private class KeyAction extends AbstractAction {
public KeyAction(String actionCommand) {
putValue(ACTION_COMMAND_KEY, actionCommand);
}
#Override
public void actionPerformed(ActionEvent actionEvt) {
System.out.println(actionEvt.getActionCommand() + " pressed");
}
}
private static void createAndShowGui() {
TestKeyBindings mainPanel = new TestKeyBindings();
JFrame frame = new JFrame("TestKeyListener");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Edit 3
Regarding your recent SSCCE, your while (true) loops are blocking your Swing event thread and may prevent user interaction or painting from happening. Better to use a Swing Timer rather than while (true). For example:
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;
public class BbbTest extends JFrame {
private AreaOfGame areaOfGame;
public BbbTest() {
super("");
// setVisible(true);
this.setBackground(Color.darkGray);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.pack();
setLayout(null);
setBounds(200, 10, 400, 700);
areaOfGame = new AreaOfGame();
this.add(areaOfGame);
setVisible(true);
startGame();
}
public int generateNext() {
Random r = new Random();
int n = r.nextInt(7);
return n;
}
public void startGame() {
// while (!areaOfGame.GameOver()) {
// areaOfGame.startGame(generateNext());
// }
areaOfGame.startGame(generateNext());
}
public static void main(String[] args) {
new BbbTest();
}
class AreaOfGame extends JPanel {
private static final int rightside = 370;
private int bottom;
private int top;
private int currentPos;
private int currentver;
private KeyLis listener;
public AreaOfGame() {
super();
bottom = 650;
top = 50;
setLayout(null);
setBounds(20, 50, 350, 600);
setVisible(true);
this.setBackground(Color.lightGray);
listener = new KeyLis();
this.setFocusable(true);
if (this.requestFocus(true))
System.out.println("true");
;
this.addKeyListener(listener);
currentPos = 150;
currentver = 0;
}
public void startGame(int n) {
// while (verticallyInBound()) {
// System.out.println("anything");
// }
int timeDelay = 50; // msecs delay
new Timer(timeDelay , new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
System.out.println("anything");
}
}).start();
}
public boolean verticallyInBound() {
if (currentPos <= bottom - 50)
return true;
return false;
}
public boolean GameOver() {
if (top >= bottom) {
System.out.println("game over");
return true;
}
else
return false;
}
public boolean horizontalyInBounds() {
if (currentPos <= rightside && currentPos >= 20)
return true;
else
return false;
}
class KeyLis implements KeyListener {
#Override
public void keyPressed(KeyEvent e) {
System.out.println("called");
currentver += 5;
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT:
if (horizontalyInBounds())
currentPos -= 5;
break;
case KeyEvent.VK_RIGHT:
if (horizontalyInBounds())
currentPos += 5;
break;
}
repaint();
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent e) {
System.out.println("called 3");
}
}
}
}
It's possible to use the "TAB" button to switch between the buttons and the key listener.
I have a program with one button that after I press it, the key listener does not work.
I realized that if you press the "TAB" button, the "Attention" or "focus" of the program returns to the key listener.
maybe this will help: http://docstore.mik.ua/orelly/java-ent/jfc/ch03_08.htm
Related
I am trying to make elements of an array to be displayed in different locations with random time periods (with fade in and fade out effect).
What i ve done so far, made an array of text labels. Made transitions. But i can't figure out, how to create a for loop that will display other labels in different locations on JFrame. And they should not appear all at the same time but one after another.
Please, help out?
Here is my code:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class FadingLabel {
private int alpha = 255;
private int increment = -5;
public JLabel label = new JLabel("Fading Label");
public JLabel label2 = new JLabel("Fading Label 2");
public JLabel label3 = new JLabel("Fading Label 3");
public JLabel label4 = new JLabel("Fading Label 4");
JLabel labels[] = new JLabel[]{ label, label2, label3 };
Dimension size = label.getPreferredSize();
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new FadingLabel().makeUI();
}
});
}
public void makeUI() {
new Timer(80, new ActionListener() {
public void actionPerformed(ActionEvent e) {
for (int i = 0; i <= 3; i++){
alpha += increment;
if (alpha >= 255) {
alpha = 255;
increment = -increment;
}
if (alpha <= 0) {
try {
Thread.sleep(100);
} catch (InterruptedException interruptedException) {
interruptedException.printStackTrace();
}
alpha = 0;
increment = -increment;
}
label3.setForeground(new Color(0, 0, 0, alpha));
label3.setLocation(50,60);
}
}
}).start();
JFrame frame = new JFrame();
frame.add(labels[2]);
frame.setPreferredSize(new Dimension(700,500));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Animation is hard, good animation is harder.
A stepped animation (like you've done) is not particularly efficient and can suffer from interruptions (from the OS or other parts of the system) and can be difficult to scale.
Instead, you should aim for a "duration" based animation. Where something happens over a given period of time, this way, you can more easily drop frames you can't render.
One of the difficult concepts to get around is the idea that you can't perform long running or blocking operations in the "main thread" of the GUI, but neither can you update UI from outside of the "main thread" (in Swing this is known as the Event Dispatching Thread).
So, instead, you need some way monitor each label and as it fades out, start the next label fading in. This is where a good observer pattern (AKA listener) comes in.
import java.awt.AlphaComposite;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.Duration;
import java.time.Instant;
import java.util.EventListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.border.EmptyBorder;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
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 FadableLabel[] labels = new FadableLabel[]{
new FadableLabel("A long time ago"),
new FadableLabel("in a galaxy far, far, away..."),
new FadableLabel("It is a period of civil war."),
new FadableLabel("Rebel spaceships striking from a hidden base,"),
new FadableLabel("have won their first victory against the evil Galactic Empire"),
new FadableLabel("During the battle,"),
new FadableLabel("Rebel spies managed to steal secret plans to the Empire's ultimate weapon,"),
new FadableLabel("the Death Star")
};
private int labelIndex = -1;
public TestPane() {
setBorder(new EmptyBorder(50, 50, 50, 50));
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
for (FadableLabel label : labels) {
label.setAlpha(0);
add(label, gbc);
}
}
#Override
public void addNotify() {
super.addNotify();
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
nextLabel();
}
});
}
#Override
public void removeNotify() {
super.removeNotify();
}
protected void nextLabel() {
labelIndex++;
if (labelIndex >= labels.length) {
return;
}
FadableLabel label = labels[labelIndex];
label.addFadableLableListener(new FadableLableListener() {
#Override
public void didFadeLabelIn(FadableLabel label) {
Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
label.fadeOut();
}
});
timer.setRepeats(false);
timer.start();
}
#Override
public void didFadeLabelOut(FadableLabel label) {
label.removeFadableLableListener(this);
nextLabel();
}
});
label.fadeIn();
}
}
public interface FadableLableListener extends EventListener {
public void didFadeLabelIn(FadableLabel label);
public void didFadeLabelOut(FadableLabel label);
}
public class FadableLabel extends JLabel {
private float alpha = 1.0f;
private Timer fadeTimer;
private FadeRange fadeRange;
private Instant fadeStartedAt;
private Duration desiredFadeTime = Duration.ofMillis(1000);
public FadableLabel() {
super();
}
public FadableLabel(String text) {
super(text);
}
public void addFadableLableListener(FadableLableListener listener) {
listenerList.add(FadableLableListener.class, listener);
}
public void removeFadableLableListener(FadableLableListener listener) {
listenerList.remove(FadableLableListener.class, listener);
}
public float getAlpha() {
return alpha;
}
public void setAlpha(float alpha) {
this.alpha = alpha;
repaint();
}
protected void fireDidFadeOut() {
FadableLableListener[] listeners = listenerList.getListeners(FadableLableListener.class);
if (listeners.length == 0) {
return;
}
for (FadableLableListener listener : listeners) {
listener.didFadeLabelOut(this);
}
}
protected void fireDidFadeIn() {
FadableLableListener[] listeners = listenerList.getListeners(FadableLableListener.class);
if (listeners.length == 0) {
return;
}
for (FadableLableListener listener : listeners) {
listener.didFadeLabelIn(this);
}
}
protected void stopFadeTimer() {
if (fadeTimer != null) {
fadeStartedAt = null;
fadeTimer.stop();
}
}
protected void startFadeTimer() {
if (fadeRange == null) {
throw new RuntimeException("Fade range can not be null when starting animation");
}
fadeStartedAt = Instant.now();
fadeTimer = new Timer(5, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Duration runTime = Duration.between(fadeStartedAt, Instant.now());
double progress = Math.min(1d, Math.max(0d, runTime.toMillis() / (double) desiredFadeTime.toMillis()));
setAlpha(fadeRange.valueAt(progress));
if (progress >= 1.0) {
stopFadeTimer();
if (getAlpha() >= 1.0) {
fireDidFadeIn();
} else {
fireDidFadeOut();
}
}
}
});
fadeTimer.start();
}
public void fadeIn() {
stopFadeTimer();
if (alpha < 1.0) {
fadeRange = new FadeRange(alpha, 1.0f);
startFadeTimer();
}
}
public void fadeOut() {
stopFadeTimer();
if (alpha > 0.0) {
fadeRange = new FadeRange(alpha, 0);
startFadeTimer();
}
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setComposite(AlphaComposite.SrcOver.derive(alpha));
super.paintComponent(g2d);
g2d.dispose();
}
protected class FadeRange {
private float from;
private float to;
public FadeRange(float from, float to) {
this.from = from;
this.to = to;
}
public float getFrom() {
return from;
}
public float getTo() {
return to;
}
public float getDistance() {
return getTo() - getFrom();
}
public float valueAt(double progress) {
double distance = getDistance();
double value = distance * progress;
value += getFrom();
return (float) value;
}
}
}
}
Now, to your next problem. A poor approach might be to use an "absolute" or "null" layout
A better choice would be to either make use of something like GridBagLayout (and possibly EmptyLayout) and randomise the Insets of the GridBagConstraints. Alternatively, you could create your own layout manager to do the job for you
See Absolute Positioning Graphic JPanel Inside JFrame Blocked by Blank Sections and Moving JPasswordField to absolute position for some ideas
A cray example
When I say animation is "hard" and it can become complicated very fast, I'm not kidding. To that I end I wrote myself an animation library, which does all the things I keep finding myself doing.
https://github.com/RustyKnight/SuperSimpleSwingAnimationFramework
So, this is an example, based on the above library, which moves the label across a random range, while it's been faded in/out. Without the above library, this kind of work would be, a lot.
import java.awt.AlphaComposite;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.Duration;
import java.util.EventListener;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import org.kaizen.animation.Animatable;
import org.kaizen.animation.AnimatableAdapter;
import org.kaizen.animation.DefaultAnimatableDuration;
import org.kaizen.animation.curves.AnimationCurve;
import org.kaizen.animation.curves.Curves;
import org.kaizen.animation.ranges.AnimatableRange;
import org.kaizen.animation.ranges.FloatAnimatableRange;
import org.kaizen.animation.ranges.FloatRange;
import org.kaizen.animation.ranges.PointAnimatableRange;
import org.kaizen.animation.ranges.PointRange;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
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 String[] textValues = new String[] {
"A long time ago",
"in a galaxy far, far, away...",
"It is a period of civil war.",
"Rebel spaceships striking from a hidden base,",
"have won their first victory against the evil Galactic Empire",
"During the battle,",
"Rebel spies managed to steal secret plans to the Empire's ultimate weapon,",
"the Death Star"
};
private int labelIndex = -1;
// You'd need two if you wanted to do cross fades
private FadableLabel label;
private Random rnd = new Random();
// The desired duration of the animation, 1 second for fade in,
// 1 second for fade out and 1 second for delay between swicthing state
private Duration desiredDuration = Duration.ofSeconds(3);
// The desired animation curve (ease in/out)
private AnimationCurve curve = Curves.SINE_IN_OUT.getCurve();
// The movement animator
private DefaultAnimatableDuration animator;
public TestPane() {
setLayout(null);
label = new FadableLabel();
label.setAlpha(0);
add(label);
label.addFadableLableListener(new FadableLableListener() {
#Override
public void didFadeLabelIn(FadableLabel label) {
Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
label.fadeOut();
}
});
timer.setRepeats(false);
timer.start();
}
#Override
public void didFadeLabelOut(FadableLabel label) {
nextText();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 400);
}
#Override
public void addNotify() {
super.addNotify();
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
nextText();
}
});
}
#Override
public void removeNotify() {
stopAnimation();
super.removeNotify();
}
protected void stopAnimation() {
if (animator != null) {
animator.stop();
}
}
protected void nextText() {
stopAnimation();
labelIndex++;
if (labelIndex >= textValues.length) {
return;
}
String text = textValues[labelIndex];
label.setText(text);
label.setSize(label.getPreferredSize());
// Randomise the from and to locations
Point from = new Point(rnd.nextInt(getWidth() - label.getSize().width), rnd.nextInt(getHeight() - label.getSize().height));
Point to = new Point(rnd.nextInt(getWidth() - label.getSize().width), rnd.nextInt(getHeight() - label.getSize().height));
// Generate the range
PointRange range = new PointRange(from, to);
// Setup an animatable range of the PointRange
animator = new PointAnimatableRange(range, desiredDuration, curve, new AnimatableAdapter<Point>() {
#Override
public void animationChanged(AnimatableRange<Point> animatable) {
label.setLocation(animatable.getValue());
}
});
label.setLocation(from);
// Make it so
label.fadeIn();
animator.start();
}
}
public interface FadableLableListener extends EventListener {
public void didFadeLabelIn(FadableLabel label);
public void didFadeLabelOut(FadableLabel label);
}
public class FadableLabel extends JLabel {
private FloatAnimatableRange animator;
private AnimationCurve curve = Curves.SINE_IN_OUT.getCurve();
private Duration desiredDuration = Duration.ofSeconds(1);
private float alpha = 1.0f;
public FadableLabel() {
super();
}
public FadableLabel(String text) {
super(text);
}
public void addFadableLableListener(FadableLableListener listener) {
listenerList.add(FadableLableListener.class, listener);
}
public void removeFadableLableListener(FadableLableListener listener) {
listenerList.remove(FadableLableListener.class, listener);
}
public float getAlpha() {
return alpha;
}
public void setAlpha(float alpha) {
this.alpha = alpha;
repaint();
}
protected void fireDidFadeOut() {
FadableLableListener[] listeners = listenerList.getListeners(FadableLableListener.class);
if (listeners.length == 0) {
return;
}
for (FadableLableListener listener : listeners) {
listener.didFadeLabelOut(this);
}
}
protected void fireDidFadeIn() {
FadableLableListener[] listeners = listenerList.getListeners(FadableLableListener.class);
if (listeners.length == 0) {
return;
}
for (FadableLableListener listener : listeners) {
listener.didFadeLabelIn(this);
}
}
protected void stopFadeTimer() {
if (animator != null) {
animator.stop();
}
}
protected void startFadeTimer(FloatRange range, AnimationListener animationListener) {
stopFadeTimer();
animator = new FloatAnimatableRange(range, desiredDuration, curve, new AnimatableAdapter<Float>() {
#Override
public void animationChanged(AnimatableRange<Float> animatable) {
alpha = animatable.getValue();
repaint();
}
#Override
public void animationCompleted(Animatable animator) {
if (animationListener != null) {
animationListener.animationCompleted();
}
}
});
animator.start();
}
public void fadeIn() {
stopFadeTimer();
startFadeTimer(new FloatRange(alpha, 1f), new AnimationListener() {
#Override
public void animationCompleted() {
fireDidFadeIn();
}
});
}
public void fadeOut() {
stopFadeTimer();
startFadeTimer(new FloatRange(alpha, 0f), new AnimationListener() {
#Override
public void animationCompleted() {
fireDidFadeOut();
}
});
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setComposite(AlphaComposite.SrcOver.derive(alpha));
super.paintComponent(g2d);
g2d.dispose();
}
protected interface AnimationListener {
public void animationCompleted();
}
}
}
The library is based on Netbeans, it wouldn't be hard to just extract the source into some other IDE.
Swing based "perform after delay"
made up silly solution, #MadProgrammer. added Thread.sleep(ms); in removeFadeableLabelListener. it works but i believe there is much brighter and smart solution. could you show please how to use delay timer for such task?
Don't, ever, use Thread.sleep from within the Event Dispatching Thread. This is going to cause a cascade of issues which will basically make you program look like it's frozen (because, essentially, it is)
Instead, you need to become familiar with the mechanisms you have available to you via the API. You could use a SwingWorker, but a simpler solution might be to just use a non-repeating Swing Timer, which is demonstrated above.
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.Duration;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.border.EmptyBorder;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
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 {
public TestPane() {
JButton btn = new JButton("Click me");
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
btn.setText("...");
SwingHelper.after(Duration.ofSeconds(1), new Runnable() {
#Override
public void run() {
btn.setEnabled(false);
btn.setText("Don't do that");
}
});
}
});
setBorder(new EmptyBorder(10, 10, 10, 10));
setLayout(new GridBagLayout());
add(btn);
}
}
public class SwingHelper {
public static void after(Duration duration, Runnable runnable) {
Timer timer = new Timer((int)duration.toMillis(), new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
runnable.run();
}
});
timer.setRepeats(false);
timer.start();
}
}
}
I'm currently working on a schoolproject, where I have to code the game snake. Now I`m finished with the biggest part and tryed to make the game menue. I tryed to place a JButton for starting the game (startPlay). However, the button won't show up and I can't figure out why. Can someone help? Thanks in advance!!
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.*;
public class Main extends JPanel implements ActionListener, KeyListener{
public static int field[][];
public static GenerateField genField;
public static Snake snake;
public static GenerateFood food;
public static GenerateBarrier barrier;
public int difficultness;
public static int widthField;
public static int heightField;
public static TimerTask move, genBarriers;
public static Timer snakeTimer, barrierTimer;
public JButton startPlay;
public static boolean gameStarted;
public Main ()
{
startPlay = new JButton("Starte Spiel");
startPlay.setBounds(0,0,300,200);
startPlay.addActionListener(this);
add(startPlay);
difficultness = 15;
gameStarted = false;
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
widthField = 150;
heightField = 95;
genField = new GenerateField();
snake = new Snake();
food = new GenerateFood();
barrier = new GenerateBarrier();
barrierTimer = new Timer("Timer");
snakeTimer = new Timer("Timer");
genBarriers = new TimerTask() {
#Override
public void run() {
barrier.clearBarrier();
barrier.multiSpawnBarrier(difficultness);
}
};
move = new TimerTask()
{
public void run()
{
if(GenerateField.inGame)
{
snake.moveSnake();
repaint();
}
}
};
}
private static void startGame()
{
genField.generateField();
field = genField.getField();
snake.generateSnake(40, 75);
food.spawnFood();
snakeTimer.schedule(move,0,50);
barrierTimer.schedule(genBarriers, 0, 25000);
}
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setSize(1520,1000);
frame.getContentPane().add(new Main());
frame.setLocationRelativeTo(null);
frame.setBackground(Color.LIGHT_GRAY);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
#Override
public void paint(Graphics g)
{
if(gameStarted) {
for (int iy = 0; iy < heightField; iy++) {
for (int ix = 0; ix < widthField; ix++) {
//Zeichnet schwarzen Hintergrund
if (genField.field[iy][ix] == 0) {
g.setColor(Color.BLACK);
g.fillRect(ix * 10, iy * 10, 10, 10);
}
//Zeichnet die Grenze an den Rändern
if (genField.field[iy][ix] == 1) {
g.setColor(Color.red);
g.fillRect(ix * 10, iy * 10, 10, 10);
}
//Zeichnet die Schlange
if (genField.field[iy][ix] == 2) {
g.setColor(Color.green);
g.fillRect(ix * 10, iy * 10, 10, 10);
}
//Zeichnet das "Futter"
if (genField.field[iy][ix] == 3) {
g.setColor(Color.orange);
g.fillRect(ix * 10, iy * 10, 10, 10);
}
//Zeichte die Hindernisse
if (genField.field[iy][ix] == 4) {
g.setColor(Color.blue);
g.fillRect(ix * 10, iy * 10, 10, 10);
}
}
}
}
}
#Override
public void actionPerformed(ActionEvent e)
{
startPlay.setVisible(false);
startGame();
gameStarted = true;
}
#Override
public void keyPressed (KeyEvent e)
{
int code = e.getKeyCode();
if ( code == KeyEvent.VK_LEFT)
{
if (snake.mRight == false)
{
snake.mLeft = true;
snake.mRight = false;
snake.mUp = false;
snake.mDown = false;
}
}
if ( code == KeyEvent.VK_RIGHT)
{
if (snake.mLeft == false)
{
snake.mLeft = false;
snake.mRight = true;
snake.mUp = false;
snake.mDown = false;
}
}
if ( code == KeyEvent.VK_UP)
{
if (snake.mDown == false)
{
snake.mLeft = false;
snake.mRight = false;
snake.mUp = true;
snake.mDown = false;
}
}
if ( code == KeyEvent.VK_DOWN)
{
if (snake.mUp == false)
{
snake.mLeft = false;
snake.mRight = false;
snake.mUp = false;
snake.mDown = true;
}
}
}
#Override
public void keyReleased(KeyEvent e)
{
}
#Override
public void keyTyped(KeyEvent e)
{
}
}
Immediate Problem
The over use of static highlights issues with your design. static is not your friend, you should use it sparingly and wisely.
You're trying to put all your eggs in single basket. This is just going to make the state management harder to handle.
Instead, start by separating your menu and game into separate classes and managing them independently of each other.
This then allows you to use a CardLayout to manage the navigation between the different views.
The following is simple example to demonstrate how you might use CardLayout to perform decoupled navigation
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
CardLayout cardLayout = new CardLayout();
JPanel base = new JPanel(cardLayout);
NavigationController controller = new NavigationController() {
#Override
public void show(Screen screen) {
cardLayout.show(base, screen.name());
}
};
base.add(new MainMenuPane(controller), Screen.MENU.name());
base.add(new GamePane(controller), Screen.GAME.name());
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(base);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public enum Screen {
MENU, GAME;
}
public interface NavigationController {
public void show(Screen scren);
}
public class MainMenuPane extends JPanel {
public MainMenuPane(NavigationController controller) {
setLayout(new GridBagLayout());
JButton start = new JButton("Start");
add(start);
start.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
controller.show(Screen.GAME);
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
public class GamePane extends JPanel {
private NavigationController controller;
public GamePane(NavigationController controller) {
this.controller = controller;
setLayout(new GridBagLayout());
add(new JLabel("Ready Player One"));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}
Every thing else you'll need to fix
Don't use KeyListener, use Key bindings instead, they will fix the focus related issues in a more reliable way
You're violating the requirements of the paint chain, which is part of your immediate problem - See Performing Custom Painting and Painting in Swing for more details about how painting works and how you should work with it
Swing is single thread AND not thread safe - see Concurrency in Swing for more details. Essentially the use of java.util.Timer is running the risk of dirty read/writes which could lead to any number of weird and near impossible to diagnose issues. Instead, you should be using Swing Timer instead, which will ensure that any updates you make are made within the context of the Event Dispatching Thread. You should also be using a single Timer and scheduling everything in a simple update pass - this will generally improve performance
I'm writing a simple program in Java which includes a KeyListener with the following overriding they KeyTyped method:
#Override
public void keyTyped(KeyEvent e)
{
int key = e.getKeyCode();
System.out.println("TEST");
if (key == KeyEvent.VK_KP_LEFT || key == KeyEvent.VK_LEFT)
{
System.out.println("LEFT");
//Call some function
}
else if (key == KeyEvent.VK_KP_RIGHT || key == KeyEvent.VK_RIGHT)
{
System.out.println("RIGHT");
//Call some function
}
}
When I type anything other than the arrow keys (e.g. "a"), it prints TEST as it should. However, when I type a numpad arrowkey, it only prints TEST and when I type a standard arrow key it doesn't print anything at all. Is this possibly because I'm on a laptop, or have I just made a silly mistake somewhere?
Yep, you'll see the arrow keys respond to keyPressed and keyReleased, not keyTyped. My SSCCE:
import java.awt.Dimension;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class ArrowTest extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
public ArrowTest() {
setFocusable(true);
requestFocusInWindow();
addKeyListener(new KeyAdapter() {
#Override
public void keyTyped(KeyEvent e) {
myKeyEvt(e, "keyTyped");
}
#Override
public void keyReleased(KeyEvent e) {
myKeyEvt(e, "keyReleased");
}
#Override
public void keyPressed(KeyEvent e) {
myKeyEvt(e, "keyPressed");
}
private void myKeyEvt(KeyEvent e, String text) {
int key = e.getKeyCode();
System.out.println("TEST");
if (key == KeyEvent.VK_KP_LEFT || key == KeyEvent.VK_LEFT)
{
System.out.println(text + " LEFT");
//Call some function
}
else if (key == KeyEvent.VK_KP_RIGHT || key == KeyEvent.VK_RIGHT)
{
System.out.println(text + " RIGHT");
//Call some function
}
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
ArrowTest mainPanel = new ArrowTest();
JFrame frame = new JFrame("ArrowTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
So to solve this, override keyPressed rather than keyTyped if you want to listen to arrow events.
Or for an even better solution: use Key Bindings
Edit
My Key Bindings version:
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class ArrowTest extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
public ArrowTest() {
ActionMap actionMap = getActionMap();
int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = getInputMap(condition);
for (Direction direction : Direction.values()) {
inputMap.put(direction.getKeyStroke(), direction.getText());
actionMap.put(direction.getText(), new MyArrowBinding(direction.getText()));
}
}
private class MyArrowBinding extends AbstractAction {
public MyArrowBinding(String text) {
super(text);
putValue(ACTION_COMMAND_KEY, text);
}
#Override
public void actionPerformed(ActionEvent e) {
String actionCommand = e.getActionCommand();
System.out.println("Key Binding: " + actionCommand);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
ArrowTest mainPanel = new ArrowTest();
JFrame frame = new JFrame("ArrowTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
enum Direction {
UP("Up", KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0)),
DOWN("Down", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0)),
LEFT("Left", KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0)),
RIGHT("Right", KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0));
Direction(String text, KeyStroke keyStroke) {
this.text = text;
this.keyStroke = keyStroke;
}
private String text;
private KeyStroke keyStroke;
public String getText() {
return text;
}
public KeyStroke getKeyStroke() {
return keyStroke;
}
#Override
public String toString() {
return text;
}
}
I have just written a program in Netbeans that moves/copies/deletes files, and I wanted to give it a "diagnostic mode" where information about selected files, folders, variables, etc is displayed in a Text Area. Now, I could set this to only be visible when the "diagnostic mode" toggle is selected, but I think it would look awesome if the text area started behind the program, and "slid" out from behind the JFrame when the button is toggled. Is there any way to do this?
Thanks!
-Sean
Here is some starter code for you. This will right-slide a panel
of just about any content type. Tweak as necessary. Add error
checking and exception handling.
Tester:
static public void main(final String[] args) throws Exception {
SwingUtilities.invokeAndWait(new Runnable() {
#Override
public void run() {
final JPanel slider = new JPanel();
slider.setLayout(new FlowLayout());
slider.setBackground(Color.RED);
slider.add(new JButton("test"));
slider.add(new JButton("test"));
slider.add(new JTree());
slider.add(new JButton("test"));
slider.add(new JButton("test"));
final CpfJFrame42 cpfJFrame42 = new CpfJFrame42(slider, 250, 250);
cpfJFrame42.slide(CpfJFrame42.CLOSE);
cpfJFrame42.setSize(300, 300);
cpfJFrame42.setLocationRelativeTo(null);
cpfJFrame42.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
cpfJFrame42.setVisible(true);
}
});
}
Use GAP & MIN to adjust spacing from JFrame and closed size.
The impl is a little long...it uses a fixed slide speed but
that's one the tweaks you can make ( fixed FPS is better ).
package com.java42.example.code;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.FlowLayout;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.KeyAdapter;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseMotionAdapter;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
public class CpfJFrame42 extends JFrame {
public static int GAP = 5;
public static int MIN = 1;
public static final int OPEN = 0x01;
public static final int CLOSE = 0x02;
private JDialog jWindow = null;
private final JPanel basePanel;
private final int w;
private final int h;
private final Object lock = new Object();
private final boolean useSlideButton = true;
private boolean isSlideInProgress = false;
private final JPanel glassPane;
{
glassPane = new JPanel();
glassPane.setOpaque(false);
glassPane.addMouseListener(new MouseAdapter() {
});
glassPane.addMouseMotionListener(new MouseMotionAdapter() {
});
glassPane.addKeyListener(new KeyAdapter() {
});
}
public CpfJFrame42(final Component component, final int w, final int h) {
this.w = w;
this.h = h;
component.setSize(w, h);
addComponentListener(new ComponentListener() {
#Override
public void componentShown(final ComponentEvent e) {
}
#Override
public void componentResized(final ComponentEvent e) {
locateSlider(jWindow);
}
#Override
public void componentMoved(final ComponentEvent e) {
locateSlider(jWindow);
}
#Override
public void componentHidden(final ComponentEvent e) {
}
});
jWindow = new JDialog(this) {
#Override
public void doLayout() {
if (isSlideInProgress) {
}
else {
super.doLayout();
}
}
};
jWindow.setModal(false);
jWindow.setUndecorated(true);
jWindow.setSize(component.getWidth(), component.getHeight());
jWindow.getContentPane().add(component);
locateSlider(jWindow);
jWindow.setVisible(true);
if (useSlideButton) {
basePanel = new JPanel();
basePanel.setLayout(new BorderLayout());
final JPanel statusPanel = new JPanel();
basePanel.add(statusPanel, BorderLayout.SOUTH);
statusPanel.add(new JButton("Open") {
private static final long serialVersionUID = 9204819004142223529L;
{
setMargin(new Insets(0, 0, 0, 0));
}
{
addActionListener(new ActionListener() {
#Override
public void actionPerformed(final ActionEvent e) {
slide(OPEN);
}
});
}
});
statusPanel.add(new JButton("Close") {
{
setMargin(new Insets(0, 0, 0, 0));
}
private static final long serialVersionUID = 9204819004142223529L;
{
addActionListener(new ActionListener() {
#Override
public void actionPerformed(final ActionEvent e) {
slide(CLOSE);
}
});
}
});
{
//final BufferedImage bufferedImage = ImageFactory.getInstance().createTestImage(200, false);
//final ImageIcon icon = new ImageIcon(bufferedImage);
//basePanel.add(new JButton(icon), BorderLayout.CENTER);
}
getContentPane().add(basePanel);
}
}
private void locateSlider(final JDialog jWindow) {
if (jWindow != null) {
final int x = getLocation().x + getWidth() + GAP;
final int y = getLocation().y + 10;
jWindow.setLocation(x, y);
}
}
private void enableUserInput() {
getGlassPane().setVisible(false);
}
private void disableUserInput() {
setGlassPane(glassPane);
}
public void slide(final int slideType) {
if (!isSlideInProgress) {
isSlideInProgress = true;
final Thread t0 = new Thread(new Runnable() {
#Override
public void run() {
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
disableUserInput();
slide(true, slideType);
enableUserInput();
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
isSlideInProgress = false;
}
});
t0.setDaemon(true);
t0.start();
}
else {
Toolkit.getDefaultToolkit().beep();
}
}
private void slide(final boolean useLoop, final int slideType) {
synchronized (lock) {
for (int x = 0; x < w; x += 25) {
if (slideType == OPEN) {
jWindow.setSize(x, h);
}
else {
jWindow.setSize(getWidth() - x, h);
}
jWindow.repaint();
try {
Thread.sleep(42);
} catch (final Exception e) {
e.printStackTrace();
}
}
if (slideType == OPEN) {
jWindow.setSize(w, h);
}
else {
jWindow.setSize(MIN, h);
}
jWindow.repaint();
}
}
}
I'm writing a simple program in Java which includes a KeyListener with the following overriding they KeyTyped method:
#Override
public void keyTyped(KeyEvent e)
{
int key = e.getKeyCode();
System.out.println("TEST");
if (key == KeyEvent.VK_KP_LEFT || key == KeyEvent.VK_LEFT)
{
System.out.println("LEFT");
//Call some function
}
else if (key == KeyEvent.VK_KP_RIGHT || key == KeyEvent.VK_RIGHT)
{
System.out.println("RIGHT");
//Call some function
}
}
When I type anything other than the arrow keys (e.g. "a"), it prints TEST as it should. However, when I type a numpad arrowkey, it only prints TEST and when I type a standard arrow key it doesn't print anything at all. Is this possibly because I'm on a laptop, or have I just made a silly mistake somewhere?
Yep, you'll see the arrow keys respond to keyPressed and keyReleased, not keyTyped. My SSCCE:
import java.awt.Dimension;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class ArrowTest extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
public ArrowTest() {
setFocusable(true);
requestFocusInWindow();
addKeyListener(new KeyAdapter() {
#Override
public void keyTyped(KeyEvent e) {
myKeyEvt(e, "keyTyped");
}
#Override
public void keyReleased(KeyEvent e) {
myKeyEvt(e, "keyReleased");
}
#Override
public void keyPressed(KeyEvent e) {
myKeyEvt(e, "keyPressed");
}
private void myKeyEvt(KeyEvent e, String text) {
int key = e.getKeyCode();
System.out.println("TEST");
if (key == KeyEvent.VK_KP_LEFT || key == KeyEvent.VK_LEFT)
{
System.out.println(text + " LEFT");
//Call some function
}
else if (key == KeyEvent.VK_KP_RIGHT || key == KeyEvent.VK_RIGHT)
{
System.out.println(text + " RIGHT");
//Call some function
}
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
ArrowTest mainPanel = new ArrowTest();
JFrame frame = new JFrame("ArrowTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
So to solve this, override keyPressed rather than keyTyped if you want to listen to arrow events.
Or for an even better solution: use Key Bindings
Edit
My Key Bindings version:
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class ArrowTest extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
public ArrowTest() {
ActionMap actionMap = getActionMap();
int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = getInputMap(condition);
for (Direction direction : Direction.values()) {
inputMap.put(direction.getKeyStroke(), direction.getText());
actionMap.put(direction.getText(), new MyArrowBinding(direction.getText()));
}
}
private class MyArrowBinding extends AbstractAction {
public MyArrowBinding(String text) {
super(text);
putValue(ACTION_COMMAND_KEY, text);
}
#Override
public void actionPerformed(ActionEvent e) {
String actionCommand = e.getActionCommand();
System.out.println("Key Binding: " + actionCommand);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
ArrowTest mainPanel = new ArrowTest();
JFrame frame = new JFrame("ArrowTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
enum Direction {
UP("Up", KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0)),
DOWN("Down", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0)),
LEFT("Left", KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0)),
RIGHT("Right", KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0));
Direction(String text, KeyStroke keyStroke) {
this.text = text;
this.keyStroke = keyStroke;
}
private String text;
private KeyStroke keyStroke;
public String getText() {
return text;
}
public KeyStroke getKeyStroke() {
return keyStroke;
}
#Override
public String toString() {
return text;
}
}