I have a JPanel that I need to check for the control being pressed down so that the user can select multiple things on screen, i had the issues of using a key listener so after research i found that i was supposed to use key bindings, and i finally got it to work for pressing control, but i cant get it to work for releasing control
'''
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_CONTROL,
InputEvent.CTRL_DOWN_MASK), "press");
getActionMap().put("press", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
controlPressed = true;
}
});
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.CTRL_DOWN_MASK
,InputEvent.CTRL_DOWN_MASK,true), "release");
getActionMap().put("release", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("release");
controlPressed = false;
}
});
'''
so pressing ctrl works but releasing does not, any ideas?
Update, I found what I think is the best solution for my problem, the mouse event stores weather or not control is pressed down so there was no need to do any magic with keysListeners or binding keys. here is the line of code if anyone needs it
'''
public void mousePressed(MouseEvent e){
e.isControlDown();
}
'''
Related
I need to design a game with two players. Each has a ball and should be able to move the ball to right or left, the first player with 'a' 'd' buttons and the second player with right,left arrow buttons. However currently one player needs to wait for the other player's action to be completed in order to move their own ball. How can i resolve that problem? Here is the related parts of my code:
public class AnimationWindow extends JPanel{
public AnimationWindow()
{
super();
....
....
cezmiMover();
}
public void cezmiMover(){
this.getInputMap().put(KeyStroke.getKeyStroke('a'), "left1");
this.getActionMap().put("left1", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
board.cezmi1.moveLeft();
}
});
this.getInputMap().put(KeyStroke.getKeyStroke('d'), "right1");
this.getActionMap().put("right1", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
board.cezmi1.moveRight();
}
});
this.getInputMap().put(KeyStroke.getKeyStroke("LEFT"), "left2");
this.getActionMap().put("left2", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
board.cezmi2.moveLeft();
}
});
this.getInputMap().put(KeyStroke.getKeyStroke("RIGHT"), "right2");
this.getActionMap().put("right2", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
board.cezmi2.moveRight();
}
});
}
}
You need to use a series of flags and some kind of "update" loop to update the state of the game depending on the state of the flags...
For example, start by creating a series of flags...
private boolean p1Left, p1Right, p2Left, p2Right = false;
These could just as easily be maintained by the individual player objects, but you've not provided that much code...
Next, you need to monitor for key press and key release events and set the state of the flag as required...
this.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, false), "right1down");
this.getActionMap().put("right1down", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
p1Right = true;
}
});
this.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, true), "right1up");
this.getActionMap().put("right1up", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
p1Right = false;
}
});
Then you need some kind loop or timer that can update the state of the game. Personally, I like using javax.swing.Timer, but that's just me.
On each run of the update loop, you need to check the state of each flag and update the objects accordingly...
if (p1Right) {
board.cezmi1.moveRight();
}
For example
Check out Motion Using the Keyboard. The KeyboardAnimation.java code contains a complete working example that demonstrates one way to do this.
Each instance of the KeyboardAnimation class:
animates a component (JLabel) using a Timer
the animation is controlled by assigned KeyStrokes
a Map tracks the KeyStrokes that have been pressed to it handles multiple KeyStrokes at the same time
Having tried KeyEvents it was recommended that I switch to Key Bindings to activate certain events by the pushing of the arrow keys while one is in a TextArea
area.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
.put(KeyStroke.getKeyStroke("VK_UP"),
"doEnterAction");
area.getActionMap().put("doEnterAction", new AbstractAction(){
#Override
public void actionPerformed(ActionEvent e){
System.out.println("Event Handled");
oneRay[pick][0] = ("");
if(i>=4){
i=0;
area.setText("");
}
caller();
}
});
area.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
.put(KeyStroke.getKeyStroke("VK_DOWN"),
"doEnterAction");
area.getActionMap().put("doEnterAction", new AbstractAction(){
#Override
public void actionPerformed(ActionEvent e){
System.out.println("Event 2 Handled");
area.append("\n"+oneRay[pick][1]);
buton1.setEnabled(true);
buton2.setEnabled(true);
}
});
area.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
.put(KeyStroke.getKeyStroke("VK_RIGHT"),
"doEnterAction");
area.getActionMap().put("doEnterAction", new AbstractAction(){
#Override
public void actionPerformed(ActionEvent e){
if(i>=4){
i=0;
area.setText("");
}
caller();
}
This code covers three different Key Bindings, but none work, whether I press up down left right the cursor just moves in that direction in the TextArea.
What have I done wrong this time. Please help me!
whether I press up down left right the cursor just moves in that direction in the TextArea.
You are building the KeyStroke incorrectly. You should not be including the "VK_" in the Keystroke. So basically nothing is being added to the InputMap.
Also your code is updating the InputMap and ActionMap with a new identifier. I find is easier to just replace the Action in the ActionMap. See Key Bindings for a list of all the default Actions as well as the basic code for replacing the default Action (this is a different link than you got in your last posting).
Finally, in your other posting you suggested that you want to invoke the Action of a button. Well then your code should be creating an Action that can be used by the button and the Key Bindings. You create an Action the same way you create an ActionListener except you extend AbstractAction instead of implementing ActionListener.
I'm using this code to bind keyboard keys to custom actions without using the KeyListener:
Action left = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("pressed left key");
}
};
Action right = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("pressed right key");
}
};
Action space = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("pressed space key");
}
};
myJPanel.getInputMap().put(KeyStroke.getKeyStroke("LEFT"), "pressedLeft");
myJPanel.getInputMap().put(KeyStroke.getKeyStroke("A"), "pressedLeft");
myJPanel.getActionMap().put("pressedLeft", left);
myJPanel.getInputMap().put(KeyStroke.getKeyStroke("RIGHT"), "pressedRight");
myJPanel.getInputMap().put(KeyStroke.getKeyStroke("D"), "pressedRight");
myJPanel.getActionMap().put("pressedRight", right);
myJPanel.getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "pressedSpace");
myJPanel.getActionMap().put("pressedSpace", space);
Everything works perfectly, but i noticed that when i press i.e. SPACE while holding A, the left action isn't fired anymore, it would be great if events for both pressed keys are fired.
Is there any way to use key bindings with key combinations?
See Motion Using the KeyBoard for a potential solution.
An event is only generated for the last key pressed so you need to manually keep track of any other keys that have been pressed (and keep manually simulate firing the event). This is true whether you use key bindings or a KeyListener.
I am working on a Java application and interfacing with an RFID reader that acts as a keyboard input device.
The application will be used for employee time tracking, so the employee should not see the code that his/her RFID tag contains.
Currently, the application opens a jFrame that asks the employee to scan their tag. This is where I would like to listen for the keyboard input.
All of the RFID tags are 10 digits, so I would like to use some kind of regex to detect when a card is scanned if possible.
If someone could point me in the right direction, or contribute some code I would be grateful.
Thanks in advance.
UPDATE:
I was able to read the input of the scanner by adding the following to the constructor of my JFrame.
addKeyListener(new KeyListener(){
#Override
public void keyPressed(KeyEvent e){ System.out.print(e.getKeyChar());}
#Override
public void keyReleased(KeyEvent e) { }
#Override
public void keyTyped(KeyEvent e) { }
});
So it is now confirmed that the Reader is just standard Keyboard input.
Here is an example of what I get for a tag: 0006459027
Now, the big question is, how do I take the characters that I got, and detect that it is a 10 digit string, and from there trigger an event to open a new frame?
First, I'd see if the RFID reader is triggering an ActionEvent to be fired when the tag is scanned. This would be the simplest approach.
Failing that, you would need to attach a DocumentListener to the fields underlying document and monitor for changes.
You'll need to decide how best to interrupt the results (as you're likely to get each letter of the RFID at a time). You could monitor the length of the document or have a javax.swing.Timer which triggers after a short delay (you'd reset the timer on each update event triggered by the DocumentListener)
Check out
JTextField.addActionListener
JTextField.getDocument().addDocumentListener
I'd suggest taking a look at DocumentFilter as well, but your interested in the final result, not modifying it.
UPDATED with DocumentListener Example
// In the classes variable decleration section...
private JTextField rfidField;
// In the classes constructor or UI init method...
rfidField = new JTextField(12);
rfidField.getDocument().addDocumentListener(new DocumentListener() {
public void handleUpdate(DocumentEvent e) {
if (e.getDocument().getLength() == 10) {
System.out.println("Trigger me happy...");
SwingUtilities.invokeLater(new Runnable() {
public void run() {
rfidField.setText(null);
}
});
}
}
#Override
public void insertUpdate(DocumentEvent e) {
handleUpdate(e);
}
#Override
public void removeUpdate(DocumentEvent e) {
handleUpdate(e);
}
#Override
public void changedUpdate(DocumentEvent e) {
handleUpdate(e);
}
});
// Now don't forget to add the field to your forms container ;)
//////
One of things I would be do when you "trigger" the code event is, once you've read it from the text field, is clear the text field (JTextField.setText(null)) - IMHO
If the RFID reader acts as a keyboard input device, try with key events:
JFrame frame = new JFrame();
// frame setup
frame.addKeyListener(new KeyAdapter(){
public void KeyPressed(KeyEvent ke)
{
System.out.println(ke);
}
});
Otherwise you have to check which kind of event it fires.
I was in a similar situation but with a bar-code scanner.
I really worked hard on a custom DocumentListener that would take care of all scenarios, and none of it worked.
Out of desperation, I added an ActionListener and it then worked very well.
Here is a code snap-shot :
try {
txtStockItemRef.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
System.out.println(txtStockItemRef.getText());
DatabaseManager.peformStockItemLookupByBarcodeRef(txtStockItemRef.getText());
}
});
} catch(Exception exc) {
LiveCityRetailTools.handleExceptionWithUserMessage(exc);
}
I've implemented right mouse click for open menu listener on my main Jframe, it works fine except one problem. One out of 5 (give or take) clicks it not responding, this can be very annoying for the user. Here is my code:
contentPane = new JPanel();
contentPane.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON3)
{
//Do Stuff
}
}
});
Can you please help me
You won't get clicks from sub-components of contentPane.
I think your problem is that you have added things to your panel. When the user clicks at regions occupied by a sub-component, that sub-component get's the click event.
Quick fix: I would recommend you to add the same mouse listener to all sub-components.
You are not "clicking"
A click is when the mouse is pressed and release really quickly. If you are not careful you might get events for (for instance) "pressed, moved, released" instead of "clicked".
Quick fix: use mouseReleased event instead.
Use this Code instead:
private MouseAdapter listener = new MouseAdapter() {
public void mouseReleased(MouseEvent e) {
if (downer) {
downer = false;
if (new Rectangle(e.getComponent().getLocationOnScreen(), e.getComponent().getSize())
.contains(e.getLocationOnScreen())) {
downer = false;
// CODE
new Thread(new Runnable(){
public void run(){
//Your Listener code
}
}).start();
/// COde
}
}
}
boolean downer = false;
public void mousePressed(java.awt.event.MouseEvent e) {
downer = true;
}
};
This code only reacts if you press on the component and release on the component AND starts a new Thread for the custom task. This should work allways, because the AWT Thread isnt blocked with long calculations.