Detect CTRL+V in Swing App but keep original function - java

Wrting a chat application, I want the user to be able to send images out of his/her clipboard. For this, I would like to catch any CTRL+Vkeyboard input. Since pasting text should be possible as by default, the original ctrl+v-function (pasting text) must not be overridden.
I see can two approaches, of which none works for me:
1st: Taken from the official Java documentation: KEY LISTENER
editorPane.addKeyListener(new KeyListener() {
#Override
public void keyPressed(KeyEvent e) {
e.getKeyChar()
// when I press ctrl+v, ^ this is falsely a white square character, looks like (U+25A1). Plain v without ctrl does work.
e.getKeyCode()
// ^ this is falsely 0
// (e.getModifiersEx() correctly returns InputEvent.CTRL_DOWN_MASK)
}
2nd: KEY BINDING
InputMap iMap = editorPane.getInputMap(condition);
ActionMap aMap = editorPane.getActionMap();
iMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_DOWN_MASK), "ctrlV");
aMap.put("ctrlV", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
// works, but overrides natural ctrl+v function!
}
});
Any ideas?
Note: I am using a "foreign" keyboard layout (German). But I can't see why this should make any difference - I would pretty much like to have my application work internationally.
Cheers
edit. Alt+SomeKey however is correctly recognized by the KeyListener
edit2. after changing keyboard layout to US, problem persists.

Stick to Keybindings: KeyListener is a low-level API, while Keybindings will provide you consistent, predictable and robust behaviour.
The solution here is quite easy. You can simply combine the actions yourself by adding a CombinedAction class that will execute the "original" action bound to CTRL+V and the "custom" action you want to execute.
See a small example below combining both actions (here my custom action is a Sysout):
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.JComponent;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
import javax.swing.ScrollPaneConstants;
public class TestEditorPane {
private JEditorPane editorPane;
public static class CombinedAction implements ActionListener {
private final ActionListener action1;
private final ActionListener action2;
public CombinedAction(ActionListener action1, ActionListener action2) {
super();
this.action1 = action1;
this.action2 = action2;
}
#Override
public void actionPerformed(ActionEvent e) {
if (action1 != null) {
action1.actionPerformed(e);
}
if (action2 != null) {
action2.actionPerformed(e);
}
}
}
public TestEditorPane() {
}
private void initUI() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// JTEXTBOX
editorPane = new JEditorPane();
KeyStroke ctrlV = KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.CTRL_DOWN_MASK);
final ActionListener ctrlVAction = editorPane.getActionForKeyStroke(ctrlV);
editorPane.registerKeyboardAction(new CombinedAction(ctrlVAction, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("This is my action on CTRL+V");
}
}), ctrlV, JComponent.WHEN_FOCUSED);
// JSCROLLPANE
JScrollPane scroll1 = new JScrollPane(editorPane);
scroll1.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scroll1.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
frame.add(scroll1);
frame.setSize(400, 400);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
TestEditorPane test = new TestEditorPane();
test.initUI();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}

Related

java eclipse windowbuilder keyPressed event does not fire

I've got a problem with my program what I can't solve. I'm trying for hours and tried to google, etc... I've seen many programs, which is working, but I don't know why my solution does not. My goal (for now) is simple, I want to write to the cmd-line in case of a mouse click or a key press. The first one works, but the second is not. Can anyone tell my why?
import java.awt.EventQueue;
import javax.swing.JFrame;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class test {
private JFrame frame;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
test window = new test();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public test() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.getContentPane().addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
System.out.println("Mouse has clicked!");
}
});
frame.getContentPane().addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent arg0) {
System.out.println("A key has pressed.");
}
});
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Well, finally I had enough time trying to find the solution and now I'm discovered it. I do not know why, but it was not possible to add a keyListener to the JFrame. I could only add for a JButton or a JTextField, etc... This is strange for me, a little bit :c

Java easiest keylistener

I know there was milions of questions about that, but I can't understand most of them. I've seen that people make something like that:
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode()== KeyEvent.VK_Q)
//do something
}
but keyPressed must override methos of some class to work or be runned in other thread. I really don't know how to do that. Can someone give me code of the easiest keylistener for java.
It should work even when program is not focused (it's just console program).
import java.awt.AWTException;
import java.awt.Robot;
import java.awt.event.*;
import javax.swing.JFrame;
public class SquatCounter {
class MyKeyListener extends KeyAdapter{
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode()== KeyEvent.VK_Q)
System.out.println("Key Q pressed!");
}
}
JFrame jf = new JFrame("title");
public SquatCounter() {
jf.addKeyListener(new MyKeyListener());
}
public static void main(String[] args) {
Key1 key = new Key1 ();
SquatCounter test = new SquatCounter();
}
}
When you setup the JFrame, add a KeyListener like this:
JFrame jf = new JFrame("title");
jf.addKeyListener(new MyKeyListener());
jf.setVisible(false);
(The jf.setVisible(false); stops the program window from appearing (only command line)
Then create a new class called MyKeyListener that extends KeyAdapter.
class MyKeyListener extends KeyAdapter{
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode()== KeyEvent.VK_Q)
System.out.println("Key Q pressed!");
}
}
Now let me explain things a bit.
First, when you create a JFrame, it has no default KeyListener attached. Therefore, we have to create a class MyKeyListener to do that.
Secondly, we extended KeyAdapter instead of implementing KeyListener because there are a lot more methods than what you need in there. You only need to override the keypressed() method when you extends KeyAdapter but you have to implement all (I think it's 3) the other methods that you don't need for your purposes.
Lastly, if you want to do other methods like keyreleased(), just add it in to the MyKeylistener class and it will work.
Hope this helps!
EDIT: Per OP's request, it should be like this:
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String line = "";
while (line.equalsIgnoreCase("q") == false) {
line = in.read();
System.out.println("Q is pressed!");
}
in.close();
Just add a KeyListener.
import java.awt.AWTException;
import java.awt.Robot;
import java.awt.event.*;
import javax.swing.JFrame;
public class SquatCounter {
JFrame jf = new JFrame("title") {{
setVisible(true);
setDefaultCloseOperation(3); // EXIT_ON_CLOSE
}};
public SquatCounter() {
jf.addKeyListener(new KeyListener() {
#Override
public void keyPressed(KeyEvent event) {
if (e.getKeyCode()== KeyEvent.VK_Q)
//do something
}
#Override
public void keyReleased(KeyEvent event) {
// different stuff
}
#Override
public void keyTyped(KeyEvent event) {
// more stuff
}
});
}
public static void main(String[] args) {
SquatCounter test = new SquatCounter();
}
}
Doing something out of focus has an answer here: Stackoverflow: Listening for input without focus in Java

Can't figure out error with ActionListener

The following is my program. the goal is to convert from a roman numeral to an Arabic number after a user types in the numeral and presses the enter key.
This is a homework assignment and we are forced to user JTextAreas in lieu of JTextFields.
My error exists on the line: enterRomanNumber.addActionListener(handler);
The error reads:
"The method addActionListener(ArabicToRomanGUI.HandlerForTextArea) is
undefined for the type JTextArea"
I can't seem to figure out why I am getting this error or how to correct it, can someone please advise.
import java.awt.FlowLayout;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.ActionEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextArea;
public class ArabicToRomanGUI extends JFrame
{
private static final long serialVersionUID = 1L;
private JTextArea enterRomanNumber = new JTextArea();
JLabel label = new JLabel();
JPanel panel = new JPanel();
JFrame frame = new JFrame();
//TestArea contructor adds jtextArea to jframe
public ArabicToRomanGUI()
{
super("Convert a Roman Numeral");
setLayout(new FlowLayout());
//Text field to enter a roman numeral
enterRomanNumber = new JTextArea(1,25);
enterRomanNumber.setText("Delete this text and Enter a Roman Numerial Here!");
//enterRomanNumber.setAlignmentX(0);
//enterRomanNumber.setAlignmentY(0);
add(enterRomanNumber);
HandlerForTextArea handler = new HandlerForTextArea();
enterRomanNumber.addActionListener(handler);
}
private class HandlerForTextArea implements ActionListener
{
//used to process textArea events
#Override
public void actionPerformed(ActionEvent e)
{
String userInput = "";
userInput = enterRomanNumber.getText();
userInput = userInput.toUpperCase();
ConversionLogic.ConvertFromRomanToArabic(userInput); //converts user string of Roman numerals to an int in arabic
String arabicNumberAsString = ConversionLogic.getConvertedRomanNumeral();
enterRomanNumber.setText(arabicNumberAsString);
//user pressed enter in JTextField enterNumberField
if(e.getSource() == enterRomanNumber)
{
//enterRomanNumber.setText(arabicNumberAsString);
if (ConversionLogic.getCheckFail() == true)
{
JOptionPane.showMessageDialog(frame, "The Roman Numeral entered is Invalid", "Error", JOptionPane.ERROR_MESSAGE);
}
else
{
JOptionPane.showMessageDialog(frame, "The arabic equivalent is " + arabicNumberAsString + "." , "Conversion Successful", JOptionPane.PLAIN_MESSAGE);
}
}
}
}
}//end inner class TextAreaHandler
For a better answer, see #MadProgrammer 's answer.
My solution:
There is no ActionListener for JTextArea.
So just use KeyListener instead
HandlerForTextArea handler = new HandlerForTextArea();
enterRomanNumber.addKeyListener(handler);
Implements KeyListener
private class HandlerForTextArea implements KeyListener
{
#Override
public void keyPressed(KeyEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void keyReleased(KeyEvent arg0) {
// TODO Auto-generated method stub
if (arg0.getKeyCode() == VK_ENTER){
// TODO Your bussiness
}
}
#Override
public void keyTyped(KeyEvent arg0) {
// TODO Auto-generated method stub
}
}
KeyListeners are NEVER appropriate solutions to use with text components, if you want to be notified when a text component changes, you use a DocumentListener, if you want to change/filter what can be entered into a text component, you use a DocumentFilter, if you need to change a special key, like Enter, you should use a key binding
See How to Use Key Bindings for more details.
One of the problems you could have with KeyListener is not knowing when the key stroke is processed by the text component, in your case, it may not be a major issue, but it could change the way the program works on different platforms.
Instead, you can override the JTextArea's key binding for the Enter key (named insert-break). This provides you with the ability to actually change the behavior of the key stroke, or, in your case, manage how you process the event. For example, this replaces the Action for the text area's Enter key, but retains the previous/default behavior...
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class KeyBindingsTest {
public static void main(String[] args) {
new KeyBindingsTest();
}
public KeyBindingsTest() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JTextArea ta;
public TestPane() {
ta = new JTextArea(10, 20);
ActionMap am = ta.getActionMap();
Action proxy = am.get("insert-break");
am.put("insert-break", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
// You can process the event through the original action BEFORE
// you do your own processing
//proxy.actionPerformed(e);
System.out.println("You pressed the enter key, you can have candy");
// Or you can process the event through the original action AFTER
// you do your own processing, you have now gained control
proxy.actionPerformed(e);
}
});
setLayout(new BorderLayout());
add(ta);
}
}
}
Now, you could even go to the extent for creating your own JTextArea which supported ActionPerformed...
public class ActionableTextArea extends JTextArea {
private String actionCommand;
public ActionableTextArea() {
installKeyBindings();
}
public ActionableTextArea(String text) {
super(text);
installKeyBindings();
}
public ActionableTextArea(int rows, int columns) {
super(rows, columns);
installKeyBindings();
}
public ActionableTextArea(String text, int rows, int columns) {
super(text, rows, columns);
installKeyBindings();
}
public ActionableTextArea(Document doc) {
super(doc);
installKeyBindings();
}
public ActionableTextArea(Document doc, String text, int rows, int columns) {
super(doc, text, rows, columns);
installKeyBindings();
}
protected void installKeyBindings() {
ActionMap am = getActionMap();
Action proxy = am.get("insert-break");
am.put("insert-break", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
// You can process the event through the original action BEFORE
// you do your own processing
//proxy.actionPerformed(e);
fireActionPerformed();
// Or you can process the event through the original action AFTER
// you do your own processing, you have now gained control
proxy.actionPerformed(e);
}
});
}
public void addActionListener(ActionListener listener) {
listenerList.add(ActionListener.class, listener);
}
public void removeActionListener(ActionListener listener) {
listenerList.remove(ActionListener.class, listener);
}
public void setActionCommand(String actionCommand) {
this.actionCommand = actionCommand;
}
public String getActionCommand() {
return actionCommand;
}
protected void fireActionPerformed() {
ActionListener[] listeners = listenerList.getListeners(ActionListener.class);
if (listeners.length > 0) {
ActionEvent evt = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, getActionCommand());
for (ActionListener listener : listeners) {
listener.actionPerformed(evt);
}
}
}
}

What kind of voodoo is necessary to get the glassPane visible and valid for an JInternalFrame?

I have a project where I use JDesktopPane for the main application and a bunch of JInternalFrames for a series of independent analyses.
Certain bits of the analyses are time-consuming thus I run them on SwingWorkers, but I would like to both disable the GUI (so no actions are queued) and inform the user that some action is going on and that it's normal.
Previously I have used a custom GlassPane for that purpose, and it has worked nicely before. Now I am experiencing some issues, using the same class as before. Specifically, the glassPane intercepts user input, expected but no visual cue is visible, which makes me think that the paintComponent() is never called on the glassPane.
Just to be sure I googled and came across another implementation (called DisabledGlassPane) of the "please-wait-glassPane" concept but to no success really. While trying to debug the issue I realised that when I start/activate my glassPane it is invalid by default and does not get validated by itself.
If I specifically call validate() on the JInternalFrame after activating the glassPane, it appears to be valid and visible, based on the properties of the glassPane but I see nothing on the screen (both GlassPane implementations have color and text based features that should be immediately visible to the user).
EDIT:
Below is the relevant piece of the code, extracted out of the bigger scheme of things into a minimalist, self-contained (with the exception of the DisabledGlassPane class mentioned above, omitted for the sake of brevity) example. When I run the DesktopFrame class below, and click the button the calculations start, the cursor changes to waiting mode, however the screen is not grayed out, and the message to the user is not displayed, hence my suspicion of paintComponent is never actually called..
I am primarily wondering if I have made an obvious miss, since I am not that experienced with GUI programming and Swing.
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.ExecutionException;
import javax.swing.JButton;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.SwingWorker;
import javax.swing.event.InternalFrameEvent;
import javax.swing.event.InternalFrameListener;
public class DesktopFrame extends JFrame implements InternalFrameListener{
private JDesktopPane dpane;
private JInternalFrame f;
static DisabledGlassPane gp = new DisabledGlassPane();
public DesktopFrame() {
dpane = new javax.swing.JDesktopPane();
dpane.setPreferredSize(new java.awt.Dimension(1020, 778));
setContentPane(dpane);
addFrame();
pack();
}
public JInternalFrame addFrame(){
f = new JInternalFrame("test");
f.setGlassPane(gp);
f.addInternalFrameListener(this);
f.setLayout(new GridLayout());
f.setPreferredSize(new java.awt.Dimension(400,300));
f.add(new javax.swing.JLabel("something something"));
f.add(new javax.swing.JTextArea(10, 10));
javax.swing.JButton but = new JButton("click me!");
but.setPreferredSize(new java.awt.Dimension(100,50));
but.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
gp.activate("Please wait...");
SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
for(float i=-3000; i < 3000; i = i + 0.01f){
double exp = Math.pow(2,i);
double fac = Math.pow(i, 2);
System.out.println(exp/fac);
}
return null;
}
};
worker.execute();
try {
if(worker.get() == null)
gp.deactivate();
} catch (InterruptedException | ExecutionException e1) {
e1.printStackTrace();
}
}
});
f.add(but);
f.setVisible(true);
f.pack();
dpane.add(f);
try {
f.setSelected(true);
} catch (java.beans.PropertyVetoException e) {
e.printStackTrace();
}
dpane.repaint();
return f;
}
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
DesktopFrame df = new DesktopFrame();
df.setLocationRelativeTo(null);
df.setVisible(true);
df.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
});
}
#Override
public void internalFrameOpened(InternalFrameEvent e) {}
#Override
public void internalFrameClosing(InternalFrameEvent e) {}
#Override
public void internalFrameClosed(InternalFrameEvent e) {}
#Override
public void internalFrameIconified(InternalFrameEvent e) {}
#Override
public void internalFrameDeiconified(InternalFrameEvent e) {}
#Override
public void internalFrameActivated(InternalFrameEvent e) {}
#Override
public void internalFrameDeactivated(InternalFrameEvent e) {}
}
but I would like to both disable the GUI (so no actions are queued) and inform the user that some action is going on and that it's normal.
Check out the Disable Glass Pane for a general solution you might be able to use. The above class intercepts mouse and key events and allows you to display a message while the glass pane is visible.

How to act upon hitting "Enter" when on "Cancel" button in JFileChooser?

I have a JFileChooser in a JFrame. I've added an ActionListener to the JFileChooser so that the "Cancel" button works when clicked. I can also tab to the "Cancel" button, but when I then hit the "Enter" key, nothing happens (i.e., the ActionListener isn't called with the event command JFileChooser.CANCEL_SELECTION). What must I do with the JFileChooser so that hitting the "Enter" key when on the "Cancel" button is equivalent to clicking on the "Cancel" button?
Here's a simple example of the (mis)behavior I'm seeing:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
public final class TestApp {
public static void main(final String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
final JFileChooser chooser = new JFileChooser();
chooser.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
System.exit(0);
}
});
final JFrame frame = new JFrame();
frame.add(chooser);
frame.pack();
frame.setVisible(true);
}
catch (final Throwable t) {
t.printStackTrace();
}
}
});
}
}
To see the (mis)behavior, execute the program, tab to "Cancel", and then hit the "Enter" key. The program doesn't terminate on my platform -- although it does when I click on the "Cancel" button.
Extending JFileChooser and overriding cancelSelection() also doesn't work (apparently, that function isn't called when the "Enter" key is hit while on the "Cancel" button).
The (mis)behavior occurs on my Fedora 10 x86_64 system with Java 5, 6, and 7.
ADDENDUM: The following adds a KeyEventPostProcessor to the current KeyboardFocusManager and appears to do what I want:
import java.awt.Component;
import java.awt.KeyEventPostProcessor;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
public final class TestApp {
public static void main(final String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
final JFileChooser chooser = new JFileChooser();
chooser.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
System.out.println(e.paramString());
System.exit(0);
}
});
final KeyboardFocusManager kfm = KeyboardFocusManager
.getCurrentKeyboardFocusManager();
kfm.addKeyEventPostProcessor(new KeyEventPostProcessor() {
#Override
public boolean postProcessKeyEvent(final KeyEvent e) {
if (e.getID() == KeyEvent.KEY_RELEASED
&& e.getKeyCode() == KeyEvent.VK_ENTER) {
final Component comp = e.getComponent();
if (chooser.isAncestorOf(comp)) {
if (!(comp instanceof JButton)) {
chooser.approveSelection();
}
else {
final JButton button = (JButton) comp;
if ("Cancel".equals(button.getText())) {
chooser.cancelSelection();
}
else {
chooser.approveSelection();
}
}
}
}
return false;
}
});
final JFrame frame = new JFrame();
frame.add(chooser);
frame.pack();
frame.setVisible(true);
}
catch (final Throwable t) {
t.printStackTrace();
}
}
});
}
}
It seems like a lot of work, however, just to be able to distinguish between hitting the enter key on the "Cancel" button versus anywhere else.
Do you see any problems with it?
DISCOVERED SOLUTION: Setting the GUI Look and Feel to the native one for my system (Linux) does what I want without the need for anything else. This is what I was ignorant of and what I was looking for. The solution is to have the following
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
as the first executable statement of the main() method. One can then dispense with all focus listeners, key event processors, etc.
I've awarded the 100 points to the most helpful respondent.
The program doesn't terminate on my platform.
I see normal operation on Mac OS X 10.5, Ubuntu 10 and Windows 7 using (variously) Java 5 and 6. I replaced your exit() with println() to see the event:
System.out.println(rootDirChooser.getSelectedFile().getName() + e.paramString());
It may help to specify your platform and version; if possible, verify correct installation as well.
I'm not sure I understand your goal; but, as an alternative, consider overriding approveSelection():
private static class MyChooser extends JFileChooser {
#Override
public void approveSelection() {
super.approveSelection();
System.out.println(this.getSelectedFile().getName());
}
}
Addendum:
The goal is to have the action of hitting the "Enter" key while on the "Cancel" button be identical to clicking on the "Cancel" button.
As discussed in Key Bindings, you can change the action associated with VK_ENTER.
KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
InputMap map = chooser.getInputMap(JFileChooser.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
map.put(enter, "cancelSelection");
If you want the change to occur only while the "Cancel" button has focus, you'll need to do it in a Focus Listener.
Addendum:
I found a solution that uses KeyboadFocusManager, instead. What do you think?
I can see pros & cons each way, so I've outlined both below. Using KeyboadFocusManager finds all buttons, but offers no locale independent way to distinguish among them; the Focus Listener approach can only see the approve button, and it's UI specific. Still, you might combine the approaches for better results. A second opinion wouldn't be out of order.
Addendum:
I've updated the code below to eliminate the need to know the localized name of the "Cancel" button and use key bindings.
import java.awt.EventQueue;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.KeyStroke;
import javax.swing.plaf.metal.MetalFileChooserUI;
public final class FileChooserKeys
implements ActionListener, FocusListener, PropertyChangeListener {
private final JFileChooser chooser = new JFileChooser();
private final MyChooserUI myUI = new MyChooserUI(chooser);
private final KeyStroke enterKey =
KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
private void create() {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
chooser.addActionListener(this);
myUI.installUI(chooser);
myUI.getApproveButton(chooser).addFocusListener(this);
KeyboardFocusManager focusManager =
KeyboardFocusManager.getCurrentKeyboardFocusManager();
focusManager.addPropertyChangeListener(this);
frame.add(chooser);
frame.pack();
frame.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(e.paramString());
}
#Override
public void focusGained(FocusEvent e) {
System.out.println("ApproveButton gained focus.");
}
#Override
public void focusLost(FocusEvent e) {
System.out.println("ApproveButton lost focus.");
}
#Override
public void propertyChange(PropertyChangeEvent e) {
Object o = e.getNewValue();
InputMap map = chooser.getInputMap(
JFileChooser.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
if (o instanceof JButton) {
if ("focusOwner".equals(e.getPropertyName())) {
JButton b = (JButton) o;
String s = b.getText();
boolean inApproved = b == myUI.getApproveButton(chooser);
if (!(s == null || "".equals(s) || inApproved)) {
map.put(enterKey, "cancelSelection");
} else {
map.put(enterKey, "approveSelection");
}
}
}
}
private static class MyChooserUI extends MetalFileChooserUI {
public MyChooserUI(JFileChooser b) {
super(b);
}
#Override
protected JButton getApproveButton(JFileChooser fc) {
return super.getApproveButton(fc);
}
}
public static void main(final String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new FileChooserKeys().create();
}
});
}
}

Categories