Allow user to redefine hotkeys for Swing during runtime Java - java

I have a Java application that contains a lot of features, and to make life easier for the user, I have set up numerous mnemonics and accelerators. For instance, I have a JMenuItem that allows the user to save the state of the application, witht he following code:
JMenuItem saveItem = new JMenuItem("Save");
saveItem.setMnemonic('S');
saveItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_MASK));
This works as desired, but now I would like to give the user an option to change the hot keys. While CTRL + s would seem like a fairly obvious hot key to stick with, there are many features that use these short cuts, and simply picked Save as an example.
I have a JButton that I have arranged for testing purposes that allows the user to enter in a new shortcut when clicked. I was thinking that I would simply try and capture the keys that the user holds down (InputEvent) and presses (KeyEvent). I also though it might be smart to force the use of an InputMask to avoid complications in Text Fields and the like.
What I am wondering is: What is the best way to capture the new input that the user enters? I have looked up information regarding KeyBindings and they look right for the job, but the main issue I see is actually capturing the keys and saving them.

Sounds like you need to setup a KeyListener. When the user presses/releases a key, it triggers a KeyEvent from which you can retrieve the main key pressed (e.g. S) and the mask/modifiers (e.g. CTRL+SHIFT).
From there you can create a KeyStroke object and set this as the new accelerator of your menu.
public void keyReleased(KeyEvent e){
KeyStroke ks = KeyStroke.getKeyStroke(e.getKeyCode(), e.getModifiers());
menuItem.setAccelerator(ks);
}
The thing is you probably want this key listener to be removed right after the key released event, to avoid multiple keystrokes to be captured. So you could have this kind of logic:
JButton captureKeyButton = new JButton("Capture key");
JLabel captureText = new JLabel("");
KeyListener keyListener = new KeyAdapter(){
public void keyReleased(KeyEvent e){
KeyStroke ks = KeyStroke.getKeyStroke(e.getKeyCode(), e.getModifiers());
menuItem.setAccelerator(ks);
captureText.setText("Key captured: "+ks.toString());
captureKeyButton.removeKeyListener(this);
}
};
ActionListener buttonClicked = new ActionListener(){
public void actionPerformed(ActionEvent e){
captureKeyButton.addKeyListener(keyListener);
captureText.setText("Please type a menu shortcut");
}
};
captureKeyButton.addActionListener(buttonClicked);

Related

How to kill a program with esc or a button Java

I want my program to run but once esc is pressed to quit the program. The only way I can think of doing this is by doing a scanner and looking for the next line but that pauses the whole program. Maybe a key listener but how do I make it be constantly checking? And it is a GUI. Any help would be great!
static Scanner sc = new Scanner(System.in);
stop = sc.nextLine();
if (stop.equals(a)){
running = false;
}
else{
do program
}
If u use a frame you can register the keys.
myFrame.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "EXIT");
myFrame.getRootPane().getActionMap().put("EXIT", new AbstractAction(){
public void actionPerformed(ActionEvent e)
{
myFrame.dispose();
}
});
If this is a UI, you should not be maintaining any kind of loop that could block the Event Dispatching Thread.
The EDT will dispatch key events to your program and you can respond to them if you have registered for notifications.
I would avoid KeyListener as it requires the component it is registered to be focused and have keyboard focus before it will respond.
Instead, I would use the Key Bindings API.
You can register a Escape key to either the main application window (or sub component) or directly with the JButton you are using to close the application with.

How to catch Enter key and change event to Tab in Java

I have a swing application with multiple jtextfield on it. How do you replace the function of the enter key wherein when you press the Enter key, it will transfer to the nextfocusable component just like the tab key? I dont want to put a keylistener on each jtextfield.
You're looking for Container.setFocusTraversalKeys:
Container root = ...
// pressed TAB, control pressed TAB
Set<AWTKeyStroke> defaultKeys = root.getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
// since defaultKeys is unmodifiable
Set<AWTKeyStroke> newKeys = new HashSet<>(defaultKeys);
newKeys.add(KeyStroke.getKeyStroke("pressed ENTER"));
root.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, newKeys);
For more information, take a look at the Focus Subsystem tutorial.
You can call:
KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
manager.focusNextComponent();
but you will have to register a single ActionListener with all your JTextFields.

Pull down searching window in Java

I have to create a searching window, like a google browser window. It must have a pull down list containing similar results, which is populated from a database.
I am trying to adjust a JCombobox but this has caused ​​me a lot of trouble. Is there a better way to do this? (Perhaps something like this already exists in Java.) If not, can anyone advise me on how to achieve my goal?
create JTextField with keyboard event to show the popup window on key realeased,
Example:
jTextField2.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyReleased(java.awt.event.KeyEvent evt) {
showPopup(evt);
}
});
void showPopup(java.awt.event.KeyEvent evt) {
JPopupMenu popup = new JPopupMenu();
popup.setLightWeightPopupEnabled(false);
popup.setBorder(BorderFactory.createLineBorder(Color.black));
popup.setLayout(new BorderLayout());
popup.setSize(this.getPreferredSize());
popup.setPreferredSize(this.getPreferredSize());
popup.pack();
popup.setOpaque(false);
// create panel that contains the search result
popup.add(BorderLayout.CENTER, <YOUR PANEL WITH THE RESULT>);
popup.setPreferredSize(new Dimension(jTextField2.getWidth(),250));
<SEARCH PANEL>.setPreferredSize(new Dimension(jTextField2.getWidth(),250));
popup.show(jTextField2, 0, jTextField2.getHeight());
}
i have to do searching window like google browser window. It must have pull down list with similarities results that comes from database. I trying to adjust JCombobox but this made ​​me a lot of trouble.
Maybe not true, I'd to use AutoComplete JComboBox / JTextField

How do I change the value of a JOptionPane from a PropertyChangeListener without triggering the listener?

I am trying to make a program to manage a group of sports players. Each player has an enum Sport, and SportManager has convenient factory methods. What I am trying to do is open a dialog that has a JTextField for a name and a combo box to choose a sport. However, I want to stop the user from closing the dialog while the text field is blank, so I wrote a PropertyChangeListener so that when the text field is blank, it would beep to let the user know. However, if the user puts in something in the text after setting off the beep, it doesn't trigger the listener and you can't close the dialog without pressing cancel because the value is already JOptionPane.OK_OPTION, and cancel is the only way to change JOptionPane.VALUE_PROPERTY. So I tried to add
message.setValue(JOptionPane.UNITIALIZED_VALUE);
within the listener. However this just closes the window right away without giving the user a chance to fill in the text field, presumably because it triggers the listener I just registered. How do I make it so that it will beep more than once and give the user a chance to fill in the field?
FYI newPlayer is the component I'm registering the action to.
Code:
newPlayer.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
Object[] msg = new Object [4];
msg[0] = new JLabel("Name:");
final JTextField nameField = new JTextField();
msg[1]=nameField;
msg[2] = new JLabel("Sport: ");
JComboBox<Sport> major = new JComboBox<Sport>(SportManager.getAllSports());
msg[3]=major;
final JOptionPane message = new JOptionPane();
message.setMessage(msg);
message.setMessageType(JOptionPane.PLAIN_MESSAGE);
message.setOptionType(JOptionPane.OK_CANCEL_OPTION);
final JDialog query = new JDialog(gui,"Create a new player",true);
query.setContentPane(message);
query.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
message.addPropertyChangeListener(
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
String prop = e.getPropertyName();
if (query.isVisible()&& (e.getSource() == message)&& (prop.equals(JOptionPane.VALUE_PROPERTY))) {
if(nameField.getText().equals("")&&message.getValue().equals(JOptionPane.OK_OPTION)){
Toolkit.getDefaultToolkit().beep();
message.setValue(JOptionPane.UNINITIALIZED_VALUE);
return;
}
query.dispose();
}
}
});
query.pack();
query.setVisible(true);
if(Integer.parseInt(message.getValue().toString())==JOptionPane.OK_OPTION){
players.add(new Player(nameField.getText(),(Sport)major.getSelectedItem()));
edited=true;
}
gui.show(players);
}
});
I don't think you can do it with JOptionPane but you can using using TaskDialog framework and few others.
You can also create a dialog yourself, attach change listeners to your fields and enable/disable OK button based on content of your fields. This process is usually called "form validation"
However, I want to stop the user from closing the dialog while the
text field is blank
I get where you are going, but Java Swing is not very good at this. There is no way you can prevent the listener from being called. A solution would be to ignore the call, but this is complicated to implement.
The way I solved this issue is to let the pop-up disappear, check the returned value and if it is null/empty, beep and re-open it until user fills something.
JOptionPane does not internally support validation of inputs (Bug Reference). Your best bet is to create your own custom JDialog which supports disabling the OK button when the input data is invalid.
I'd recommend reading the bug report since other people talk about it and give workarounds.
However, I want to stop the user from closing the dialog while the text field is blank
The CustomDialog example from the section in the Swing tutorial on Stopping Automatic Dialog Closing has a working example that does this.
After taking a quick look at your code and the working example I think your code should be something like:
if (query.isVisible()
&& (e.getSource() == message)
&& (prop.equals(JOptionPane.VALUE_PROPERTY)))
{
if (message.getValue() == JOptionPane.UNINITIALIZED_VALUE)
return;
if (nameField.getText().equals("")
&& message.getValue().equals(JOptionPane.OK_OPTION))
{
Toolkit.getDefaultToolkit().beep();
message.setValue(JOptionPane.UNINITIALIZED_VALUE);
}
else
query.dispose();
}
Otherwise, I'll let you compare your code with the working code to see what the difference is.
One way to solve this problem is to add a Cancel and Ok button to your dialog. Then, disable closing the popup via the X in the corner, forcing the user to click either Cancel or Ok to finish/close the dialog. Now, simply add a listener to the text field that will disable the Ok button if the text field is blank.
Judging from your code I assume you can figure out how to implement these steps, but if you have trouble let us know! Good luck!

How to process forms in Java?

Using Swing in Java I wrote a form containing radio buttons, text fields and so on. In the very end I have a "Submit" button.
Now I want to "send" the information given by the user to the program. How do I do that? Is there a good tutorial about that?
Is it kind of similar to PHP? (I am asking just because I know how to do it in PHP. To avoid confusions I probably need to mention that I do NOT program a web application).
Processing data in Swing is way different from the typical web REQUEST/RESPONSE paradigm.
To Take something you may know, it's more in the fashion of Javascript actions in an HTML page : each time user performs an operation, one or more events are sent, and the application developper can update application content according to it.
In your case, if you register an ActionListener to the button, it will be called each time button is clicked. You'll then have the possibility to perform any operation you want.
But that's not all !
Each time a component is keyboard focused, or receives the mouse, events are sent, as well as when a key is stroked or when widget's model is updated.
I would really suggest you to read documents such as Swing tutorial (which dives in greater details than I could do in 1 month).
Not completely sure what you mean by "send to the program". You are in the program so I assume that you have a dialog that renders this form? Just pass the dialog the object that you want to use to store the data. For example, your dialog's constructor can take an argument.
public class MyDialog extends JPanel {
private UserInfo userInfo;
private JTextField name;
/**
* The main area of the dialog.
*/
protected JPanel panel;
public MyDialog(UserInfo userInfo) {
this.userInfo = userInfo;
}
public showDialog() {
// Some code to create the form which it looks like you already know how to do
// Create a name field
JLabel nameLabel = new JLabel("Name:");
panel.add( nameLabel );
JButton submit = new JButton("Submit");
submit.addActionListener( new ActionListener() {
public void actionPerformed (ActionEvent event)
{
this.userInfo.setName(name.getText().trim());
} } );
panel.add( submit );
}
}

Categories

Resources