Java Swing KeyBinding with multiple key combination - java

I want to print to the console a message when both G key and A key are pressed. This should be a pretty easy task but for some reason i cannot achieve this, and cannot find any useful example online. I tried various syntaxes to describe the keystroke i wish to use, but none worked. This is my minimal code:
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.KeyStroke;
public class TestKeyBinding extends JFrame {
public static void main(String[] args) {
new TestKeyBinding();
}
public TestKeyBinding() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
JLabel l = new JLabel();
l.getInputMap().put(KeyStroke.getKeyStroke("G A"), "ga");
l.getActionMap().put("ga", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("test ga");
}
});
l.setOpaque(true);
l.setBackground(Color.red);
frame.add(l);
frame.setVisible(true);
frame.pack();
}
});
}
}

Related

How do I add Command + Delete functionality in JTextPane [duplicate]

I have a small text editor that I made in Java Swing with JTextArea.
I want to implement the following:
When the user presses Command+Backspace I want to remove all the text from the beginning of the line up to the cursor. How to implement this? I tried using KeyListeners but it doesn't work.
For example (before user presses Command+Backspace) ...
Result (after user presses Command+Backspace) ...
My code (Not 100% exact compared to the image):
import javax.swing.*;
import javax.swing.text.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Main{
static JFrame frame = new JFrame();
static JTextArea textArea = new JTextArea();
static JScrollPane scrollPane = new JScrollPane(textArea);
public static void main(String[] args) throws BadLocationException {
frame.setTitle("Untitled");
addComponentsToFrame();
textArea.addKeyListener(new KeyListener(){
#Override
public void keyTyped(KeyEvent e) {
if(e.getKeyCode() == (Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx() | KeyEvent.VK_BACK_SPACE)){
System.out.println("Delete"); //Placeholder
}
}
#Override
public void keyPressed(KeyEvent e) {}
#Override
public void keyReleased(KeyEvent e) {}
});
}
public static void addComponentsToFrame(){
scrollPane.setAutoscrolls(true);
frame.add(scrollPane);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
For now when I have placed a print Statement as a place holder, since I don't know how to delete all the words from the beginning of the line up to the cursor (i.e. the logic).
Credits: #Abra
Solution:
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.text.BadLocationException;
import java.awt.Toolkit;
public class TestSamplePrograms {
private JTextArea textarea;
private void buildAndShowGui() {
JFrame frame = new JFrame("Untitled");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createTextArea(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JScrollPane createTextArea() {
textarea = new JTextArea(20, 60);
InputMap im = textarea.getInputMap();
KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx());
im.put(ks, "del2EoL");
ActionMap am = textarea.getActionMap();
am.put("del2EoL", new Delete2EOL());
JScrollPane pane = new JScrollPane(textarea);
return pane;
}
#SuppressWarnings("serial")
private class Delete2EOL extends AbstractAction {
#Override
public void actionPerformed(ActionEvent e) {
int caretOffset = textarea.getCaretPosition();
int lineNumber = 0;
try {
lineNumber = textarea.getLineOfOffset(caretOffset);
int startOffset = textarea.getLineStartOffset(lineNumber);
int endOffset = textarea.getLineEndOffset(lineNumber);
textarea.replaceRange("", startOffset, endOffset);
} catch (BadLocationException ex) {
throw new RuntimeException(ex);
}
}
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> new TestSamplePrograms().buildAndShowGui());
}
}

How to define a shortcut for special keys in Java Swing, e.g. german umlaut key Ä?

How do I define a keyboard shortcut for top level special keys like german umlaut key Ä? I found a way to map unicode letters that are used for default american layout keys, see here. But the key event for the german umlaut key Ä is:
java.awt.event.KeyEvent[KEY_PRESSED,keyCode=0,keyText=Unknown keyCode: 0x0,keyChar='ä',keyLocation=KEY_LOCATION_STANDARD,rawCode=222,primaryLevelUnicode=228,scancode=40] on frame0
The idea is to register a keyboard action:
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
public class KeyStrokeForGermanUmlaut {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.setPreferredSize(new Dimension(600, 400));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
final JLabel label = new JLabel("Text shall change with shortcut");
panel.add(label);
panel.registerKeyboardAction(new AbstractAction() {
#Override
public void actionPerformed(ActionEvent event) {
label.setText("It is working!!!");
}
}, KeyStroke.getKeyStroke("control typed Ä"), JComponent.WHEN_IN_FOCUSED_WINDOW);
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
});
}
}
you can to conjuring with JLabel, nothing happends for KeyEvents
should be start point with moving the focus to JFrames ContentPane (can be used as JPanel, but has BorderLayout in compare with plain JPanel - FlowLayout)
-
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
public class KeyStrokeForGermanUmlaut {
private JFrame frame = new JFrame();
private JLabel label = new JLabel("Text shall change with shortcut");
public KeyStrokeForGermanUmlaut() {
frame.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.CTRL_MASK), "CTRL + A");
frame.getRootPane().getActionMap().put("CTRL + A", updateCol());
frame.setPreferredSize(new Dimension(600, 100));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(label);
frame.pack();
frame.setLocation(150, 150);
frame.setVisible(true);
}
private Action updateCol() {
return new AbstractAction("Hello World") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
label.setText(label.getText() + " presses");
}
};
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new KeyStrokeForGermanUmlaut();
}
});
}
}
.
.
EDIT see description in API getKeyStroke/ v.s. getKeyStrokeForEvent
then result is could be (little bit lost when and how to use modifiers SHIFT with uppercase form (ä and ú) for those two chars, maybe someone will help us with those pieces of KeyEvents)
from
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
public class KeyStrokeForGermanUmlaut {
private JFrame frame = new JFrame();
private JLabel label = new JLabel("Text shall change with shortcut");
public KeyStrokeForGermanUmlaut() {
frame.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
KeyStroke.getKeyStroke("typed ä"), "typed ä");
frame.getRootPane().getActionMap().put("typed ä", updateCol());
frame.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
KeyStroke.getKeyStroke("typed ú"), "typed ú");
frame.getRootPane().getActionMap().put("typed ú", updateCol1());
frame.setPreferredSize(new Dimension(600, 100));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(label);
frame.pack();
frame.setLocation(150, 150);
frame.setVisible(true);
}
private Action updateCol() {
return new AbstractAction("Hello World") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
label.setText(label.getText() + " presses - ä");
}
};
}
private Action updateCol1() {
return new AbstractAction("Hello World") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
label.setText(label.getText() + " presses - ú");
}
};
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new KeyStrokeForGermanUmlaut();
}
});
}
}
I am afraid there is something fishy in the handling of modifiers for CTRL.
That is: when inspecting the received key modifier=InputEvent.CTRL_MASK, extended modifier=InputEvent.CTRL_DOWN_MASK. And the API's javadoc is a bit suspicious.
Apart from that, Ä is not a special case, when "control" is left out.
To make it work, I had to add a dirty hack: register a key listener, that calls the action itself. I must be overseeing something.
For the rest I used an InputMap/ActionMap as intended. The input map does not seem to work, but to my understanding it does not work if added to a JTextField, or in the other answer (for Ä). The following works - in a horrible way.
final JLabel label = new JLabel("Text shall change with shortcut");
final KeyStroke key = KeyStroke.getKeyStroke((Character)'k',
InputEvent.CTRL_DOWN_MASK, false);
final Object actionKey = "auml";
final Action action = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent event) {
System.out.println("aha");
label.setText("It is working!!!");
}
};
label.addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(java.awt.event.KeyEvent e) {
if (e.isControlDown() && e.getKeyChar() == 'ä') {
System.out.println("Ctrl-ä");
label.getActionMap().get(actionKey).actionPerformed(null);
// return;
}
super.keyPressed(e);
}
});
label.getInputMap().put(key, actionKey);
label.getActionMap().put(actionKey, action);
Ä, \xC4, Ä, Ä, %C4, %C3%84
There are the code for Ä. Please try with this, maybe one them will work for you.

JFrame not repainting

I've been trying for at least an hour on refreshing my simple Jframe. I have tried repaint() revalidate; and just about anything else on the internet.
here is my entire class:
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
public final class BRUTEFORCE {
static int Passwords = 0;
static JFrame frame;
public static void main(String[] args) {
//Create and set up the window.
frame = new JFrame("Simple GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel textLabel = new JLabel("Passwords tried: " + Passwords,SwingConstants.CENTER);
textLabel.setPreferredSize(new Dimension(300, 100));
frame.getContentPane().add(textLabel, BorderLayout.CENTER);
//Display the window.
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
Passwords++;
new Thread("Refresh") {
public void run () {
while(true){
frame.invalidate();
frame.validate();
frame.repaint();
}
}
}.start();
new Thread("Test") {
public void run () {
while(true) Passwords++;
}
}.start();
}
}
What am I doing wrong?
Two things are going wrong. You're first thread is constantly feeling the Event Queue with update requests, probably faster then the Event Queue can process them which may eventually flood it, degrading the performance of the system.
Secondly, you never actually change the text of the textLabel
For example...
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
public class BruteForce {
static transient int Passwords = 0;
static JFrame frame;
public static void main(String[] args) {
//Create and set up the window.
frame = new JFrame("Simple GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JLabel textLabel = new JLabel("Passwords tried: " + Passwords, SwingConstants.CENTER);
textLabel.setPreferredSize(new Dimension(300, 100));
frame.getContentPane().add(textLabel, BorderLayout.CENTER);
//Display the window.
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
Passwords++;
new Thread("Test") {
public void run() {
while (true) {
try {
Passwords++;
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
textLabel.setText("Passwords tried: " + Passwords);
}
});
Thread.sleep(5);
} catch (InterruptedException ex) {
Logger.getLogger(BruteForce.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}.start();
}
}
Now, instead of a Thread, you might consider using a SwingWorker instead...
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
public class BruteForce {
static transient int Passwords = 0;
static JFrame frame;
public static void main(String[] args) {
//Create and set up the window.
frame = new JFrame("Simple GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JLabel textLabel = new JLabel("Passwords tried: " + Passwords, SwingConstants.CENTER);
textLabel.setPreferredSize(new Dimension(300, 100));
frame.getContentPane().add(textLabel, BorderLayout.CENTER);
//Display the window.
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
SwingWorker worker = new SwingWorker<Integer, Integer>() {
#Override
protected void process(List<Integer> chunks) {
// Only care about the last one..
int value = chunks.get(chunks.size() - 1);
textLabel.setText("Passwords tried: " + value);
}
#Override
protected Integer doInBackground() throws Exception {
while (true) {
// Perform long running process...
// Forced delay to simulate long running process
Thread.sleep(5);
Passwords++;
publish(Passwords);
}
}
};
worker.execute();
}
}

make enter key act like a tab key for jtextfield,jcombobox,jspinner in java

I want enter key to behave like tab key in my swing application.And this class is working fine for JTextFields.How can i do the same for JComboBox and Jspinner or for the other controls on the frame?kindly help.
class MyTextField extends JTextField {
MyTextField(int len) {
super(len);
addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent evt) {
int key = evt.getKeyCode();
if (key == KeyEvent.VK_ENTER)
transferFocus();
}
});
}
}
Enter has special meaning for most components in Swing, for example JTextField will trigger actionPerformed on registered ActionListeners when Enter is pressed. Modifying this behaviour may have unexpected results for your application and may confuse many users...
Having said that, the best way to change the focus traversal keys is to provide a Set of KeyStrokes to the KeyboardFocusManager. This will (mostly) make the key's global.
Some component's supply there own focus traversal keys however, like JTextArea and JTable
Take a look at How to use Focus Subsystem for more details
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestFocusTraversal {
public static void main(String[] args) {
new TestFocusTraversal();
}
public TestFocusTraversal() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
for (int index = 0; index < 10; index++) {
JTextField tf = new JTextField(5);
tf.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("...");
}
});
add(tf);
}
add(new JScrollPane(new JTextArea(10, 10)));
KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
KeyStroke tab = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0);
KeyStroke ctrlTab = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, KeyEvent.CTRL_DOWN_MASK);
Set<KeyStroke> keys = new HashSet<>();
keys.add(enter);
keys.add(tab);
keys.add(ctrlTab);
KeyboardFocusManager.getCurrentKeyboardFocusManager().setDefaultFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, keys);
}
}
}

KeyListener not working

public class KL implements KeyListener {
public static void main(String[] args) {
final JPopupMenu popup = new JPopupMenu();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 200);
frame.setVisible(true);
}
#Override
public void keyPressed(KeyEvent arg0) {
System.out.println(arg0.getKeyChar());
}
#Override
public void keyReleased(KeyEvent e) {
System.out.println(e.getKeyChar());
}
#Override
public void keyTyped(KeyEvent e) {
System.out.println(e.getKeyChar());
}
}
That's my class, it's probably something really stupid on my part, but my KeyListener here is not working. Nothing comes up on the console.
Let's start with the fact that you're not attached the listener to anything, then move on to the fact that you really should be using Key Bindings
And with example
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestTableEditing {
public static void main(String[] args) {
new TestTableEditing();
}
public TestTableEditing() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JLabel key;
private int counter = 0;
public TestPane() {
key = new JLabel("...");
add(key);
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), "A.pressed");
am.put("A.pressed", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("A was pressed");
key.setText("A was pressed " + (++counter));
}
});
}
}
}
I know this is an old post but I wanted to put this online so someone like myself can find it....
I worked on this problem for hours before figuring it out. Make sure that your Component has focus. For example I have all of my activity going on in a custom JPanel named SpaceShipPanel:
class SpaceShipPanel
{
//instance variables
//Now my constructor
SpaceShipPanel(){
//bla bla blah
setFocusable(true);//THIS LINE IS WHAT SAVED ME!!
}
}
From what I hear, keyBindings are the best route but the class I'm taking didn't cover this topic. Hopefully this will save someone hours of beating their heads against the wall.

Categories