I am trying to create a Tanks game but am still learning how to do graphics programming in Java. I had initially tried moving one of two images (which one depends on which player is going) with KeyListeners. I was told that Key Bindings might be a more effective way of going about this. Here is some of my code:
public class FrameMain extends JFrame{
...
public FrameMain(){
this.addBindings();
The addBindings() method:
protected void addBindings() {
InputMap inputMap = pnlPlay.getInputMap();
KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, Event.KEY_PRESS);
inputMap.put(key, pnlPlay.pnlGame.MoveTank(2, pnlPlay.nPlayer));
key = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, Event.KEY_PRESS);
inputMap.put(key, pnlPlay.pnlGame.MoveTank(-2, pnlPlay.nPlayer));
}
The MoveTank method:
public int MoveTank(int xChange, int nPlayer){
System.out.println("move "+nPlayer);
if(nPlayer==0){
tank1.x+=xChange;
}else tank2.x+=xChange;
repaint();
return 1;
}
The problem I'm having is that, when I press either the right or left arrow key, I am not getting any kind of response. It should be printing "move #" but it's not. If anyone knows what I have done wrong or could point me in the direction of some code that does the same thing I would appreciate it. I learn best from seeing the code in working order and then playing around with it.
Two things with this code:
I do not see anything about the action map. The input map maps a key to an action identifier, and the action map is the link between the identifier and the actual action. So you normally have code like
InputMap inputMap = component.getInputMap( );
ActionMap actionMap = component.getActionMap();
Action actionToTrigger = ...;
actionMap.put( "myAction", actionToTrigger );
inputMap.put( key, "myAction" );
If putting your action in the action map with the correct identifier and it still does not work, you might have been using the wrong input map. There are 3 different input maps as explained in the Swing keybindings guide. Try with the others
Perhaps you should consult the Swing keybindings tutorial again as it explains all this in more detail + contains code examples
Related
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
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;
What is the simplest and fastest way to remove the standard enter key bindings (pressing enter selects the next row) in a JTable?
That's what I tried
table.getInputMap().put(KeyStroke.getKeyStroke("ENTER"), null);
But it doesn't work. I assume that we have to do that somehow for each cell and not the table itself.
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT and JComponent.WHEN_IN_FOCUSED_WINDOW have a value for the enter keystroke. So you want to get both of them
Correction: You need to get the InputMap for WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
InputMap iMap1 =
table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
//InputMap iMap2 =
// table.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
Then you want to set the value for the map to "none", instead of null, as described in How to Use Key Bindings.
To make a component ignore a key that it normally responds to, you can use the special action name "none". For example, the following code makes a component ignore the F2 key.
component.getInputMap().put(KeyStroke.getKeyStroke("F2"), "none");
So just do:
KeyStroke stroke = KeyStroke.getKeyStroke("ENTER");
iMap1.put(stroke, "none");
//iMap2.put(stroke, "none");
Also note when you just do getInputMap() without any arguments, it's basically the same thing as getInputMap(JComponent.WHEN_FOCUSED). And in the case of JTable, there's no value for the enter keystroke for that InputMap.
Read more at How to Use Key Bindings. You'll get a better explanation of the different InputMaps
UPDATE : Correction (corrections made above either struck through or // commented out)
You only to set it for the InputMap for JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
UPDATE per the OP comment: Yes in short
table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
.put(KeyStroke.getKeyStroke("ENTER"), "none");
This seems to be the most convenient way:
table.registerKeyboardAction(
null,
KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0),
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
);
To assign an action replace null with ActionListener call or with e -> someMethod() for JDK 1.8
Update:
David Kroukamp solution:
private void createKeybindings(JTable table) {
table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "Enter");
table.getActionMap().put("Enter", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {}
});
}
And for you should be enough:
table.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "Enter");
table.getActionMap().put("Enter",null);
I dont know if it is possible to use null, you could use anonymous class instead...
I'm looking for a PrimeFaces 4.0 Component to provide little messages like Facebook does in the upper right corner by clicking on the earth symbol.
Any idea?
You could adapt Primefaces Notification Bar for your needs, but to be honest it rather looks like a job for this famous "do-it-yourself" component to me.
In fact, there really seemed to be no ready-to-use component. I'n experimenting with dynamic menues which seems to offer the right functionality. But I'm currently fighting with presenting it as cute as possible ... which of course is the real challenge.
In the facelet it's nothing more than
<p:menu model="#{nachrichtTeaserController.unreadMenu}"/>
and the controller looks soemthing like
...
private List<Nachricht> unread;
private MenuModel unreadMenu;
...
public void initUnread() {
unread = nachrichtFacade.findAllUnread(
personLoginController.getCurrentUser().getMandant(),
personLoginController.getCurrentUser());
unreadMenu = new DefaultMenuModel();
Integer menuItemId = 1;
for (Nachricht nachricht : unread) {
menuItemId++;
DefaultMenuItem menuItem = new DefaultMenuItem(nachricht.getTeaserText());
menuItem.setId(menuItemId.toString());
String nachrichtIdString = nachricht.getId().toString();
menuItem.setCommand("#{nachrichtTeaserController.show('" + nachrichtIdString + "')}");
//menuItem.setCommand(String.format("#{nachrichtTeaserController.show('%d')}",unread.indexOf(n)));
unreadMenu.addElement(menuItem);
}
}
...
public String show(String nachrichtIdString) {
Long nachrichtId = Long.valueOf(nachrichtIdString);
Nachricht nachricht = nachrichtFacade.find(nachrichtId);
return show(nachricht);
}
Two points:
It's important to use menuItem.setId(menuItemId.toString());
otherwise you'll get an NullPointerexception somewhere deep in
PrimeFaces ...
and please consider how to do "row selection" - I mean: It's easy
to call show() but it's necessary to get some information in
show() about which MenuItem was clicked. Unfortunately one cannot pass a reference to the nachricht so I use the primary key.
I'm having troubles making a second call to load a Google Map in a GWT app. The problem itself is that once the map is called, it won't fit the container size. This is a usual problem, as depicted in many previous SO questions:
Here
Here
Here
Here
Let me state that I've tried all of the above and sadly nothing seems to work. I must also say I'm using the unofficial version of GWT Maps API v3, which can be found here. Thus, this is the problem:
Now, weird enough, if I change the browser size, map displays correctly:
Thus, it looks like I need to "dispatch" the onResize event somehow...but I tried with all of the above methods and nothing seemed to work. Just for clarification this, is the part where I construct the map and add it to the container:
private void buildMapMarinesPark() {
//Visualizar datos...
LatLng center = LatLng.newInstance(52.62715,1.7734);
MapOptions opts = MapOptions.newInstance();
opts.setZoom(9);
opts.setCenter(center);
opts.setMapTypeId(MapTypeId.HYBRID);
MapTypeControlOptions controlOptions = MapTypeControlOptions.newInstance();
controlOptions.setMapTypeIds(MapTypeId.values()); // use all of them
controlOptions.setPosition(ControlPosition.TOP_RIGHT);
opts.setMapTypeControlOptions(controlOptions);
mapMarinePark = new MapWidget(opts);
mapMarinePark.setSize("100%", "100%");
// Add some controls for the zoom level
List<EuropeanMarineParkDataEntity> parksPerAnio = null;
listPolygon = new ArrayList<Polygon>();
Polygon poly = null;
for(int i=2003;i<=ANIO_MAP_PARK;i++){
parksPerAnio = this.hashAnioParks.get(""+i);
if(parksPerAnio != null){
for(EuropeanMarineParkDataEntity emp : parksPerAnio){
poly = this.createPolygon(emp);
poly.setMap(mapMarinePark);
listPolygon.add(poly);
}
}
}
((Element)DOM.getElementById("currentYear")).setPropertyObject("innerHTML", ""+(ANIO_MAP_PARK));
// Add the map to the HTML host page
final DockLayoutPanel dock = new DockLayoutPanel(Unit.PX);
dock.addNorth(mapMarinePark, 500);
RootPanel.get("mapContainerProfile2").add(dock);
RootPanel.get("timeline").setVisible(true);
RootPanel.get("mapPanel2").setVisible(true);
RootPanel.get("gadget_marinepark").setVisible(true);
mapMarinePark.triggerResize(); --> Does not work!
onLoadedMapMarinePark();
}
I guess you try to draw the map when the DOM hasn't been fully constructed and the wrong dimensions are retrieved.
Try to draw/create the map in a callback of a
Scheduler.get().scheduleDeferred() call.
Update:
Also you are mixing a DockLayoutPanel with a RootPanel.
That will cause issues. Use a RootLayoutPanel instead.
Construct the DOM normally and at the point where you normally add your map to the DockLayoutPanel call scheduleDeferred() and add the map to the panel in the callback