I'm a beginner in Java programming & I am making an application requiring an object to move around a grid filled with squares.
The object should only move one square at a time and if the user wants to move into another square, they must press the key again. My move method is the following:
public void move() {
x += dx;
y += dy;
}
I am using the KeyListener interface to implement the keyPressed, keyTyped and keyReleased methods and I have conditions like the one in the fragment below inside KeyPressed
//KeyPressed
int c = e.getKeyCode();
if (c == KeyEvent.VK_UP) {
player.setDy(-5);
}
This allows the object to move freely. However, it will clearly continue to move as long as the UP arrow is pressed.
Is there any way to have to object move up by say -5 once and then stop even if the key is still pressed?
I am unsure whether I need to change my move method or the KeyListener methods to do this.
I hope that I have been clear enough as to what I'm asking and I'd highly appreciate any pointers.
first of all : you should use Synchronization if you call class-methods from within listeners like keyPressed or keyReleased - thats because your listener-method can be called from multiple threads so your class-method (player.setDy()) can (and will) be called in parallel - you will need to make sure that each call to setDy happens before the next one.
Also : keyTyped is much better in many cases : https://stackoverflow.com/a/7071810/351861
An example could look like this:
public void keyTyped(KeyEvent arg0) {
if(arg0.getKeyCode() == KeyEvent.VK_UP)
{
synchronized(player)
{
player.setDy(-5);
}
}
}
this will call setDy sequentially and reliably. Now all you need to do is to make sure that setDy works as intended, hence sets the position only once
easiest would be to add a boolean to indicate, that a moving key is pressed
class member : boolean movingKeyPressed = false
in key pressed :
if (movingKeyPressed) {
return;
} else {
// do stuff
movingKeyPressed = true;
}
in key released method :
movingKeyPressed = false;
Related
I have 62 check boxes on 2 different panels.
30 of them on each panel are for selecting PC names while 1 on each selects all.
So on each of those 60 that are just selecting items I have this code:
private void HP04ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
setComponent(HP04, blrS,all_blr);
HP04 is the name of a checkbox for one of the PCs, blrS is the name of an int that counts how many checkboxes are selected(there is another int for the boxes on the other panel), all_blr is the name of the checkbox that selects all on the blr panel.
This is the method I used:
public void setComponent(javax.swing.JCheckBox component, int room,javax.swing.JCheckBox all)
{
System.out.println("Inside Component: "+component.isSelected()); //testing to see if the method is actually being called
if (component.isSelected()){ //if checkbox is checked
room++; //records how many boxes are checked
if (room == 30)
{
all.setSelected(true);//autochecks "all" check box if all PCs are selected
}
if (!messagearea.getText().equals(""))
{
sendb.setEnabled(true);//if any boxes are checked and the message area is populated, enable the button
}
}
else
{
room--;//records how many boxes are checked
all.setSelected(false);//unchecks the "all" check box if not all of them are checked
if (room == 0)
{
sendb.setEnabled(false);//disables button if no PCs are selected to be messaged
}
}
System.out.println(room); //testing int updates based on UI changes
}
Now the problem is room is only fetching the value of whatever variable is put in that parameter and then room itself is being modified. So in the example setComponent(HP04, blrS,all_blr); blrS is never changed.
I know the code inside the method works, it worked before I decided to cut down on code by using a method, as before I had the code inside the method in the actionperformed for every checkbox before hand... Like this:
private void HP04ActionPerformed(java.awt.event.ActionEvent evt) {
if (HP04.isSelected()){
blrS++;
if (blrS == 30)
{
all_blr.setSelected(true);
}
if (!messagearea.getText().equals(""))
{
sendb.setEnabled(true);
}
}
else
{
blrS--;
all_blr.setSelected(false);
if (blrS == 0)
{
sendb.setEnabled(false);
}
}
System.out.println(blrS);
}
It's just understanding how parameters and methods works that is tripping me up.
It feels obvious that what I'm doing shouldn't work, room is a variable inside the method... But how do I change that?
Solution found:
"Why not return room from the method, and assign it to the variable when you call it? blrS = setComponent(HP04, blrS, all_blr);"
– Rob Spoor (in the comments to this post)
Alright, I'll say in advance I'm aware this isn't a new concept... But no matter what I research nothing seems to work. Basically, I want to be able to sense every key on my keyboard including the different shift/ctrl/alt/enter keys. Every key besides these returns a unique keyCode which is good, but I can't seem to distinguish these duplicates.
Without any modifications, the void keyPressed () will work just fine. I'm told that to distinguish the duplicate keys I can import java.awt.event.KeyEvent; and then use
void keyPressed (KeyEvent e) {
if (keyCode == SHIFT) {
int location = e.getKeyLocation ();
if (location == KEY_LOCATION_RIGHT) {
RShift = true;
}
if (location == KEY_LOCATION_LEFT) {
LShift = true;
}
}
}
However, some problems arise with this:
If I import the library, keyPressed () never gets called at all.
If I import the library but take out the KeyEvent parameter in keyPressed () it works as long as I comment out any reference to the nonexistent KeyEvent e.
If I DON'T import it and leave the parameter it just complains that getKeyLocation () doesn't exist, but that's it.
Do I need like a reverse override or something?? Help is much appreciated!
P.S. Another related question, how can I distinguish more than left, center, and right mouse buttons? I can get these and the scrollwheel but any other button just returns a mouseButton code of 0. Suggestions? Thanks!
https://processing.org/reference/keyPressed_.html
The keyPressed() function is called once every time a key is pressed. The key that was pressed is stored in the key variable.
if you want to override keyPressed you must use the same signature so no parameters, in the method you can reference the key variable of the PApplet
like this i believe
void keyPressed ()
**int location = key
edit: int location = keyEvent
In Java, I have checked the list of Virtual Key Codes, and there is not a VK for '<'. I have tried "VK_LESS" with my program (which sounds like it could be '<'), but that did not work either.
I am wondering if I have to check to see if the Shift key is pressed down, and then check to see if the Comma key is also pressed down, but I am not sure how to do that in a KeyHandler class, using a switch statement for the keyPressed method.
The KeyHandler keyPressed method will receive a KeyEvent. You can call isShiftDown() on that KeyEvent to see if the shift key is currently pressed.
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_COMMA && e.isShiftDown()) {
// do your thing!
}
}
You could also try doing:
public void keyTyped(KeyEvent e) {
if (e.getKeyChar() == '<') {
...
}
}
Note the use of keyTyped rather than keyPressed. keyTyped triggers only when a key press outputs a character, rather than on every key press. This method would be more likely to work for other types of keyboard. But I haven't tried it, so I don't know if it would work at all.
I believe you'd want to use VK_LESS and VK_GREATER for "<" and ">", respectively.
You can use KeyEvents.getKeyChar() method
public void keyPressed(KeyEvent e) {
if (evt.getKeyChar().equals("<")) {
/*your code*/
}
}
I am trying to attach an UndoableEditListener to a JTextPane or JTextArea that queues up edits into an UndoManager.
textPane.getDocument().addUndoableEditListener(new UndoableEditListener() {
#Override
public void undoableEditHappened(UndoableEditEvent event) {
undoQueue.addEdit(event.getEdit());
}
});
But undoableEditHappened is never called when I type "aaa" in the text window.
Thinking it's Java's fault, not mine, I crack AbstractDocument.class open with Eclipse debugger to watch the event trigger. It has a private listeners array. AbstractDocument stores all its listeners in odd indices in the listeners array, with the listeners' type Class<>'s in the even indices.
protected void fireUndoableEditUpdate(UndoableEditEvent e) {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == UndoableEditListener.class) {
// Lazily create the event:
// if (e == null)
// e = new ListSelectionEvent(this, firstIndex, lastIndex);
((UndoableEditListener) listeners[i + 1]).undoableEditHappened(e);
}
}
}
See the line if (listeners[i] == UndoableEditListener.class)? When I add the undo change listener, the debugger shows listeners containing my listener, along with UndoableEditListener.class in the index before it. But, when the debugger comes to that if-statement, all the even indices in the array listeners show as DocumentListener.class in the debugger. Consequently, the if-statement is always false and the listener never called.
What the heck? Is this a Java 8 bug? Or am I missing a step the examples forgot to mention?
The problem was in the JTextPane. I was overriding its setText method to force it to call read, the alternative to setText that normalizes all kinds of newline while remembering them. But JTextPane.read appears to not trigger an UndoableEditEvent on the document.
If I leave setText alone, then UndoManager.undo works.
How can I know when the key typed change my text? Or if the key is a char?
The interface KeyListener contain three methods:
void keyTyped(KeyEvent)
void keyPressed(KeyEvent)
void keyReleased(KeyEvent)
So, if you get the char in the KeyEvent object like:
if ("a".equals(KeyEvent.getKeyChar()))
System.out.println("It's a letter")
i guess you want to know wether typing a specific key actually prints a char or is some "invisible" control character or something:
in this case you can check the typed key in the KeyEvent which gets passed into the implemented methods of the KeyListener:
this quick example should work, although i didnt test it. It constructs a new String on the char returned by the KeyEvent, than invokes the length() method to chekc if the char created a readable character in the String. kinda hacky but i hope you get the gist of it
public void keyReleased(KeyEvent ke){
if (new String(ke.getKeyChar()).length() == 0){
// do something important...
}
}
alternativley you can use ke.getKeyCode() and check vs the static fields in KeyEvent (VK_F12,VK_ENTER...)
check here:
http://docs.oracle.com/javase/6/docs/api/java/awt/event/KeyEvent.html
You need a document listener. See the oracle docs for more information: How to Write a Document Listener