How can I trigger backspace key press event when button click.
private void doClick(char type)
{
jTextField1.dispatchEvent(new KeyEvent(jTextField1, KeyEvent.KEY_PRESSED, System.currentTimeMillis(),KeyEvent.SHIFT_DOWN_MASK, KeyEvent.VK_7, type));
jTextField1.dispatchEvent(new KeyEvent(jTextField1, KeyEvent.KEY_TYPED, System.currentTimeMillis(),KeyEvent.SHIFT_DOWN_MASK, KeyEvent.VK_UNDEFINED, type));
jTextField1.dispatchEvent(new KeyEvent(jTextField1, KeyEvent.KEY_RELEASED, System.currentTimeMillis(),KeyEvent.SHIFT_DOWN_MASK, KeyEvent.VK_7, type));
}
Im using this method to add one character when button click. Is there any mechanism to trigger backspace key press event like this.
Okay, before I answer the question, because I believe the approach is dirty, here are two, similar, concepts...
You could make use of the Action API, which would allow you to define self-contained units for work. These could be abstract to do the heavy lifting, in the particular case of inserting new values, but this demonstrates the use case of removing a character...
public class BackspaceAction extends AbstractAction {
private JTextField field;
public BackspaceAction(JTextField field) {
putValue(NAME, "Back-space");
this.field = field;
}
#Override
public void actionPerformed(ActionEvent e) {
String text = field.getText();
if (!text.isEmpty()) {
int position = field.getCaretPosition();
if (position > 0) {
text = text.substring(0, position - 1) + text.substring(position);
field.setText(text);
field.setCaretPosition(Math.max(position - 1, 0));
}
}
}
}
Or through use the Document itself...
public class BackspaceAction extends AbstractAction {
private JTextField field;
public BackspaceAction(JTextField field) {
putValue(NAME, "Back-space");
this.field = field;
}
#Override
public void actionPerformed(ActionEvent e) {
Document doc = field.getDocument();
if (doc.getLength() > 0) {
int position = field.getCaretPosition();
if (position > 0) {
try {
doc.remove(position - 1, 1);
field.setCaretPosition(Math.max(position - 1, 0));
} catch (BadLocationException ex) {
ex.printStackTrace();
}
}
}
}
}
Which would simply instantiated using something like...
JButton back = new JButton(new BackspaceAction(field));
If you're hell bent on trying to get into the nitty gritty low layers of the API, then something like....
char value = (char)8;
field.dispatchEvent(new KeyEvent(field, KeyEvent.KEY_PRESSED, System.currentTimeMillis(), 0, KeyEvent.VK_BACK_SPACE, value));
field.dispatchEvent(new KeyEvent(field, KeyEvent.KEY_RELEASED, System.currentTimeMillis(), 0, KeyEvent.VK_BACK_SPACE, value));
field.dispatchEvent(new KeyEvent(field, KeyEvent.KEY_TYPED, System.currentTimeMillis(), 0, KeyEvent.VK_UNDEFINED, value));
might work. I say might, as this does work on Windows 7, but I make no guarantee if it will work on any other platforms or versions of Windows
Now, for me, I can look at the other two Actions and see what they are trying to do, I look at the key event approach and begin to scratch my head wondering why, but that's just me...
All Swing components have default Actions to perform this type of functionality. You may want to consider using the default "backspace Action" to do this.
If so then check out the ActionMapAction class is a simple wrapper class that will allow you to easily use the default Action for the component by creating the Action for you. For example the code would be:
JTextField textField = new JTextField();
Action backSpace = new ActionMapAction("Backspace", textField, "delete-previous");
backSpace.putValue(AbstractAction.MNEMONIC_KEY, KeyEvent.VK_B);
JButton backSpaceButton = new JButton(backSpace);
You can use the Action with JButtons, JMenuItems. Make use of reusable code to leverage existing Actions of the Swing components.
Related
I'm using the StyledEditorKit in a project I'm working on. I've used the StyledEditorKit.BoldAction(), and the StyledEditorKit.ItalicAction(). Now I want to use the StyledEditorKit.UnderlineAction() as well.
I make the JButtons that they'll be used in:
JButton bold = new JButton(new StyledEditorKit.BoldAction());
tool.add(bold);
JButton italic = new JButton(new StyledEditorKit.ItalicAction());
tool.add(italic);
JButton underline = new JButton(new StyledEditorKit.UnderlineAction());
tool.add(underline);
They each have their own use where I setText(null) and assign an Icon to the button. Then when I try to use these buttons in an AbstractAction:
Action Bold = new AbstractAction("Bold", new ImageIcon("bold.png"))
{
public void actionPerformed(ActionEvent e)
{
if(bolded == false)
{
area.setFont(area.getFont().deriveFont(Font.BOLD));
bolded = true;
}
else
{
area.setFont(area.getFont().deriveFont(Font.PLAIN));
bolded = false;
}
}
};
Action Italic = new AbstractAction("Italic", new ImageIcon("italic.png"))
{
public void actionPerformed(ActionEvent e)
{
if(italiced == false)
{
area.setFont(area.getFont().deriveFont(Font.ITALIC));
italiced = true;
}
else
{
area.setFont(area.getFont().deriveFont(Font.PLAIN));
italiced = false;
}
}
};
Action underline = new AbstractAction("underline", new ImageIcon("underline.png"))
{
public void actionPerformed(ActionEvent e)
{
if(underlined == false)
{
area.setFont(area.getFont().deriveFont(Font.UNDERLINE));
underline = true;
}
else
{
area.setFont(area.getFont().deriveFont(Font.PLAIN));
underline = false;
}
}
};
The first two AbstractActions work fine. The final one where I use
area.setFont(area.getFont().deriveFont(Font.UNDERLINE);
is not correct however. I have yet to find the actual implementation on oracle (am I looking in the wrong place maybe?), but I figure it is just how I am using 'UNDERLINE' that is incorrect. Simple answer I know. Any help is appreciated.
I figured it out. Yeah that second half of code is completely unnecessary.
The StyledEditorKit that was called in the creation of the button was all I needed to get it working. When I was trying to implement that second AbstractAction, something was going on that wasn't happening in the other 2 AbstractActions (for what ever reason).
I was under the impression I still needed to create another bold action in order to bold the text, but Java handles all of that automatically with the StyledEditorKit.
I'm very new to coding(2 months) and i attempted to make Tic-Tac-Toe in java. I'm in a little over my head but i managed to create it using swing. My main problem is in the button1 class. I was going to use the getText() method but ended up not needing it or so i thought. I tried deleting it but as it turns out my tictactoe buttons don't switch letters without it. The compiler told me it overrides AbstractButton's getText() method but i don't see why that should matter since i never actually used it i thought. I'm thinking it's maybe a scope issue handled by it being overwritten somehow but i'm not sure. I was trying to use the text variable to update the button with setText() and that doesn't seem to work like i thought it should. I also don't understand why the 3 by 3 gridlayout seems to work properly most of the time but sometimes the number of buttons added is wrong.
So in summation the program works(mostly) but i'm not fully understanding how the button1 class is working.
TicTacToe.java
import java.awt.*;
import java.util.*;
import javax.swing.*;
public class TicTacToe extends JFrame {
public static void main(String[] args) {
JFrame window = new JFrame("Tic-Tac-Toe");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
window.setSize(600, 600);
window.setLayout(new GridLayout(3, 3));
ArrayList<button1> buttonArrayList = new ArrayList<>(9);
for (int i = 0; i < 9; i++) {
button1 newbutton = new button1();
buttonArrayList.add(newbutton);
window.add(buttonArrayList.get(i));
}
}
}
button1.java
import java.awt.*;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
public class button1 extends JButton {
int value = 0;
String text = "";
public button1() {
class ButtonAction extends AbstractAction {
public ButtonAction() {}
#Override
public void actionPerformed(ActionEvent Switcher) {
System.out.println(text + " " + value);
value++;//value is a relic from earlier attempts that i just felt like keeping.
if (text.equals("O")) {
text = "X";
} else if (text.equals("X")) {
text = "";
} else if (text.equals("")) {
text = "O";
}
}
}
this.setAction(new ButtonAction());
this.setText(text);
this.setFont(new Font("Arial",Font.PLAIN,120));
}
public String getText()// <----culprit
{
return text;
}
}
A JButton class has a methods defined for it, including setText() (which will set the displayed text on the button) and getText() (which will return the current text that is displayed on the button).
You created a class button1 (note: classes should start with Capital Letters).
You added an Action to the button1 class, which means that when the action is activated, something happens. Note that in that actionPerformed method, you should call setText(text) to update the displayed value.
You have also defined a getText() method that overrides the getText() method defined in JButton. This approach is fine if it is a conscious design decision. As it is, I think you should remove the getText() method from the button1 class, and allow the standard JButton class to handle the update. Right now, you are attempting to keep an instance variable text with the value, but it is possible for that instance variable to not be in alignment with the actual displayed value of the button (consider another class calling .setText() on the button).
EDIT: It is true that this referring to the JButton in the ButtonAction is not available. However, the Action itself contains the button that was pressed.
#Override
public void actionPerformed(ActionEvent e)
{
JButton btn = (JButton)e.getSource();
// if desired, String cur = btn.getText() may be called to find the
// current setting; get and process if needed
btn.setText(WHAT_EVER_TEXT);
}
Unless it is a specific requirement to process the current text, however (allowing selecting an O to an X to a blank), I would implement something to keep track of the current turn. This code is something I was experimenting with, and has good and bad points to it (as it is illustrative):
static class TurnController
{
// whose turn it is; start with X
private Player whoseTurn = Player.X;
// the instance variable
private static final TurnController instance = new TurnController();
private TurnController()
{
}
public static Player currentTurn()
{
return instance.whoseTurn;
}
public static Player nextTurn()
{
switch (instance.whoseTurn) {
case X:
instance.whoseTurn = Player.O;
break;
case O:
instance.whoseTurn = Player.X;
break;
}
return instance.whoseTurn;
}
public static String getMarkerAndAdvance()
{
String marker = currentTurn().toString();
nextTurn();
return marker;
}
enum Player
{
X,
O,
;
}
}
Using this TurnController, the actionPerformed becomes:
#Override
public void actionPerformed(ActionEvent e)
{
JButton btn = (JButton)e.getSource();
btn.setText(TurnController.getMarkerAndAdvance());
}
and the Button1 class may have the String text instance variable removed.
What you have tried is Try to make a Custom Button Class and its EventHandler just by extending AbstractAction namee button1 as we See in Your Question.
You have Override the method actionPerformed(ActionEvent Switcher) which actually belongs to Class AbstractAction by your own definition (What should Performed on Action Event of Every Button).
class ButtonAction extends AbstractAction {
public ButtonAction() {}
#Override
public void actionPerformed(ActionEvent Switcher) { // Your Definition For actionPerformed..
System.out.println(text + " " + value);
value++;//value is a relic from earlier attempts that i just felt like keeping.
if (text.equals("O")) {
text = "X";
} else if (text.equals("X")) {
text = "";
} else if (text.equals("")) {
text = "O";
}
}
}
this.setAction(new ButtonAction()); // add ActionListener to each Button.
this.setText(text); // Setting Text to each Button
this.setFont(new Font("Arial",Font.PLAIN,120)); //add Font to each Button.
}
Now In this Code.
ArrayList buttonArrayList = new ArrayList<>();
for (int i = 0; i < 9; i++) {
button1 newbutton = new button1(); // Creating 9 new buttons.
buttonArrayList.add(newbutton); // add each button into the ArrayList.
window.add(buttonArrayList.get(i)); // each Button to the the AWT Window.
}
Above Code will generate 9 Button and add it to Your AWT Window. each button have actionPerformed() method which contains the overrided Definition.
Now Each button will performed action as per the definition you give to actionPerformed() Method.
Thank You.
I'm looking for a way to pass fields with enter key in VerticalLayout or others. In vaadin book there an example with Shortcut and Handler listeners but I don't know how to implement that.
I'm trying this.
public class MyWindow extends Window implements Handler{
private Action action_enter; //pass fields with enter
private Action action_esc;
private TextField name, lastName;
public MyWindow(){
super("this window is opened");
VerticalLayout vLayout = new VerticalLayout();
setContent(vLayout);
center();
setModal(true);
setClosable(false);
setDraggable(false);
setResizable(false);
//actions
action_enter = new ShortcutAction("Enter key", ShortcutAction.KeyCode.ENTER, null);
action_esc = new ShortcutAction("Esc key", ShortcutAction.KeyCode.ESCAPE, null);
addActionHandler(this);
//fields
name = new TextField("Name");
lastName = new TextField("Last name");
name.focus();
vLayout.addComponent(name);
vLayout.addComponent(lastName);
}
#Override
public Action[] getActions(Object target, Object sender) {
return new Action[] { action_enter, action_esc };
}
#Override
public void handleAction(Action action, Object sender, Object target) {
/** close window with esc key */
if(action == action_esc){
close();
}
/** pass fields with enter key */
if(action == action_enter){
//here pass fields with enter key
}
}
}
any idea ?
try this way with ShortcutListener:
ShortcutListener skEnterListener = new ShortcutListener("Enter", ShortcutAction.KeyCode.ENTER, null){
#Override
public void handleAction(Object sender, Object target) {
if (target instanceof VerticalLayout) { // VerticalLayout or other
// sending fileds here
}
}
};
addShortcutListener(skEnterListener);
change focus of TextField using Enter instead Tab:
final TextField tf1 = new TextField("tf1");
tf1.setId("tf1");
final TextField tf2 = new TextField("tf2");
tf2.setId("tf2");
ShortcutListener skEnterListener = new ShortcutListener("Enter", ShortcutAction.KeyCode.ENTER, null){
#Override
public void handleAction(Object sender, Object target) {
if (target instanceof TextField) {
TextField field = (TextField) target;
if ("tf1".equals(field.getId())) {
tf2.focus();
}
if ("tf2".equals(field.getId())) {
tf1.focus();
}
}
}
};
addShortcutListener(skEnterListener);
There is no interface which does provide an accessor that would allow you finding out the currently focused component. Focus information can be acquired for some (but not all) field components through the com.vaadin.event.FieldEvents.FocusListener and com.vaadin.event.FieldEvents.BlurListener interfaces.
You could add for all possible fields a FocusListener and remember every time it's invoked, the current field in a variable. (Problem: not all fields provide a FocusListener.) Then when ENTER is pressed focus the next component according to the current focused field (remember the variable) that has to be focused (with the help of a simple List, LinkedList, Map, switch-case and so forth). To make it even better add a BlurListener as well to know when not to focus the next field.
Hope that helps.
I am trying to get a group of JRadioButtons to be navigable using the arrow keys. I was going to implement this manually with KeyListeners, but apparently this behavior is already supposed to work for at least the last 8 years (http://bugs.sun.com/view_bug.do?bug_id=4104452). However, it's not working for me: pressing the arrow keys does nothing. Java version is 7u45 on Windows.
A standalone test case to see what I'm talking about:
import java.awt.*;
import javax.swing.*;
public class Test {
public static void main(final String[] args) {
if (!EventQueue.isDispatchThread()) {
try {
EventQueue.invokeAndWait(new Runnable() {
public void run() {
main(args);
}
});
} catch (Exception e) {
throw new RuntimeException(e);
}
return;
}
try {
//UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
//UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (Throwable t) {
throw new RuntimeException(t);
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ButtonGroup group = new ButtonGroup();
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
JRadioButton rb;
rb = new JRadioButton("Option A");
panel.add(rb);
group.add(rb);
rb = new JRadioButton("Option B");
panel.add(rb);
group.add(rb);
rb = new JRadioButton("Option C");
panel.add(rb);
group.add(rb);
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
}
I have tried using different look & feels, different containers, and different layout managers, but it still does not work.
You need to add the right/left (up/down?) keys to the focus traversal policy of each radio button. For example to add the right/left arrow keys:
Set set = new HashSet( rb.getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS ) );
set.add( KeyStroke.getKeyStroke( "RIGHT" ) );
rb.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, set );
set = new HashSet( rb.getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS ) );
set.add( KeyStroke.getKeyStroke( "LEFT" ) );
rb.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, set );
Read the section from the Swing tutorial on How to Use the Focus Subsystem for more information.
I believe you can achieve your goal using KeyBindings instead of KeyListeners. In many cases bindings are actually recommended over KeyListeners, as the second ones can generate many problems (frame catching the key activity must be active one etc.)
Thank you everyone for the answers.
I discovered the reason for my confusion. Apparently, when the Sun bug report system says that a bug's status is "Closed" and its "Resolved Date" is "2005-07-19", that doesn't mean the bug is fixed at all. Apparently, it's just logged as a duplicate of some other (newer?) bug. Nearly 16 years since it was first reported it still isn't fixed. Whatever.
The needed behavior is much more subtle than I realized. I experimented in native Windows dialogs in various programs:
Most button-like components: buttons, checkboxes, and radio buttons, implement the arrow keys for focus navigation. In Java this corresponds to the AbstractButton class. (JMenuItem is also a subclass of that, but that has its own distinct arrow key behavior.)
Only radio buttons get selected/checked during this navigation.
Unfocusable (including disabled or invisible) components must be skipped.
Attempting to navigate before the first button in a group or after the last one is inconsistent: on some dialogs it loops from end to end; on others it moves irreversibly onto non-button components; and on yet others it does nothing. I experimented with all these different behaviors and none of them was particularly better than the others.
I implemented a looping behavior below as it felt slightly more fluent. The navigation silently skips past non-AbstractButton components, forming a sort-of separate focus cycle private to buttons. This is dubious but sometimes needed when a set of related checkboxes or radio buttons are mixed with other components. Testing for a common parent component to identify groups would also be a reasonable behavior, but that didn't work in one dialog where I'd used separate components purely for layout reasons (to implement a line break in a FlowLayout).
As suggested I studied up on InputMaps and ActionMaps instead of using a KeyListener. I've always avoided the maps as they seem overcomplicated but I guess I see the advantage of being able to easily override the binding.
This code uses an auxialiary look and feel to install the desired behavior for all AbstractButton components application-wide (which is a nice technique I found out about here). I've tested it with several different dialog boxes and windows and it seems to be okay. If it causes issues I'll update this post.
Call:
ButtonArrowKeyNavigation.install();
once at application startup to install it.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ButtonArrowKeyNavigation {
private ButtonArrowKeyNavigation() {}
public static void install() {
UIManager.addAuxiliaryLookAndFeel(lookAndFeel);
}
private static final LookAndFeel lookAndFeel = new LookAndFeel() {
private final UIDefaults defaults = new UIDefaults() {
#Override
public javax.swing.plaf.ComponentUI getUI(JComponent c) {
if (c instanceof AbstractButton && !(c instanceof JMenuItem)) {
if (c.getClientProperty(this) == null) {
c.putClientProperty(this, Boolean.TRUE);
configure(c);
}
}
return null;
}
};
#Override public UIDefaults getDefaults() { return defaults; };
#Override public String getID() { return "ButtonArrowKeyNavigation"; }
#Override public String getName() { return getID(); }
#Override public String getDescription() { return getID(); }
#Override public boolean isNativeLookAndFeel() { return false; }
#Override public boolean isSupportedLookAndFeel() { return true; }
};
private static void configure(JComponent c) {
InputMap im = c.getInputMap(JComponent.WHEN_FOCUSED);
ActionMap am = c.getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "focusPreviousButton");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "focusPreviousButton");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "focusNextButton");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "focusNextButton");
am.put("focusPreviousButton", focusPreviousButton);
am.put("focusNextButton", focusNextButton);
}
private static final Action focusPreviousButton = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
move((AbstractButton)e.getSource(), -1);
}
};
private static final Action focusNextButton = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
move((AbstractButton)e.getSource(), +1);
}
};
private static void move(AbstractButton ab, int direction) {
Container focusRoot = ab.getFocusCycleRootAncestor();
FocusTraversalPolicy focusPolicy = focusRoot.getFocusTraversalPolicy();
Component toFocus = ab, loop = null;
for (;;) {
toFocus = direction > 0
? focusPolicy.getComponentAfter(focusRoot, toFocus)
: focusPolicy.getComponentBefore(focusRoot, toFocus);
if (toFocus instanceof AbstractButton) break;
if (toFocus == null) return;
// infinite loop protection; should not be necessary, but just in
// case all buttons are somehow unfocusable at the moment this
// method is called:
if (loop == null) loop = toFocus; else if (loop == toFocus) return;
}
if (toFocus.requestFocusInWindow()) {
if (toFocus instanceof JRadioButton) {
((JRadioButton)toFocus).setSelected(true);
}
}
}
}
Here is my example of JRadioButtons can be navigable using the arrow keys(UP and Down) and modified few codes for you.
public class JRadioButton extends JPanel {
private JRadioButton[] buttons;
public JRadioButtonTest(int row) {
ButtonGroup group = new ButtonGroup();
buttons = new JRadioButton[row];
for (int i = 0; i < buttons.length; i++) {
final int curRow = i;
buttons[i] = new JRadioButton("Option " + i);
buttons[i].addKeyListener(enter);
buttons[i].addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_UP:
if (curRow > 0)
buttons[curRow - 1].requestFocus();
break;
case KeyEvent.VK_DOWN:
if (curRow < buttons.length - 1)
buttons[curRow + 1].requestFocus();
break;
default:
break;
}
}
});
group.add(buttons[i]);
add(buttons[i]);
}
}
private KeyListener enter = new KeyAdapter() {
#Override
public void keyTyped(KeyEvent e) {
if (e.getKeyChar() == KeyEvent.VK_ENTER) {
((JButton) e.getComponent()).doClick();
}
}
};
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JRadioButton(3));
frame.pack();
frame.setVisible(true);
}
}
The core implement method is calling requestFocus() on the correct JRadioButton when an arrow key is called. Extra KeyListener for when the Enter key is pressed.
You can use this KeyListener to your program and add more key.
Good luck!
I have created a key binding for a JTextArea Component. When invoked, it creates a new instance of itself and sets focus to it.
If you hold down the enter (which invokes key binding) my program will start spitting out bunch of JTextArea instances.
Is there a way to force the user to press enter againg to create a new instance?
Do I have I switch to KeyListeners or is there a way with key bindings?
You specify that a KeyStroke only fire on key release when you're setting up the input map
See KeyStroke getKeyStroke(int keyCode, int modifiers, boolean onKeyRelease)
the way to do it with keybindings is to have two actions:
an action creating the component is bound to the pressed enter, it disables itself when inserting the component
an action enabling the action again is bound to the released enter
Some code:
// the action to create the component
public static class CreateAction extends AbstractAction {
private Container parent;
private Action enableAction;
public CreateAction(Container parent) {
this.parent = parent;
enableAction = new EnableAction(this);
}
#Override
public void actionPerformed(ActionEvent e) {
setEnabled(false);
Component field = createTextField();
parent.add(field);
parent.revalidate();
field.requestFocus();
}
int count;
private Component createTextField() {
// just for fun counting the fields we create
JTextField field = new JTextField("field: " + count++, 20);
field.getInputMap().put(KeyStroke.getKeyStroke("ENTER"),
"createComponent");
field.getActionMap().put("createComponent", this);
field.getInputMap().put(KeyStroke.getKeyStroke("released ENTER"),
"enableCreation");
field.getActionMap().put("enableCreation", enableAction);
return field;
}
}
// the action that enables another
public static class EnableAction extends AbstractAction {
Action toEnable;
public EnableAction(Action toEnable) {
this.toEnable = toEnable;
}
#Override
public void actionPerformed(ActionEvent e) {
toEnable.setEnabled(true);
}
}
// usage
final JComponent parent = new JPanel(new MigLayout("wrap"));
// here I'm lazy and let the action create the very first component as well
add.actionPerformed(null);
add.setEnabled(true);
Note that the same instances of the actions are registered to all components, so it doesn't matter which has the focus (and ultimately enables the creation again)
Here is the code I use, to have an action only run when a key is first pressed down:
private void registerKeyBindings(final JFrame frame) {
var inputMap = frame.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
inputMap.put(KeyStroke.getKeyStroke(KeyCode.G.getInputEventCode(), 0, false), "g_down");
inputMap.put(KeyStroke.getKeyStroke(KeyCode.G.getInputEventCode(), 0, true), "g_up");
frame.getRootPane().getActionMap().put("g_down", new AbstractAction() {
#Override public void actionPerformed(ActionEvent e) {
if (gDown) return;
gDown = true;
// put your custom key-down-action code here
}
});
frame.getRootPane().getActionMap().put("g_up", new AbstractAction() {
#Override public void actionPerformed(ActionEvent e) {
gDown = false;
}
});
}
Boolean gDown = false;