Custom keyboard shortcut in java - java

I am developing a java swing application. I want to add a keyboard shortcut say CTRL + H. This should perform the same action performed by jButton1 when clicked.
This shortcut should behave in the same way even when jButton1 is not focused.
I tried with KeyEventDispatcher, but it doesn't seem to be working for me. Is there any other way?

Ok - First I don't think there is a way to set application wide shortcuts in Java Swing(Refer this question). But for a component it is possible.
You have to use a create an Action for the KeyStroke. But for Windows I found this library very helpful.
{
KeyStroke cancelKeyStroke = KeyStroke
.getKeyStroke((char) KeyEvent.VK_ESCAPE);
Keymap map = JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP);
map.addActionForKeyStroke(cancelKeyStroke, cancelKeyAction);
}
private static Action cancelKeyAction = new AbstractAction() {
public void actionPerformed(ActionEvent ae) {
Component comp = (Component) ae.getSource();
Window window = SwingUtilities.windowForComponent(comp);
if (window instanceof Dialog) {
window.dispose();
} else if (comp instanceof JTextComponent
&& !(comp instanceof JFormattedTextField)) {
JTextComponent tc = (JTextComponent) comp;
int end = tc.getSelectionEnd();
if (tc.getSelectionStart() != end) {
tc.setCaretPosition(end);
}
}
}
};

I think the answer to your question can be found here http://docs.oracle.com/javase/6/docs/api/javax/swing/JComponent.html#registerKeyboardAction%28java.awt.event.ActionListener,%20java.lang.String,%20javax.swing.KeyStroke,%20int%29

You should look into Key Bindings, using classes KeyStroke and InputMap. From Oracle's TextComponentDemo (slightly modified, but still using DefaultEditorKit as example):
// CTRL + H
KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_H, Event.CTRL_MASK);
// bind the keystroke to an object
inputMap.put(key, DefaultEditorKit.backwardAction);
Use them over Key Listeners when you want the event fired even when the component doesn't have the focus:
Key listeners are also difficult if the key binding is to be active when the component doesn't have focus.

Instead of using the Control key explicitly as a modifier, use the MASK returned by getMenuShortcutKeyMask() for a better cross-platform user experience. ImageAppis an example.

Related

Remove Enter key binding in JTable

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...

GWT work with widgets and events

I m working with GWT 2.4 on an new application. I made a docklayoutpanel and I inserted a celllist on the west section of it. I need to create an event, every time a user clicks on an element of celllist on the west side of page a specific widget will load at the content of the docklayoutpanel.
Any suggestions?
Thank you
The following example should be self explanatory
// Create a cell to render each value.
TextCell textCell = new TextCell();
// Create a CellList that uses the cell.
CellList<String> cellList = new CellList<String>(textCell);
cellList.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.ENABLED);
// Add a selection model to handle user selection.
final SingleSelectionModel<String> selectionModel = new SingleSelectionModel<String>();
cellList.setSelectionModel(selectionModel);
selectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
public void onSelectionChange(SelectionChangeEvent event) {
String selected = selectionModel.getSelectedObject();
if (selected != null) {
Window.alert("You selected: " + selected);
}
}
});
Instead of Window.alert("You selected: " + selected); you will need to change the widget shown on the eastern side of your panel.
This can be done in several ways, one of which is to expose the Dockpanel to the Selection Change Event either by declaring the Panel as a field to the class (not a local Variable in the constructor of the class) or as a final local variable in the constructor.
Another way is to do this by event handling. The eventBus methodology on the MVP design pattern is the proper way to do all thesee here for more information.

Using Key Bindings to move Images

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

Key Bindings Fire Multiple Times when Holding Key

I'm following this guide to get key binding to work in my application. So far, the key bindings fire successfully, when I press a key. What I expect to happen is when I bind one action to a key pressed event and another action to a key released event, it will fire the first action when the key is pressed down and the second action when the key is released. What actually happens when I hold down a key is both actions get called multiple times. What can I do to achieve my desired behavior?
Here's how I'm implementing the key bindings:
component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("pressed UP"), "pressedUP");
component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released UP"), "releasedUP");
Action pressedUpAction = new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
System.out.println("Pressed UP");
}
};
Action releasedUpAction = new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
System.out.println("Released UP");
}
};
component.getActionMap().put("pressedUP", pressedUpAction);
component.getActionMap().put("releasedUP", releasedUpAction);
When I run the program, the output I actually get when I hold down the up key is Pressed UP, a slight pause, and then multiple Pressed UP values. When I release the up key, I get a Released UP message. The entire output looks like this:
Pressed UP
Pressed UP
Pressed UP
Pressed UP
Pressed UP
Pressed UP
Pressed UP
Released UP
The really weird thing is if I replace UP with a keyboard letter key, such as P, everything works as I expect it to.
use Boolean value inside Swing Action when once times fired events then change Boolean from false to true or vice versa
I'm sorry nobody knows how did you implemented KeyBindings, post an SSCCE

Which button of JSpinner has been pressed?

Is it possible to know , from inside a ChangeListener receiving a ChangeEvent from a JSpinner,
which button (increment/decrement) has been pressed?
Short answer : No there's no way to know which button was pressed
Long answer : depending on your model and your change listener, if you do a comparison between the new value and the previous value, it is possible to know if the user went forward or backward.
You can inspect the object firing the event. Perhaps save the value prior to the event and determine whether it went up or down during the event.
Compare the actual value to the previous one. Here is how:
ChangeEvent ce = ...
((JSpinner)ce.getSource()).getPreviousValue();
You can check the new value against the old value by storing the old value:
int currentValue = spinner.getValue();
spinner.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent e) {
int value = spinner.getValue();
if(value > currentValue) {
// up was pressed
} else if(value < currentValue) {
// down was pressed
}
currentValue = value;
}
});
JSpinner is a composite component, it's possible to add mouseListeners to the components it contains. You'd have to experiment a bit to work out how to distinguish the buttons from one another and from the text field. One quick and dirty way would be to check their coordinates.
I'm not sure if you want to iterate over the components contained by the JSpinner itself, or those contained by the container returned by JSpinner.getEditor(), so try both.

Categories