KeyPressed/KeyReleased not working? - java

I'm trying to make a game in java, just a simple platformer, but I'm having difficulty when running the code. I can't seem to get any response from key presses. The only thing I can think hasn't been working properly is the keyPressed and keyReleased functions. Below is the relevant code.
public ReflexPanel() {
initBoard();
setFocusable(true);
addKeyListener(this);
Timer timer = new Timer(1000/120, this);
timer.start();
}
private void initBoard() {
loadMenu();
int w = menu.getWidth(this);
int h = menu.getHeight(this);
setPreferredSize(new Dimension(w, h));
}
private void step() {
if(mainMenu){
if(ePressed) {
System.exit(0);
}
if(hPressed) {
loadScores();
repaint();
}
}
}
public void keyTyped(KeyEvent e) {}
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == 'e') {
ePressed = true;
}
if (e.getKeyCode() == 'h') {
hPressed = true;
}
}
#Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == 'e') {
ePressed = false;
}
if (e.getKeyCode() == 'h') {
hPressed = false;
}
}
#Override
public void actionPerformed(ActionEvent e) {
step();
}
The ePressed and hPressed variables are just booleans set to false by default, and loadScores calls a png file.

You can't do this:
if(e.getKeyCode() == 'e'){
// code logic
}
KeyEvent::getKeyCode doesn't return the char you press on the keyboard. It "returns the integer keyCode associated with the key in this event". When using KeyEvent::getKeyCode you have to use the KeyEvent key constants values predefined in the class. So for example:
if(e.getKeyCode() == KeyEvent.VK_E){
// code logic
}
Or you can use KeyEvent::getKeyChar which "returns the character associated with the key in this event".

You're using getKeyCode() which returns an int value with constants given in KeyEvent class, such as KeyEvent.VK_E.
You're looking to use getKeyChar() which returns 'e' directly.
if (e.getKeyChar() == 'e') { // Now it has an actual chance of working

Related

How to use arrow keys instead of buttonListeners?

public void setUpButtonListeners() {
ActionListener buttonListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
Object o = ae.getSource();
if ((o == slots[3][1]) || (o == slots[3][2])) {
slideDown(slots);
} else if ((o == slots[0][1]) || (o == slots[0][2])) {
slideUp(slots);
} else if ((o == slots[1][3]) || (o == slots[2][3])) {
slideRight(slots);
} else if ((o == slots[1][0]) || (o == slots[2][0])) {
slideLeft(slots);
}
}
};
slots[3][1].addActionListener(buttonListener);
slots[3][2].addActionListener(buttonListener);
slots[0][1].addActionListener(buttonListener);
slots[0][2].addActionListener(buttonListener);
slots[1][3].addActionListener(buttonListener);
slots[2][3].addActionListener(buttonListener);
slots[1][0].addActionListener(buttonListener);
slots[2][0].addActionListener(buttonListener);
}
This the relevant code. I can find a ton of information on how to add keylisteners to specific JComponents but all I want to do is make it so that if(up arrow pressed) then slideUp(slots), instead of having to press JButtons on the screen to call these functions.
Edit:
Fixed, and it was really simple.
Added
frame.setFocusable(true);
frame.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyPressed(KeyEvent e) {
keyCode = e.getKeyCode();
switch (keyCode) {
case KeyEvent.VK_UP:
slideUp(slots);
}
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
});
to constructor.
Maybe you should use a custom KeyEventDispatcher to handle the arrow key events, otherwise you will have issues with the components focus.
KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
manager.addKeyEventDispatcher( new ArrowsKeyDispatcher() );
...
class ArrowsKeyDispatcher implements KeyEventDispatcher {
public boolean dispatchKeyEvent(KeyEvent e) {
if(e.getID() == KeyEvent.VK_UP) {
//Do something here when pressing UP ARROWKEY
}
// Do the same for all keys you need to handle globally
...
return false;
}
}

How do I the KeyEvent only once when it is held down?

I am trying to shoot a missile at a certain rate but currently you can simple hold down the fire button (Space) and it will make a continuous line of missiles.
I believe this is because the KeyEvent is being triggered when you hold it down when what I need it to do is only trigger once when you hold it down.
How would I make it detect the holding down of a button as only pressing it once?
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_SPACE) {
fire();
}
if (key == KeyEvent.VK_A) {
dx = -1;
}
if (key == KeyEvent.VK_D) {
dx = 1;
}
}
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_SPACE) {
}
if (key == KeyEvent.VK_A) {
dx = 0;
}
if (key == KeyEvent.VK_D) {
dx = 0;
}
}
Just add a check to make sure you've released the key before allowing yourself to fire again. I use AtomicBoolean to ensure there are no multithreading issues by the different events getting fired.
private final AtomicBoolean canShoot = new AtomicBoolean(true);
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_SPACE) {
if (canShoot.compareAndSet(true, false)) {
fire();
}
}
// snip
}
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_SPACE) {
canShoot.set(true);
}
// snip
}

Make a KeyEvent update JLabel in Java

I'm trying to use Java's KeyListener to update a JLabel as I type. Essentially, I'm making my own text field. Here's what I have:
/**
* Constructor for objects of class Dictionary
*/
public Dictionary()
{
frame = new JFrame();
frame.setTitle("Shori Dictionary");
frame.setLayout(new GridBagLayout());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private void createWord()
{
frame.remove(pane);
pane = new PaintPane(field.getImage());
pane.setLayout(new BorderLayout());
frame.add(pane);
frame.pack();
newWord = new JLabel(text);
newWord.setFont(newWord.getFont().deriveFont(Font.BOLD, 28));
newWord.setForeground(Color.BLACK);
newWord.setHorizontalTextPosition(JLabel.LEFT);
newWord.setVerticalAlignment(JLabel.TOP);
newWord.setVerticalTextPosition(JLabel.TOP);
newWord.setBorder(BorderFactory.createEmptyBorder(445, 150, 0, 0));
pane.add(newWord);
frame.pack();
frame.setLocationRelativeTo(null);
pane.setFocusable(true);
updateInteraction();
}
private void keyPress()
{
pane.addKeyListener(new KeyListener()
{
public void keyTyped(KeyEvent e) {
for(int i = 97; i <= 122; i++){
//Cycles through every lowercase letter
if(e.getKeyChar() == (char)(i)&& pane.returnImage() == field.getImage()){
text += (char)(i);
break;
}
}
//Even in the Debugger, these next if-elses have never worked
if(e.getKeyCode() == KeyEvent.VK_SPACE&& pane.returnImage() == field.getImage()) text += " ";
else if(e.getKeyCode() == KeyEvent.VK_BACK_SPACE&& pane.returnImage() == field.getImage()){
int x = text.length();
text = text.substring(0,x-1); //Not sure if this works, haven't been able to test it yet
}
else if(e.getKeyCode() == KeyEvent.VK_ENTER&& pane.returnImage() == field.getImage()){
//do something with the text
text = "";
//exit the word creator
}
newWord.setText(text);
newWord.repaint(); //Apparently this isn't necessary...
}
public void keyPressed(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
}
);
}
private void mouseAction()
{
pane.addMouseListener(new MouseListener()
{
public void mouseClicked(MouseEvent arg0) {
//cover page
if(open.contains(arg0.getPoint())&& pane.returnImage() == cover.getImage()) displayPages();
else if(search.contains(arg0.getPoint())&& pane.returnImage() == cover.getImage()) searchWord();
else if(enter.contains(arg0.getPoint())&& pane.returnImage() == cover.getImage()) createWord();
//inner pages
else if(nextPage.contains(arg0.getPoint())&& pane.returnImage() == pages.getImage()) pageFlip("next");
else if(prevPage.contains(arg0.getPoint())&& pane.returnImage() == pages.getImage()) pageFlip("previous");
else if(cancel.contains(arg0.getPoint())&& pane.returnImage() == field.getImage()) coverPage();
frame.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
public void mouseEntered(MouseEvent arg0) {
}
public void mouseExited(MouseEvent arg0) {
}
public void mousePressed(MouseEvent arg0) {
}
public void mouseReleased(MouseEvent arg0) {
}
}
);
}
private void mouseMovement()
{
pane.addMouseMotionListener(new MouseMotionListener()
{
#Override
public void mouseMoved(MouseEvent e) {
if(search.contains(e.getPoint())&& pane.returnImage() == cover.getImage()){
frame.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
else if(enter.contains(e.getPoint())&& pane.returnImage() == cover.getImage()){
frame.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
else if(open.contains(e.getPoint())&& pane.returnImage() == cover.getImage()){
frame.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
else if(nextPage.contains(e.getPoint())&& pane.returnImage() == pages.getImage()){
frame.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
else if(prevPage.contains(e.getPoint())&& pane.returnImage() == pages.getImage()){
frame.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
else if(cancel.contains(e.getPoint())&& pane.returnImage() == field.getImage()){
frame.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
else{
frame.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}
#Override
public void mouseDragged(MouseEvent e) {
}
}
);
}
private void updateInteraction(){
mouseMovement();
mouseAction();
keyPress();
}
public class PaintPane extends JPanel {
private Image background;
private Graphics g2d;
public PaintPane(Image image) {
background = image;
}
#Override
public Dimension getPreferredSize() {
return background == null ? new Dimension(0, 0) : new Dimension(background.getWidth(this), background.getHeight(this));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (background != null) {
Insets insets = getInsets();
int width = getWidth() - 1 - (insets.left + insets.right);
int height = getHeight() - 1 - (insets.top + insets.bottom);
int x = (width - background.getWidth(this)) / 2;
int y = (height - background.getHeight(this)) / 2;
g.drawImage(background, x, y, this);
}
//g.fillRect(654, 798, 358, 77); //for testing rectangle positioning
}
public Image returnImage() {
return background;
}
}
I'm using BluJ to write this, and it has a built in Debugger. I just tried adding keyPress(); before the updateInteraction(); in createWord(), and ran the Debugger to go through each method step by step. Everything worked perfectly. Then I tried without the Debugger, and it wouldn't display any text while I was typing. So, I turned on the Debugger again. It didn't detect any keys being typed at all. I don't know why it only worked that once, but it was definitely working. This is my first time working with KeyListener, MouseListener, and MouseMotionListener. Is there a better way to get this program to run properly?
and it wouldn't display any text while I was typing
A component needs to have focus in order to respond to KeyEvents. A JPanel is not focusable by default.
I'm making my own text field
Why? What functionality is missing from JTextField?
I would just use JTextField and then add a DocumentListener to the document from the text field. Read the section from the Swing tutorial on How to Write a Document Listener for more information.
Your Component must have the focus for keyboard input on Key Event. However, to check it in action, first make your JPanle focus-able by panel.setFocusable(true). Then try with panel.requestFocusInWindow()
to get the focus to panel on application start-up.
However, in your code:
for(int i = 97; i <= 122; i++){
//Cycles through every lowercase letter
if(e.getKeyChar() == (char)(i)&& pane.returnImage() == field.getImage()){
text += (char)(i);
break;
}
}
Why do you have to use a loop here? Just simply putting:
if(evt.getKeyChar() >=97 && evt.getKeyChar() <=122 && pane.returnImage() == field.getImage())
text += evt.getKeyChar()
Should do the work.
If you are just doing a learning exercise, then it's OK to make your own implementation instead of using JTextField. You can make a JPanel receive key events by calling setFocusable(true) on it.
Even after that, you should be aware of something that will probably trip you up: keyTyped callbacks don't fill out the keyCode property of KeyEvents. This is because it's possible to type in characters that do not have a single associated key. For example, on Windows you can fire keyPressed once by typing ALT+0160. You hit 5 keys but entered one character (a space) and got a single keyPressed callback.
To summarize: keyPressed and keyReleased deliver keyCodes and might deliver keyChar. keyTyped never gets a keyCode, and always gets a keyChar.
public class PanelKeyListener extends JFrame {
private JPanel _contentPane;
StringBuilder _stringBuilder = new StringBuilder();
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
PanelKeyListener frame = new PanelKeyListener();
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public PanelKeyListener() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
_contentPane = new JPanel() {
protected void paintComponent(java.awt.Graphics g) {
g.drawString(_stringBuilder.toString(), 10, 20);
}
};
setContentPane(_contentPane);
_contentPane.setFocusable(true);
_contentPane.addKeyListener(new KeyListener() {
public void keyTyped(KeyEvent e) {
System.out.println("keyTyped char[" + e.getKeyChar()
+ "] code[" + e.getKeyCode() + "]");
_stringBuilder.append(e.getKeyChar());
_contentPane.repaint();
}
public void keyReleased(KeyEvent e) {
System.out.println("keyReleased char[" + e.getKeyChar()
+ "] code[" + e.getKeyCode() + "]");
}
public void keyPressed(KeyEvent e) {
System.out.println("keyPressed char[" + e.getKeyChar()
+ "] code[" + e.getKeyCode() + "]");
}
});
}
}
You shouldn't reinvent the wheel if you can avoid it. Use/extend JTextField if it's practical to do so and meets your needs.

KeyListener in Java

Hello everyone I am new to Java so i think the answer to this question is very easy but I can't find out what part i'm doing wrong.. I added a keyListener to my pacman game but somehow it won't work.. i've used the following code:
package h04PacMan;
import java.awt.event.*;
import javax.swing.*;
public class PacManBediening extends JPanel implements ActionListener, KeyListener {
private JButton links, rechts, boven, beneden;
PacMan pacman;
public PacManBediening(PacMan pacman) {
this.pacman = pacman;
links = new JButton("<");
links.addActionListener(this);
add(links);
rechts = new JButton(">");
rechts.addActionListener(this);
add(rechts);
boven = new JButton("^");
boven.addActionListener(this);
add(boven);
beneden = new JButton("v");
beneden.addActionListener(this);
add(beneden);
}
/*
* bediening bij een klik
*/
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == links) {
pacman.setRichtingEnSnelheid( -10 );
pacman.setBesturing(0);
pacman.setView(180);
//System.out.println("links");
}
else if(e.getSource() == rechts) {
pacman.setRichtingEnSnelheid( +10 );
pacman.setBesturing(0);
pacman.setView(0);
//System.out.println("rechts");
}
else if(e.getSource() == boven) {
pacman.setRichtingEnSnelheid( -10);
pacman.setBesturing(1);
pacman.setView(90);
//System.out.println("boven");
}
else {
pacman.setRichtingEnSnelheid( +10);
pacman.setBesturing(1);
pacman.setView(270);
//System.out.println("beneden");
}
}
#Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if(key == KeyEvent.VK_LEFT) {
pacman.setRichtingEnSnelheid( -10 );
pacman.setBesturing(0);
pacman.setView(180);
System.out.println("links");
}
else if(key == KeyEvent.VK_RIGHT) {
pacman.setRichtingEnSnelheid( +10 );
pacman.setBesturing(0);
pacman.setView(0);
System.out.println("rechts");
}
else if(key == KeyEvent.VK_UP) {
pacman.setRichtingEnSnelheid( -10);
pacman.setBesturing(1);
pacman.setView(90);
System.out.println("boven");
}
else if(key == KeyEvent.VK_DOWN) {
pacman.setRichtingEnSnelheid( +10);
pacman.setBesturing(1);
pacman.setView(270);
System.out.println("beneden");
}
}
#Override
public void keyReleased(KeyEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent arg0) {
// TODO Auto-generated method stub
}
}
can someone tell me what to add or do different?
You're missing a couple of lines in your PacManBediening constructor.
this.pacman = pacman;
this.setFocusable(true);
this.addKeyListener(this);
KeyListener isn't designated for Swing JComponents, I wouldn't going this way,
I think there is simple and possible to lost the Focus from focusable JComponents
use KeyBindings as most scallable workaround, rather that "catching or hunting for Focus" for KeyListener
for Swing JComponents are all internal short_cuts, key shortcuts, built_in methods, notifiers, based on KeyBindings
code example

Key Listener events not triggering?

I want to be able register a key pressed event that triggers a boolean variable. I've done it in my main class, but now I am trying to put it into classes, and it doesn't seem to be working.
Here is the hero class:
public class Hero extends Main {
private boolean downPressed;
private boolean leftPressed;
private boolean rightPressed;
public void init() {
}
public void paint(Graphics g, int x_pos, int y_pos) {
if (isDownPressed() && isLeftPressed()) {
this.sprite = hero225;
} else if (isDownPressed() && isRightPressed()) {
this.sprite = hero135;
} else if (isUpPressed() && isRightPressed()) {
this.sprite = hero45;
} else if (isUpPressed() && isLeftPressed()) {
this.sprite = hero315;
} else if (isLeftPressed() == true) {
this.sprite = hero270;
} else if (isRightPressed() == true) {
this.sprite = hero90;
} else if (isUpPressed() == true) {
this.sprite = hero;
System.out.println("Succsess");
} else if (isDownPressed() == true) {
this.sprite = hero180;
}
// this.sprite will contain value set on last "movement"
g.drawImage(this.sprite, x_pos, y_pos, this);
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
setLeftPressed(true);
System.out.println("keyPressed");
}
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
setRightPressed(true);
}
if (e.getKeyCode() == KeyEvent.VK_UP) {
setUpPressed(true);
}
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
setDownPressed(true);
}
}
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
setLeftPressed(false);
}
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
setRightPressed(false);
}
if (e.getKeyCode() == KeyEvent.VK_UP) {
setUpPressed(false);
}
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
setDownPressed(false);
}
}
public void keyTyped(KeyEvent e) {
}
public void mouseClicked(MouseEvent e) {
System.out.println("HIT!");
}
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
public void mousePressed(MouseEvent e) {
boolean isButtonPressed = true;
}
public void mouseReleased(MouseEvent e) {
boolean isButtonPressed = false;
}
public void setDownPressed(boolean downPressed) {
this.downPressed = downPressed;
}
public boolean isDownPressed() {
return downPressed;
}
public void setLeftPressed(boolean leftPressed) {
this.leftPressed = leftPressed;
}
public boolean isLeftPressed() {
return leftPressed;
}
public void setRightPressed(boolean rightPressed) {
this.rightPressed = rightPressed;
}
public boolean isRightPressed() {
return rightPressed;
}
public void setUpPressed(boolean upPressed) {
this.upPressed = upPressed;
}
public boolean isUpPressed() {
return upPressed;
}
And here is the level class which calls it:
public class Level extends Main {
Hero hero = new Hero();
public void paint(KeyEvent e, Graphics g, double x_pos, double x_pos2) {
repaint();
}
And here is the Paint function in the Main class which calls that:
public void paint(Graphics g) {
Level level = new Level();
level.paint(e, g, x_pos, y_pos);
The problem causing this doesn't seem to be apparent.
You should implement java.awt.event.KeyListener interface in the class(es) that you want to listen for events, in this case Hero, so:
public class Hero extends Main implements java.awt.event.KeyListener
and then register for the events in some method, maybe init or somewhere else using:
addKeyListener(this);
//rest of your code
Or if you want to listen for just some events, you could instead of implement the interface KeyListener, register an adapter:
addKeyListener(new java.awt.KeyAdapter()
{
public void keyPressed(java.awt.KeyEvent e)
{
//handle just this event
}
}
);
//rest of of your code
Sounds like a focus problem: Only the active component will get KeyEvents.
There are several ways to solve this problem, but I found this tutorial covers the ideas quite nicely. But if you want a quick and dirty (dirty? Not sure, easy and simple isn't bad I'd think; just gets a bit bloated for large projects) solution you could just implement a listener for every component and forward the events to some general class that handles it.

Categories