How to Stop Repeated Keypressed()/Keyreleased() Events in Swing

How to stop repeated keyPressed() / keyReleased() events in Swing

So the problem that I am having
appears to be a bug that occurs only
on Linux

Yes this is a Linux problem.

On Windows when a key is held down you get multiple KeyPressed events but only a single KeyReleased event.

This question is asked often and I've never seen a good solution.

But I think the basis of a solution is to use a Timer. When the key is pressed you start a Timer. When you get another keyPressed you restart the Timer. So as long as the Timer interval is greater than the repeat rate of the key board the Timer will be continually reset when a key is held down. When keyPresses stop being generated the Timer will fire so you assume the key has been released. This implies you will have a delay in processing the keyReleased.

Disabling key repeat in Swing

Replace your boolean array with HashSet<Integer> or TreeSet<Integer>. The key repeat is a function of the OS, so there is no way to disable it, only account for it.

In Java game, pressing one key cancels a different key that's still pressed

You should wrap the keys.

Create keys[] and if a key pressed change the keys[] don't activate the events like movement:

void keyPressed(){
if(key==KeyEvent.VK_something)keys[something]=true;
}
void keyReleased(){
if(key==KeyEvent.VK_something)keys[something]=false;
}

and inside your loop, when you update the game logic, check for key events:

if(keys[up] == true)moveUp();
if(keys[right] == true)rotateRight();

That way both rotate and move will be active at the same time, without cancelling each other.

KeyPressed event is called multiple times

I found out the reason for it. I have declared the jTextField as static.

I had it like this:

public static JTextField tPatientName= new JTextField();

After removing the static keyword it worked.

But, why static keyword do this?

Java KeyListener - Key Released Firing When Key is Held Down

The KeyEvents are registered natively. System-by-system that will change. Windows and Macs use a 'repeater delay', it resends the keyPressed event every n milliseconds based off of the repeater amount. Ubuntu bypasses this and just resends a new event instead of resending the same one.

It should have little-to-no effect on your program, depending on what happens when released.

MouseEntered and KeyPressed at Same Time Java Swing

Suggestions that might surprise you:

  • Surprise number 1: Don't use a MouseListener
  • Surprise number 2: Don't use a MouseMotionListener.
  • Surprise number 3: Don't use KeyListeners.
  • Instead use Key Bindings (tutorial here: Key Bindings Tutorial). I suggest that you bind the delete key press on the JPanel that holds your grid of JLabel. Then when the delete key has been pressed, find out which JLabel the cursor is over (if any) by using the MouseInfo class to get a PointerInfo instance, and with that get the location of the cursor on the screen. With that information and some trivial math, it should be easy for you to figure out which label has the cursor (again, if any), and do your appropriate action. Note that the Key Bindings tutorial will tell you why its better to use these rather than KeyListeners, but most importantly, you don't have to futz so much with the application's focus.

Edit
For example:

import java.awt.Component;
import java.awt.GridLayout;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

import javax.swing.*;

@SuppressWarnings("serial")
public class BindingExample extends JPanel {
private static final int ROWS = 10;
private static final int COLS = 8;
JLabel[][] labels = new JLabel[ROWS][COLS];

public BindingExample() {
setLayout(new GridLayout(ROWS, COLS));
for (int r = 0; r < labels.length; r++) {
for (int c = 0; c < labels[r].length; c++) {
String labelText = String.format("[%d, %d]", r, c);
labels[r][c] = new JLabel(labelText, SwingConstants.CENTER);
int eb = 4;
labels[r][c].setBorder(BorderFactory.createEmptyBorder(eb, eb, eb, eb));
add(labels[r][c]);
}
}

int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = getInputMap(condition);
ActionMap actionMap = getActionMap();

KeyStroke delKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0);
String delete = "delete";

inputMap.put(delKeyStroke, delete);
actionMap.put(delete, new DeleteAction());
}

private class DeleteAction extends AbstractAction {
@Override
public void actionPerformed(ActionEvent evt) {
PointerInfo pInfo = MouseInfo.getPointerInfo();
Point ptOnScrn = pInfo.getLocation();
int xPanel = getLocationOnScreen().x;
int yPanel = getLocationOnScreen().y;
int x = ptOnScrn.x - xPanel;
int y = ptOnScrn.y - yPanel;

Component component = getComponentAt(x, y);
if (component != null) {
JLabel selectedLabel = (JLabel) component;
System.out.println("Selected Label: " + selectedLabel.getText());
}
}
}

private static void createAndShowGui() {
BindingExample mainPanel = new BindingExample();

JFrame frame = new JFrame("Key Bindings Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_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

Shoot, just saw the comments to your question, and yeah, a JList would probably be much better for your purposes.



Related Topics



Leave a reply



Submit