JButton & Action & KeyBinding - java

I have created a JButton class that recieving Action, the JButton class includes keystrokes & mouse listener so i can use the same class in multiple frames as needed.
My problems is that:
JButton not getting the focus when pressing the key, but it doing the action.
i need to make a new background or something that tell the user that the button did the action.
Any ideas??
Here is my code:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.KeyStroke;
import javax.swing.SwingConstants;
import javax.swing.border.LineBorder;
import swtdesigner.SwingResourceManager;
public class IButtonSave extends JButton{
private static final long serialVersionUID = 1L;
private Action action = null;
public IButtonSave() {
super();
setFocusPainted(true);
setFocusable(true);
try {
jbInit();
} catch (Throwable e) {
e.printStackTrace();
}
}
private void jbInit() throws Exception {
setMargin(new Insets(0, 0, 0, 0));
setBorder(new LineBorder(Color.black, 1, true));
setIconTextGap(0);
setHorizontalTextPosition(SwingConstants.CENTER);
setVerticalTextPosition(SwingConstants.TOP);
setPreferredSize(new Dimension(50, 43));
setMinimumSize(new Dimension(50, 43));
setMaximumSize(new Dimension(50, 43));
addMouseListener(new ThisMouseListener());
setVerifyInputWhenFocusTarget(true);
}
public void setAction(Action a){
action = a;
KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_F1,0,true);
KeyStroke ks2 = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0);
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ks, "Save");
getInputMap(JComponent.WHEN_FOCUSED).put(ks2, "Save");
getActionMap().put("Save", a);
setText("Save [F1]");
setIcon(SwingResourceManager.getIcon(SwingResourceManager.class, "/images/small/save.png"));
setToolTipText("[F1]");
}
private class ThisMouseListener extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
this_mouseClicked(e);
}
}
protected void this_mouseClicked(MouseEvent e) {
if(e.getClickCount() >= 1){
action.actionPerformed(null);
}
}
}

Why extend JButton class when you can simply add KeyBindings to its instance?
Not to sure what you want but this works fine for me:
Basically a JButton which can be activated by mouse click, or pressing F1 (as long as focus is in window and if pressed will shift focus to JButton) or ENTER (only when in focus of JButton).
When the AbstractAction is called it will call requestFocusInWindow() on JButton (thus pressing F1 will make button gain focus which is what I think you wanted):
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
public class Test {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JButton btn = new JButton("Button");
AbstractAction aa = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
System.out.println("Here");
btn.requestFocusInWindow();//request that the button has focus
}
};
//so button can be pressed using F1 and ENTER
btn.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "Enter");
btn.getActionMap().put("Enter", aa);
btn.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0), "F1");
btn.getActionMap().put("F1", aa);
btn.addActionListener(aa);//so button can be clicked
JTextField tf = new JTextField("added to show ENTER wont work unless button in focus");
frame.add(tf);
frame.add(btn, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
});
}
}
UPADTE:
alternatively as #GuillaumePolet suggested (+1 to him) override processKeyBinding of JButton and check for appropriate key and than call the method:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
public class Test {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JButton btn = new JButton("Button") {
#Override
protected boolean processKeyBinding(KeyStroke ks, KeyEvent ke, int i, boolean bln) {
boolean b = super.processKeyBinding(ks, ke, i, bln);
if (b && ks.getKeyCode() == KeyEvent.VK_F1) {
requestFocusInWindow();
}
return b;
}
};
AbstractAction aa = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
System.out.println("Here");
}
};
//so button can be pressed using F1 and ENTER
btn.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "Enter");
btn.getActionMap().put("Enter", aa);
btn.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0), "F1");
btn.getActionMap().put("F1", aa);
btn.addActionListener(aa);//so button can be clicked
JTextField tf = new JTextField("added to show ENTER wont work unless button in focus");
frame.add(tf);
frame.add(btn, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
});
}
}

Not sure this is the best way to do it, but it works decently enough and if it is not the best way, you get a free SSCCE out of this answer.
I override processKeyBindings() and if it returns true then I grab the focus to indicate that the action has been performed. If you want to do something else you just need to modify the code there.
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
public class IButtonSave extends JButton {
private static final long serialVersionUID = 1L;
public IButtonSave() {
super();
setFocusPainted(true);
setFocusable(true);
}
#Override
protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) {
boolean processKeyBinding = super.processKeyBinding(ks, e, condition, pressed);
if (processKeyBinding) {
requestFocusInWindow();
}
return processKeyBinding;
}
#Override
public void setAction(Action a) {
super.setAction(a);
KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0, true);
KeyStroke ks2 = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ks, "Save");
getInputMap(JComponent.WHEN_FOCUSED).put(ks2, "Save");
getActionMap().put("Save", a);
setText("Save [F1]");
setToolTipText("[F1]");
}
protected void initUI() {
JFrame frame = new JFrame(IButtonSave.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTextArea textarea = new JTextArea(5, 30);
JPanel buttonPanel = new JPanel();
AbstractAction someAction = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.err.println("Action performed");
}
};
IButtonSave button = new IButtonSave();
button.setAction(someAction);
buttonPanel.add(button);
frame.add(new JScrollPane(textarea));
frame.add(buttonPanel, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new IButtonSave().initUI();
}
});
}
}

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());
}
}

Command + Backspace functionality in JTextArea

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());
}
}

Strange behaviour of a JComboBox with a different popup component

Try to use some "dark side" features of Swing and got problem when I try to populate the popup of a combo-box with some components. Here is my SSCCE:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DateFormatSymbols;
import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.plaf.basic.ComboPopup;
public class ComboBoxTryout extends JComboBox {
private JPanel panel;
public ComboBoxTryout() {
initPanel();
}
private void initPanel() {
panel = new JPanel(new GridLayout(7, 1, 5, 5));
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
DateFormatSymbols symbols = new DateFormatSymbols();
for (String s : symbols.getWeekdays()) {
if (s != null && !s.trim().isEmpty()) {
panel.add(createCheckBox(s));
}
}
setPopupComponent(this, panel);
}
private JCheckBox createCheckBox(String text) {
final JCheckBox cb = new JCheckBox(text);
cb.setHorizontalAlignment(SwingConstants.LEADING);
cb.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
StringBuilder b = new StringBuilder();
for (Component c : panel.getComponents()) {
if (c instanceof JCheckBox && ((JCheckBox) c).isSelected()) {
if (b.length() > 0) {
b.append(", ");
}
b.append(((JCheckBox) c).getText().substring(0, 3));
}
}
getModel().setSelectedItem(b.toString());
}
});
return cb;
}
/**
* Sets the custom component as popup component for the combo-box.
*
* #param combo combo-box to get new popup component.
* #param comp new popup component.
*/
public static void setPopupComponent(JComboBox<?> combo, Component comp) {
final ComboPopup popup = (ComboPopup) combo.getUI().getAccessibleChild(combo, 0);
if (popup instanceof Container) {
Container c = (Container) popup;
c.removeAll();
c.setLayout(new GridLayout(1, 1));
c.add(comp);
c.setPreferredSize(comp.getPreferredSize());
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frm = new JFrame("Test");
frm.add(new ComboBoxTryout(), BorderLayout.NORTH);
frm.setSize(250, 600);
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.setLocationRelativeTo(null);
frm.setVisible(true);
}
});
}
}
I can open the combo-box but when I click a check-box in the popup the combo-box goes closed and check-box is still not selected. But, when I change the line
frm.add(new ComboBoxTryout(), BorderLayout.NORTH);
to
frm.add(new ComboBoxTryout(), BorderLayout.SOUTH);
all works fine: I can change state of check-boxes and popup is still visible! Any suggestions, how to get it working for BorderLayout.NORTH?
The following doesn't use a regular JComboBox, but rather mimics one to give you more control.
This example is inspired from Creating Pop-Up Components and from your code.
It uses a Popup component and listeners on the button and on the textfield (textfield + button to look like a combobox, this part is not visually optimized in this example) to manage the popup hiding/showing.
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.text.DateFormatSymbols;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Popup;
import javax.swing.PopupFactory;
import javax.swing.SwingConstants;
public class ButtonPopupSample {
private final JTextField tField;
private final JButton start;
private final JPanel panel;
private boolean popping = false;
private Popup popup;
ButtonPopupSample() {
panel = new JPanel(new GridLayout(7, 1, 5, 5));
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
DateFormatSymbols symbols = new DateFormatSymbols();
for (String s : symbols.getWeekdays()) {
if (s != null && !s.trim().isEmpty()) {
panel.add(createCheckBox(s));
}
}
JFrame frame = new JFrame("Button Popup Sample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
tField = new JTextField(20);
tField.setEditable(false);
start = new JButton("Pop");
ActionListener actionListener = new ActionListener() {
#Override
public void actionPerformed(final ActionEvent e) {
popOrNot();
}
};
start.addActionListener(actionListener);
tField.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(final MouseEvent me) {
popOrNot();
}
});
JPanel contPan = new JPanel();
contPan.add(tField);
contPan.add(start);
frame.setContentPane(contPan);
frame.setSize(350, 250);
frame.setVisible(true);
}
private JCheckBox createCheckBox(final String text) {
final JCheckBox cb = new JCheckBox(text);
cb.setHorizontalAlignment(SwingConstants.LEADING);
cb.addActionListener(new ActionListener() {
#Override
public void actionPerformed(final ActionEvent e) {
StringBuilder b = new StringBuilder();
for (Component c : panel.getComponents()) {
if (c instanceof JCheckBox && ((JCheckBox) c).isSelected()) {
if (b.length() > 0) {
b.append(", ");
}
b.append(((JCheckBox) c).getText().substring(0, 3));
}
}
tField.setText(b.toString());
}
});
return cb;
}
private void popOrNot() {
if (popping) {
popup.hide();
} else {
PopupFactory factory = PopupFactory.getSharedInstance();
Point location = tField.getLocationOnScreen();
popup = factory.getPopup(tField, panel, location.x, location.y + tField.getHeight());
popup.show();
}
popping = !popping;
}
public static void main(final String args[]) {
new ButtonPopupSample();
}
}
Solution found. A strange focus change event provides the above described problem. So processing of this event must be prevented.
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.text.DateFormatSymbols;
import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.plaf.basic.ComboPopup;
#SuppressWarnings("serial")
public class ComboBoxTryout extends JComboBox {
private JPanel panel;
private boolean avoidFocusChange;
/**
*
*/
public ComboBoxTryout() {
initPanel();
}
private void initPanel() {
panel = new JPanel(new GridLayout(7, 1, 5, 5));
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
DateFormatSymbols symbols = new DateFormatSymbols();
for (String s : symbols.getWeekdays()) {
if (s != null && !s.trim().isEmpty()) {
panel.add(createCheckBox(s));
}
}
setPopupComponent(this, panel);
}
#Override
protected void processFocusEvent(FocusEvent e) {
if (avoidFocusChange && FocusEvent.FOCUS_LOST == e.getID() && panel.isAncestorOf(e.getOppositeComponent())) {
System.out.println(e); // skip it
} else {
super.processFocusEvent(e);
}
avoidFocusChange = false;
}
private JCheckBox createCheckBox(String text) {
final JCheckBox cb = new JCheckBox(text);
cb.setHorizontalAlignment(SwingConstants.LEADING);
cb.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
StringBuilder b = new StringBuilder();
for (Component c : panel.getComponents()) {
if (c instanceof JCheckBox && ((JCheckBox) c).isSelected()) {
if (b.length() > 0) {
b.append(", ");
}
b.append(((JCheckBox) c).getText().substring(0, 3));
}
}
getModel().setSelectedItem(b.toString());
}
});
cb.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
avoidFocusChange = SwingUtilities.isLeftMouseButton(e);
}
});
return cb;
}
/**
* Sets the custom component as popup component for the combo-box.
*
* #param combo combo-box to get new popup component.
* #param comp new popup component.
*/
public static void setPopupComponent(JComboBox<?> combo, Component comp) {
final ComboPopup popup = (ComboPopup) combo.getUI().getAccessibleChild(combo, 0);
if (popup instanceof Container) {
Container c = (Container) popup;
c.removeAll();
c.setLayout(new GridLayout(1, 1));
c.add(comp);
Dimension dim = comp.getPreferredSize();
dim.width += 10; // need 10 px more width
c.setPreferredSize(dim);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frm = new JFrame("Test");
frm.add(new ComboBoxTryout(), BorderLayout.NORTH);
frm.setSize(250, 600);
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.setLocationRelativeTo(null);
frm.setVisible(true);
}
});
}
}
If somebody finds a better solution, please post it!!!

Why is control TAB keystroke not working?

Following is my code
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.util.Arrays;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
public class Test {
private int selected = 0;
public Test() {
JLabel[] lables = new JLabel[] { new JLabel("Lable1"),
new JLabel("Label2") };
JFrame frame = new JFrame("FrameDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel contentPane = (JPanel) frame.getContentPane();
contentPane.setLayout(new FlowLayout());
contentPane.add(lables[0]);
contentPane.add(lables[1]);
frame.pack();
contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
KeyStroke.getKeyStroke("control TAB"), "next");
Action action = new AbstractAction("next") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
selected++;
Arrays.stream(lables).forEach(
l -> l.setForeground(Color.LIGHT_GRAY));
lables[selected % 2].setForeground(Color.BLACK);
System.out.println(selected);
contentPane.revalidate();
contentPane.repaint();
}
};
contentPane.getActionMap().put("next", action);
frame.setVisible(true);
}
public static void main(String[] args) {
new Test();
}
}
But when I press control TAB, nothing happens. But when if I change the code to something like KeyStroke.getKeyStroke("control K"), "next"); the control K keystorke changes the foreground color.
What am I doing wrong? Is the "control Tab" reserved for some purpose? If so, how can I change that behaviour so that I can bind that keystroke to my action?

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.

Categories