JComboBox actions - java

Is there a way to distinguish between a JComboBox's index being changed programatically using setSelectedBoundValue and by clicking on the JComboBox?

This is ugly and truly a hack, but works!
The ActionEvent contains a field modifiers which in this case is the mouse button id. So using that may help you distinguish between setSelectedIndex or setSelectedValue and mouse clicks (by the way setSelectedBoundValue is not a method on JComboBox):
box.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getModifiers() != 0) {
// ~ mouse button pressed ;)
}
}
});

setSelectedBoundValue
Never heard of that method?
Is there a way to distinguish between a JComboBox's index being changed programatically
Not really. You can remove the listener:
comboBox.removeActionListener(...);
comboBox.setSelectedItem(...);
comboBox.addActionListener(...);
You can set your own class variable.
manualSelection = true;
comboBox.setSelectedIndex(...);
manualSelection = false;

Related

ComboBox SAME item selected action listener

A combo box will fire an event if a DIFFERENT value is selected. I want to be also be able to listen to the SAME item being selected (that is, valueProperty has no change). There seems to be no way to do this.
I tried extending the ComboBox and finding a way to listen for the little popup menu being closed, but I don't even have access to that! What can I do?
Here is what I was trying:
class ResponsiveComboBox<E> extends ComboBox<E> {
public ResponsiveComboBox() {
super();
assert getContextMenu() != null; //Asssertion failed!
this.getContextMenu().setOnHiding((WindowEvent event) -> {
fireEvent(new ActionEvent());
});
}
}
comboBox.showingProperty().addListener((obs, wasShowing, isShowing) -> {
if (! isShowing) {
System.out.println("Combo box popup hidden");
}
});
This event handler might be triggered before the value is changed.

Disable up and down arrow buttons on JSpinner

I have a JSpinner on which I would like to take control of when editing is enabled. It's easy enough with the keyboard, but how about those little arrow widgets at the side? I can't even find references to them in the JSpinner source or any of its enclosed classes.
You can use setUI() method to hide Jspinner arrow.
public void hideSpinnerArrow(JSpinner spinner) {
Dimension d = spinner.getPreferredSize();
d.width = 30;
spinner.setUI(new BasicSpinnerUI() {
protected Component createNextButton() {
return null;
}
protected Component createPreviousButton() {
return null;
}
});
spinner.setPreferredSize(d);
}
As you see, just make createNextButton() and createPreviousButton() return null.
Because we used a BasicUI so we have to setup Spinner size again. I used PreferredSize.
you can't take control of these two arrow buttons but you can do like this
private void buttonActionPerformed(java.awt.event.ActionEvent evt) {
p.setEnabled(false);
}
suppose you want a button pressed and the user will not able to use jspinner at all this is a hint for more actions you can modified it as well
you can also allow use to use the jspinner untill for a specific value using
if(spinner.getValue()==10){
//show error message and
spinner.setEnabled(false);
}
If the UI class used derives from BasicSpinnerUI, the arrow buttons can be removed with:
for (Component component : spinner.getComponents()) {
if (component.getName() != null && component.getName().endsWith("Button")) {
spinner.remove(component);
}
}

Can I call ActionPerformed method from an Event Handler class for JButton?

I have a JButton titled "select"
In the class that creates that JButton and other classes, I want to use an if condition with ActionPerformed method.
Something like(pseudo-code)
if(_selectListener.actionPerformed(ActionEvent)) { //i.e., if select Button is clicked,
//do something
}
Is this possible?
I want to call this method because I have to handle a situation in which a player should be able to choose something by clicking "select" button, or another "scroll" button, and I want to control it using something similar to a bunch of if statements like the one above.
If it is possible, what is the syntax for it? What is the argument ActionEvent?
Thank you!
The easiest and cleanest way is to add a dedicated, specific action listener to each button. That way, when the actionPerformed() method is called, you're sure that the associated button has been clicked, and don't need to test which button has been clicked:
selectButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// handle click on select button
}
});
scrollButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// handle click on scroll button
}
});
Another way is to use a common ActionListener, and use the getSource() method of ActionEvent to know which component triggered the event. Compare the result with each potential button to determine which is the one that has been clicked:
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == selectButton) {
// handle click on select button
}
else if (e.getSource() == scrollButton) {
// handle click on scroll button
}
}
What is the argument ActionEvent?
The answer is in the documentation. Read it.
no you cant call, if needs boolean expression/value, but this method returns void.

How to make JComboBox selected item not changed when scrolling through its popuplist using keyboard

I have a JComboBox component in the panel and ItemListener attached to it. But it gets fired after every up/down keypress (when scrolling though opened popup list). I want to change the selected value after the user accepts selection by pressing for example Enter key.
This is not a case when using mouse. When I move mouse over the combobox's list the highlight follows mouse pointer, but selected item is not changed until I press the mouse button. I would like to have the same behavior for keyboard, i.e. moving highlight via up/down arrow does not change selected item, but pressing Enter does.
I believe you should be able to do:
comboBox.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);
after you have created your comboBox instance to get this functionality
In Java 8 they have fixed this behaviour, but only trigger if u set one UI property
UIManager.getLookAndFeelDefaults().put("ComboBox.noActionOnKeyNavigation", true);
the JComboBox.isTableCellEditor method works for arrow movement through the list, but does not work for type-ahead supported by the KeySelectionManager. i.e. you still get ActionEvents for every non-navigation key the user types, as the JComboBox interprets those characters for searching though the model to move to (or move close to) the user's intended selection.
this solution has a drawback in that it changes the action command for mouse clicks, which was a OK compromise for me because the the flow of the GUI forces the user to change the focus away from the combo box
I ended up making a special KeyListener, that relys on changing the combo box's default action command from comboBoxChanged to comboBoxMovement. Here's the line of code I need after my combo box is all initialized:
setExplicitSelectionManager(myComboBox);
... and here is the method and its contained class that do all the work:
private void setExplicitSelectionManager(JComboBox comboBox) {
class ExplicitSelectionManager implements KeyListener, FocusListener {
private JComboBox src;
private KeyListener superKeyListener;
ExplicitSelectionManager(JComboBox src) {
this.src = src;
// we like what the default key listener does, but not the action command
// it uses for ActionEvents it fires for plain text type-ahead characters
this.superKeyListener = src.getKeyListeners()[0]; // we only have one
src.removeKeyListener(superKeyListener); // will be replace right away, below
}
#Override
public void keyTyped(KeyEvent e) {
// basic combo box has no code in keyTyped
}
#Override
public void keyPressed(KeyEvent e) {
// in the default JComboBox implementation, the KeySelectionManager is
// called from keyPressed. I'm fine with the implementation of
// the default, but I don't want it firing ActionEvents that will cause
// model updates
src.setActionCommand("comboBoxMovement");
this.superKeyListener.keyPressed(e);
src.setActionCommand("comboBoxChanged");
if (e.getKeyCode() == 10) {
src.setSelectedIndex(src.getSelectedIndex());
}
}
#Override
public void keyReleased(KeyEvent e) {
// basic combo box has no code in keyReleased
}
#Override
public void focusGained(FocusEvent e) {
}
#Override
// this will also give us the event we want, if the user decides to Tab out of
// the combo box, instead of hitting Enter
public void focusLost(FocusEvent e) {
src.setSelectedIndex(src.getSelectedIndex());
}
}
ExplicitSelectionManager newSelectionManager = new ExplicitSelectionManager(comboBox);
comboBox.addKeyListener(newSelectionManager);
comboBox.addFocusListener(newSelectionManager);
}
... and here's the action performed method
private void comboBoxActionPerformed(java.awt.event.ActionEvent evt) {
JComboBox source = (JComboBox) evt.getSource();
// "comboBoxChanged" is the default,
// so any normal JComboBox can also use this action listener
if (evt.getActionCommand().equals("comboBoxChanged")) {
updateModel(source.getName(), (String) source.getSelectedItem());
}
}
Its the expected behavior with the ItemListener. whenever the displayed value changes the event is fired. For your requirement use an ActionListener.

Remove the listener for defaultButton in java

i have a Jframe application with the defaultbutton set to btnClose_ (Close Button: this button closes the window).
I have 2 textfields that must also fire an event when user clicks the Enter key on the textfields. What happens is that when I press the Enter key while the cursor is on the textfield, the event on the Close button is fired causing the window to close.
Is it possible to remove the listener of the default button if the Enter key is pressed on the textfield? Here's my code for the textfield listener
/**
* Receives the two textfield instance
*/
private void addFilterListener(JTextField txf) {
txf.addKeyListener(new KeyAdapter() {
/**
* Invoked when a key has been pressed.
*/
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
ActionListener al = btnClose_.getActionListeners()[0];
btnClose_.removeActionListener(al);
btnFilter_.doClick();
e.consume();
btnClose_.addActionListener(al);
}
}
});
}
private JButton getBtnClose(){
if(btnClose == null){
btnClose.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
getWindow().dispose();
}
});
}
return btnClose;
}
}
Where to start?
The first thing that springs out at me is the bad variable names. txf? What's wrong with proper words? textField or field, say. Or much better, a name descriptive of its purpose, not what it is.
Secondly, the first comment is wrong (not uncommon) and the second comment is redundant (already specified in the KeyListener interface, you don't need to try and half-heartedly specify it again).
Next up, low level key listeners tend not to work so well on Swing components (JComboBox being the most notorious example - it typically is implemented with child components). In general you can use JComponent.registerKeyboardAction (the API docs says this is obsolete but not deprecated, and to use more verbose code). For text components, you often want to play with the document (typically through DocumentFilter). In this particular case, looks like you just want to add an ActionListener.
Now doClick. It's a bit of an evil method. For one thing it blocks the EDT. It is probably the easiest way to make it look as if a button is pressed. From a programming logic point of view, it's best to keep away from modifying Swing components, when you can keep everything in your abstracted code.
Removing and adding listeners from components is generally a bad idea. Your code should determine what to do with an event including whether to ignore it. Do that at an appropriate point when handling the event. Don't duplicate state unnecessarily.
A potential issue is that the code seems to assume that there is precisely one action listener. There could be others. The code is not robust under unexpected behaviour. Set your components up at initialisation time, and you shouldn't need to refer to them again.
As far as I understood your question, you want that buttonClick should not get fired if Enter is pressed .
This won't fire doClick() if enter is pressed
if (e.getKeyCode() != KeyEvent.VK_ENTER) {
btnFilter_.doClick();
}
In the ActionListener of the close button, assuming you can change its code, don't close if one of the text fields have the focus.
public void actionPerformed(ActionEvent e) {
if (field1.hasFocus() || field2.hasFocus())
return; // don't close if text field has focus
frame.dispose();
}
If you can not change the ActionListener of the close button, add a FocusListener to the text fields. If one of them gets the focus, remove the default button. If the text field lost the focus, reset the default button.
FocusAdapter listener = new FocusAdapter() {
#Override
public void focusGained(FocusEvent e) {
frame.getRootPane().setDefaultButton(null);
}
#Override
public void focusLost(FocusEvent e) {
frame.getRootPane().setDefaultButton(close);
}
};
field1.addFocusListener(listener);
field2.addFocusListener(listener);
This should be better than depending on the listeners being called in the correct sequence - it is of no avail to remove the listener if it was already called...

Categories

Resources