I'm trying to use an editable JComboBox such that upon a user typing into the editor, possible results are displayed in the list part of the combo box.
Unfortunately, I've found that upon using either addItem(item) or getModel().addItem(item), the input typed by the user is overwritten by the first value I added. I've considered storing the editor value, adding items, and then using setSelectedItem() to fix this, but I wan't to preserve the state of any selected text/ caret position, and believe this should be something more trivial, but can't for the life of me figure it out.
JComboBox box = new JComboBox();
box.setModel(new MutableComboBoxModel());
box.setEditable(true);
box.getEditor().getEditorComponent().addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
// Actual results are retrieved from server via HTTP
box.addItem("Demo");
// Here, the editor window the user was typing in is replaced with the value "Demo".. how to fix this?
}
});
use AutoComplete JComboBox / JTextField,
for listening in JTextComponent is there DocumentListener,
never use KeyListener for Swing JComponents, this listener is designated for AWT Components, for Swing JComponents is there KeyBindings
You need to implement your own MutableComboBoxModel since DefaultComboBoxModel is responsible for the "add item then auto select it" behavior.
Related
I have two JPanels inside another JPanel. One of them has a JTextField inside, another few JButtons. I want focus to be set on the JTextField every time user starts typing (even when one of the buttons has focus at the moment).
KeyListener won't work, because in order for it to trigger key events, the component it is registered to must be focusable AND have focus, this means you'd have to attach a KeyListener to EVERY component that might be visible on the screen, this is obviously not a practical idea.
Instead, you could use a AWTEventListener which allows you to register a listener that will notify you of all the events been processed through the event queue.
The registration process allows you to specify the events your are interested, so you don't need to constantly try and filter out events which your not interested in
For example. Now, you can automatically focus the textField when a key is triggered, but you should check to see if the event was triggered by the text field and ignore it if it was
One of the other things you would be need to do is re-dispatch the key event to the text field when it isn't focused, otherwise the field will not show the character which triggered it...
Something like...
if (Character.isLetterOrDigit(e.getKeyChar())) {
filterField.setText(null);
filterField.requestFocusInWindow();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
filterField.dispatchEvent(e);
}
});
}
as an example
You need to attach a KeyListener to all controls in your JPanel, with a reference to the JTextField you want to focus like so:
panel.addKeyListener(new KeyPressedListener(yourTextField));
button1.addKeyListener(new KeyPressedListener(yourTextField));
button2.addKeyListener(new KeyPressedListener(yourTextField));
class KeyPressedListener implements KeyListener
{
private JTextField textFieldToFocus;
public KeyPressedListener(JTextField textFieldToFocus)
{
this.textFieldToFocus = textFieldToFocus;
}
#Override
public void keyPressed(KeyEvent e) {
textFieldToFocus.requestFocus();
}
}
This is in the constructor of a JPanel but it does not print anything when I press "h". If more code is needed, I can provide it. Thank you!
String hide = "hide";
this.getInputMap().put(KeyStroke.getKeyStroke('h'), hide);
this.getActionMap().put(hide, new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("HIDDEN");
if (isHidden){
slide.setVisible(true);
}else{
slide.setVisible(false);
}
}
});
this.getInputMap()....
You are trying to add the bindings to the default InputMap, which is the InputMap when the component has focus. By default a JPanel does not have focus.
You should try using one of the other InputMaps by using the getInputMap(int) method. Or you will need to make the panel focusable and give it focus.
Read the Swing tutorial on How to Use Key Bindings for more information on the proper variables to use to specify the desired InputMap.
I have some difficulties with setting a shortcut to my dynamically added buttons. Buttons are on dynamically added panel. I want to add keyboard shortcuts to these buttons, like so:
ctrl+1 -> button1
ctrl+2 -> button2
etc.
Buttons are added by an algorithm, so I don't know how many of them there will be(min 0, max 5). I would like to call these buttons with Global (working in whole panel) keyboard shortcuts. I am wondering how to achieve this, when the text on my button is made dynamically like this:
getNewAmountQueryButton(label)
which makes this:
private JButton getNewAmountQueryButton(final Decimal label) {
JButton temp = new JButton(label.toString());
...
I tried adding keylistener but it works only when I have a focus on a button:
button.addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(final KeyEvent e) {
#Override
public void run() {
if ((e.getKeyCode() == getKeyCode()) && ((e.getModifiers() & InputEvent.CTRL_MASK) != 0)) {
model.setAmount(model.getAmount().add(label));
field().selectAll();
refreshDisplay();
}
}
});
});
Do you know how can I do this? I wanted to add listener to top-level panel, but as I use model.setAmount(model.getAmount().add(label));to refresh some textField it is impossible due to lack of this label parameter.
Any idea?
Thanks in advance!
It is recommend that you use Key Bindings.
Bascially, they don't suffer from the same focus issues as KeyListeners
Use Action to encapsulate each button's behvior. You can specify the desired MNEMONIC_KEY, as shown here, and you can add a binding to the ACCELERATOR_KEY, as shown here.
I have a JFrame with multiple panels that accumulates in a fairly complex Swing UI. I want to add Keyboard support so that regardless of component focus a certain Key press, for example the [ENTER] key, causes a listener to react.
I tried adding a KeyListener to the JFrame but that doesn't work if another JComponent is selected which changes focus.
Is there a proper way to do this?
Registering a KeyEventDispatcher with the KeyboardFocusManager allows you to see all key events before they are sent to the focused component. You can even modify the event or prevent it from beeing delivered to the focused component:
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(
new KeyEventDispatcher() {
public boolean dispatchKeyEvent(KeyEvent e) {
//Get the char which was pressed from the KeyEvent:
e.getKeyChar();
//Return 'true' if you want to discard the event.
return false;
}
});
If you just want to get the key inputs for one window / component or just for specific keys, you can use KeyBindings as kleopatra suggested. As an example on how to register to the keyboard event on Enter pressed (You may use any VK_ provided by KeyEvent, for modifiers [alt, ctrl, etc.] see InputEvent) see:
JFrame frame = new JFrame(); //e.g.
JPanel content = (JPanel)frame.getContentPane();
content.getInputMap().put(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_ENTER,0),"enterDown");
content.getActionMap().put("enterDown",new AbstractAction() {
private static final long serialVersionUID = 1l;
#Override public void actionPerformed(ActionEvent e) {
//This action is called, as the Enter-key was pressed.
}
});
The way I do it is to make the JFrame focusable and append the listener to it. Then, iterate through all the JFrame children and make everything else not focusable.
Of course this only works if you don't have text boxes or similar as they will become non editable.
I have a GUI designed in Swing with all of the Components laid out. For example I have a JComboBox with a JList and a JTextField,
When I select a different item from the JComboBox I am trying to use a ListSelectionListener to call a method in a subclass to update the JTextField based on the choice,
How would I go about doing that properly? How do I call the subclass and then from the subclass update the GUI object's value?
public class Parent {
private void init() {
// ...
combo.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Object selected = combo.getSelectedItem();
textField.setText(getTextBasedOnSelection(selected));
}
});
// ...
}
/**
* Returns the text to display when the given object is selected.
* Subclasses may override this method to display what they want
*/
protected String getTextBasedOnSelection(Object selected) {
return selected.toString();
}
// ...
}
I hope I get your problem right. You have a View Component with several subviews and you want to update one because of the changes done inside the other one.
Therefore you write an action listener for your combobox in the main View:
comboBox.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent arg0) {
textField.setText(comboBox.getSelectedItem());
}
});
Instead of inter-connecting components directly, I recommend to apply the Mediator pattern:
Create a subclass of JPanel (e.g. XyzPane) where you put all your components in. This class becomes the Mediator. It
listens for events of its components
updates the components as needed
fires its own events, if needed (this allows it to be a part of a parent Mediator: grouping components in Panes and then nesting the Panes)