How to trigger Java Swing InputVerifier on enter in JComboBox (actionPerformed)? - java

I have a Swing JComboBox with an InputVerifier set correctly.
I am using the combo box to set an integer.
If I type "cat" in the field and hit tab, my InputVerifier triggers and resets the value to "0".
If I type "cat" and hit enter, my InputVerifier is never called from actionPerformed. Do I need to explicitly call my InputVerifier from actionPerformed?
What's the best model to validate my JComboBox on tab and enter? It seems like this is something that should be given to me "for free" by the swing model.

The problem is "hit Tab" and "hit Enter" mean two different things in Java Swing. But those two actions mean the same thing to you, me, and the user.
Swing has no single mechanism to detect "when the user is done entering data". Instead, Swing focuses on the mechanics of "is this field losing keyboard focus" and "is the user pressing Enter key while inside a field".
Semantically those two actions mean the same thing from the user's perspective: "I'm done. Here's my input.". But, from what I can tell, Swing fails to offer a way to detect that user intention. I'm as surprised as you by the lack of such a feature, as this seems to be the most basic function of a form in a GUI. What we need, but don't have, is a "dataEntered" event.
There is a workaround…
In a similar context (JTextField instead of JComboBox) the Sun/Oracle Java Tutorial provides the example InputVerificationDemo where a class is created that:
Extends InputVerifier (to handle tabbing/clicking where focus is about to be lost)
Implements ActionListener (to handle pressing Enter key without leaving field)
The good thing about this workaround is that you can locate your handling code all in one place. The downside is that you still have the hassle of:
Creating a separate class.
Instantiating that class.
Passing that instance to both the setInputVerifier and addActionListener methods of your widget (JTextField, etc.).

This is the expected behavior of InputVerifier: the TAB key attempts to change focus, while the ENTER key does not. You can bind the ENTER key to a different action, as described in the tutorial How to Use Key Bindings. Also, consider the informative article Key Bindings, which includes a handy utility application.

When using an editable combo box, focus is on a JTextField which is used as the editor of the combo box. You can add an ActionListener to this text field.
In the ActionListener you could try invoking the transferFocus() method which should be equivalent to tabbing our of the text field. If that doesn't work then tha actionListener should invoke the same editing code as the InputVerifier.

Related

Java Swing GUI Hidden Input

I made a simple JFrame with Swing. I want to know how I would go about making a non-visible input that would open up another JFrame I have in another class. (Like cheat codes in video games, you enter a combination and something happens.) I am not sure how to capture the user input without a text field.
You should use keybinding attached to your JFrame. You would want to store keystrokes as a String internally and after each keystroke, see whether the user has entered a recognizable cheat code or just listen for a return keypress as a delimiter for the code.
Keep in mind that if a component within that JFrame has focus and also implements the same key bindings, then that component will take precedence over the JFrame, effectively intercepting the keystrokes.

JOptionPane List Actions

I want change the icon property of an open JOptionPane upon clicking a list item. (They will correspond with each other)
Is there an equivalent to ActionListener for this? I know how to code for the buttons, unfortunately these actions are not easy?
JOptionPane.showInputDialog(null,
"SELECT A PRIMARY WEAPON FROM THE LIST",
"ARMOURY",
JOptionPane.OK_CANCEL_OPTION,
get.getIcon("shield_and_swords.png"),
character.weaponList(),
"Absolix Polearm")
This is not possible. The JOptionPane.showInputDialog documentation states:
It is up to the UI to decide how best to represent the selectionValues, but usually a JComboBox, JList, or JTextField will be used.
This means the actual GUI element used is implementation-defined and so there couldn't really be a general way to access it, or a consistent action interface to it (it might not even be a clickable list box, for example). Basically, you call showInputDialog() and you get a result back, but beyond that it's a black box and the actual GUI could be anything -- no guarantees are made.
Perhaps you could come up with some really dirty object tree hacks to find the GUI element in most cases, but... consider perhaps creating your own custom dialog with a predictable GUI that you can control instead.

Getting information from a text field JFrame form in a different class

Okay so I'm making a Library admin program and I have created a special frame where the user would enter details about a new book. However my method for adding a new book is in a separate class (methods). My question is how can I get the information the user enters in the text fields? Do I have to use something like getters, or is there an easier way. Also keep in mind that I am using the GUI layout (thing) in netbeans, and that I have already actually made the form. (I know it's frowned upon but I'm pressed for time and this is how we were taught.) This is a school project by the way. Thanks.
Okay so I'm making a Library admin program and I have created a special frame where the user would enter details about a new book.
Usually, a detail window should be a dialog, and likely a modal dialog. I suggest that you display this information in a modal JDialog, not a JFrame. Do this and it will make extracting information from the detail window much easier.
However my method for adding a new book is in a separate class (methods). My question is how can I get the information the user enters in the text fields? Do I have to use something like getters, or is there an easier way.
This begs the question -- what's so hard about using getters? And in fact his is exactly what I suggest that you use! Please note that your question essentially boils down to, "how can I get information on the state of one class's object from within another class's object", and for this getter methods are almost mandatory.
Also keep in mind that I am using the GUI layout (thing) in netbeans, and that I have already actually made the form. (I know it's frowned upon but I'm pressed for time and this is how we were taught.) This is a school project by the way.
This is unrelated to your current problem and should have little effect on its solution other than if you've hard-coded your "form" as a JFrame, then scrap it and re-do it as a JPanel.
I suggest:
Create an addEditBook modal JDialog
Give it getter methods to allow outside classes to be able to query its textfields for their contents.
Display the dialog from the main program.
Since it is modal the main program's code flow will pause until the dialog has been dealt with.
In your OK and Cancel button, set the dialog's state (OK_STATE or CANCEL_STATE) and close the dialog. The easiest way to do this actually is to use a JOptionPane as your modal dialog since it has mechanism for just this sort of thing. This is easily accomplished if your addEditBook is geared to create a JPanel, one that you display in the JOptionPane.
Program flow will then resume in your main program from right after where you showed the dialog
query the dialog for the contents of its fields.
For examples of the JOptionPane solutions, including option panes that request information from multiple fields similar to your window above, please see:
How can I make a JFrame modal like a JOptionPane?
Multiple input in JOptionPane.showInputDialog
Edit
You state in comment:
Oh and I was wondering how can I make the field of a normal JOptionpane input dialogue come up with a word already in it like for editing it will show the information stored already?
Please see the example answers that I have listed above as you'll see that they're not examples of a "normal JOptionPane" but rather JOptionPanes that display a GUI that you create. And just the same as it's easy to query the state of this GUI after it is displayed, it's just as easy to set the state of the GUI via setter methods before it is displayed.
My question is how can I get the information the user enters in the
text fields? Do I have to use something like getters, or is there an
easier way
You need to add actionListeners for you buttons, which means you will be overriding a method called actionPerformed. You basically need to associate your actionListeners with your 'Ok' and 'Cancel' buttons. When the 'ok' button is pressed, you should get a callback in the associated actionPerformed method. Then you should try to fetch the values of your textfiled using the getText method. Collect all the fileds and set the bean you have created to store that data. Then you can call your business logic to save/modify the books info.

Capturing "Tab" key press by both the focused component and its container

Is there a way to propagate a key press from say a JTextField to its container's KeyListener implementation?
So in effect, the keypress would be acted upon by both the text field and the JPanel. Right now the text field is consuming the key press so is nonexistent to the JPanel underneath.
In Swing, the tab key is used to change the focus from one component to another. The article Validating Input discusses InputVerifier, which may help you do what you want.
The question is why do you want to do this? What is your actual requirement as oppose to your attempted solution. Having an event handled by two components is generally not a good idea.
In general you should not use KeyListeners. Swing was designed to use Key Bindings. However, in this case it won't help because as mentioned earlier the focus subsystem handles the tab key.
If this is the only solution to your problem, then I think you can use KeyEventPostProcessor to listen for any KeyEvent. See Global Event Listeners for more info.

Can multiple accelerators be defined for a JMenuItem?

I've a problem with setAccelerator(). Right now, I have the code that works for Ctrl+X for DELETE operation. I want to set the accelerator to Shift+Delete as well for same JMenuItem.
My code as follows:
JMenuItem item = new JMenuItem(menuText);
item.setAccelerator(KeyStroke.getKeyStroke(
KeyEvent.VK_X, KeyEvent.CTRL_MASK));
item.setAccelerator(KeyStroke.getKeyStroke(
KeyEvent.VK_DELETE, KeyEvent.SHIFT_MASK));
but this is working only for Shift+Delete operation. Seems it is overriding the Ctrl+X operation. Can we make both these keystrokes work at the same time?
Please guide.
Yes it can be done. Behind the scenes the setAccelerator() is just creating a Key Binding, however as you noticed the second binding replaces the first.
So, you need to create an Action (not an ActionListener) to add the to the menu item. Read the section from the Swing tutorial on How to Use Actions for more information. Now that you have created the Action, you can share the Action with another KeyStroke by manually creating a Key Binding. You can read the section from the Swing tutorial on How to Use Key Bindings for a detailed explanation. Or you can read my blog on Key Bindings which give some simple code examples.
This second binding will not show up on the menu item itself.
From: http://java.sun.com/j2se/1.4.2/docs/api/java/awt/AWTEvent.html
The masks are also used to specify to which types of events an AWTEventListener should listen.
So you can combine the mask for two keys, but not the KeyEvents.
item.setAccelerator(
KeyStroke.getKeyStroke(
KeyEvent.VK_X, KeyEvent.CTRL_MASK + KeyEvent.SHIFT_MASK));
A workaround solution would be to catch the KeyEvent in the middle (after your component fired it, but before your listeners will act on it) and check, whether its one of the two combinations. Then fire one event, on which you programmatically agree to represent the action you wanted.
The second call indeed overrides the accelerator. If the method starts with set, there will be only one. If the method starts with add, you can have more than one (for example for a number of listeners).
If you want multiple keystrokes to do the same, I think you should add a keyListener to the top frame (or panel, dialog, ...) which invokes the action listeners added to the menuItem.

Categories