JComboBox - disable setSelectedItem from calling ItemStageChange - java

I have a JComboBox and it has an associated itemStageChanged method. The JComboxBox is updated in two ways:
I call comboBox.setSelectedItem(...)
The user selects an item in the comboBox via my GUI
I want only (2) to initiate an event. What method (e.g., actionPerformed? changeListener? itemListener? etc) should I use that will only catch (2) and not (1). Currently, itemStateChanged (even with an if statement to check if it is ItemEvent.SELECTED) is being called by (1) and (2).
class ItemChangeListener implements ItemListener{
#Override
public void itemStateChanged(ItemEvent event) {
if (event.getStateChange() == ItemEvent.SELECTED) {
//gets in here if user selects an item with their mouse
//or if setSelectedItem is called
}
}
}

Give this a try:
Boolean flag = false;
class ItemChangeListener implements ItemListener{
#Override
public void itemStateChanged(ItemEvent event) {
// Condition for the desired event
if (!flag && event.getStateChange() == ItemEvent.SELECTED) {
Object item = event.getItem();
// do something with object
}
}
}
[...]
//Add the listener
myComboBox.addItemListener(new ItemChangeListener());
[...]
// Setting the selection
flag = true;
comboBox.setSelectedItem(...)
flag = false;
Taken from here.

Related

Detect if JSpinner change comes from typing value or clicking on arrow

When I receive a ChangeEvent from my JSpinner, I'd like to detect if user used the arrows to increase/decrease the number value, or directly typed a new number.
What would be the best approach to do this ?
EDIT: for now my non-reliable solution is just to save the last JSpinner changed value, and if new change value is +/- equals to the step value, then I assume user clicked on an arrow. It works except if user typed a value which is equals to (oldValue +/- step).
EDIT: why ?
I want to reproduce the behavior found in Midi editors of several famous DAWs. The JSpinner represents the velocity (0-127) of selected notes. It shows the velocity of the first selected note. Usually notes velocity differ. When you increase with arrow, you want to increase all selected notes by the same amount. When you type in a new value, you want all velocities to be reset to this value.
Distinguishing the trigger of a value change is not supported - the only value-related event fired by JSpinner is a ChangeEvent which carries no state except the source. We need another type of listener or a combination of listeners.
First thought: listen to changes of the editor's textField, f.i. an actionListener or a propertyChangeListener on the value property. This doesn't work, mainly because
both change- and propertyChangeListener are fired always (change before property)
actionListener is not fired on focusLost
Second thought: go dirty and dig into implementation details to hook into the action fired by the arrow buttons.
The idea:
look up the action for increment/decrement from the spinner's actionMap: this is the same as the arrows' actions and also used by up/down keys (which I assume not counting a "editing")
for each, create a wrapper that sets a flag before delegating to super
put that wrapper into the spinner's actionMap
look up the arrow buttons in the spinner's children and replace their respective actionListener with the wrapper
Client code would change the tweak's changeListener to acts according to the flag as appropriate.
Some code doing the tweaking (beware: not formally tested!):
public static class SpinnerTweaker {
private JSpinner spinner;
private boolean wasButtonAction;
private Object oldValue;
public SpinnerTweaker(JSpinner spinner) {
this.spinner = spinner;
AbstractAction incrementDelegate = createDelegate("increment");
spinner.getActionMap().put("increment", incrementDelegate);
AbstractAction decrementDelegate = createDelegate("decrement");
spinner.getActionMap().put("decrement", decrementDelegate);
// replacing arrow button's action
Component[] components = spinner.getComponents();
for (Component component : components) {
if (component instanceof JButton) {
if (component.getName() == "Spinner.nextButton") {
ActionListener[] actions = ((JButton) component).getActionListeners();
ActionListener uiAction = actions[0];
((JButton) component).removeActionListener(uiAction);
((JButton) component).addActionListener(incrementDelegate);
}
if (component.getName() == "Spinner.previousButton") {
ActionListener[] actions = ((JButton) component).getActionListeners();
ActionListener uiAction = actions[0];
((JButton) component).removeActionListener(uiAction);
((JButton) component).addActionListener(decrementDelegate);
}
}
}
spinner.addChangeListener(e -> {
if (wasButtonAction) {
System.out.println("value changed by button: " + spinner.getValue());
} else {
System.out.println("value changed by editing: " + spinner.getValue());
}
wasButtonAction = false;
});
}
protected AbstractAction createDelegate(String actionCommand) {
// hooking into original button action to set button flag
AbstractAction action = (AbstractAction) spinner.getActionMap().get(actionCommand);
AbstractAction delegate = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
oldValue = spinner.getValue();
wasButtonAction = true;
action.actionPerformed(e);
// hit min/max - TBD: needs testing!
if (oldValue.equals(spinner.getValue())) {
wasButtonAction = false;
}
}
};
return delegate;
}
}
#kleopatra solution works but I found a simpler solution.
The trick is that commitEdit() is only called internally by JSpinner when change results from the increment or decrement action.
public class Spinner2 extends JSpinner
{
// To be checked by ChangeListener after receiving the ChangeEvent
public boolean wasManualEdit=true;
#Override
public void commitEdit() throws ParseException
{
wasManualEdit = false;
super.commitEdit();
}
#Override
protected void fireStateChanged()
{
super.fireStateChanged();
wasManualEdit = true;
}
}

selected item in combobox not printing out when selected

I'm doing this project and it has I'm trying to print out the selected item in the combo box but it's not working. Just wanting to know why it is not printing out properly. trying to print "eric white"
public void subList() {
//sets up sub list based on selection in managerbox
cboManager.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
if(e.getStateChange() == ItemEvent.SELECTED) {
Object selected = cboManager.getSelectedItem();
if (selected.equals("Eric White") ) {
System.out.println("eric white");
}
}
}
});
}
Check whether the item listed in combo box is exactly "Eric White", because equals will look for exact string including space and case sensitive.
I usually use ActionListener. Prepare for null value and case sensitivity.
public void subList() {
//sets up sub list based on selection in managerbox
cboManager.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Object selected = cboManager.getSelectedItem();
if (selected != null && selected.equalsIgnoreCase("Eric White") ) {
System.out.println("eric white");
}
}
});
}

Event handling in Java (JTree + JButton)

private void createEvents()
{
menuFileExit.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent arg0)
{
System.exit(0);
}
});
////// Events on tree selection
jtStoryViewer.addTreeSelectionListener(new TreeSelectionListener()
{
public void valueChanged(TreeSelectionEvent arg0)
{
DefaultMutableTreeNode selection = (DefaultMutableTreeNode) jtStoryViewer.getLastSelectedPathComponent();
Object nodeObject = selection.getUserObject();
////// Checks if selected node is a String (only story title is a string)
if(selection.getUserObject().getClass().getName() == "java.lang.String" )
{
tfTitle.setText(nodeObject.toString());
////// Action listener for Change Button
btnChange.addActionListener(new ActionListener()
{
////// Title text swap
public void actionPerformed(ActionEvent arg0)
{
selection.setUserObject(tfTitle.getText());
((DefaultTreeModel)jtStoryViewer.getModel()).nodeChanged(selection);
}
});
}
///// checks if the object is a chapter object
if(selection.getUserObject().getClass().getName() == "ISW.common.Chapter")
{
Chapter chapter = (Chapter) selection.getUserObject();
tfTitle.setText(chapter.toString());
////// Action listener for Change Button
btnChange.addActionListener(new ActionListener()
{
////// Title text swap
public void actionPerformed(ActionEvent arg0)
{
chapter.setTitle(tfTitle.getText());
((DefaultTreeModel)jtStoryViewer.getModel()).nodeChanged(selection);
}
});
}
}
});
}
I am using JTree to display and modify some objects. I added a TreeSelectionListener to get the object data on selection. For now I want to be able to change the title of an object, it works fine on first selection on the tree , I change the value in the text box and the "Change" button works just fine, but when I move on to next objects, the change button also modifies the value of all previously selected objects.
I guess it is caused due to my improper usage of the ActionListeners but I can't tell for sure and at this point I'm stuck.
Will be grateful for any hints.
Don't keep adding an ActionListener to the btnChange JButton within the TreeSelectionListener#valueChanged method.
This will cause the button to call EVERY ActionListener you have previously
Instead, give the btnChange a single ActionListener, when clicked, can act on the currently selected node (by checking the JTree it self). You could have the TreeSelectionListener#valueChanged method enable or disable the btnChange based on the validity of the selection
Also, if(selection.getUserObject().getClass().getName() == "ISW.common.Chapter") isn't how String comparison is done in Java, instead you should use something more like if("ISW.common.Chapter".equals(selection.getUserObject().getClass().getName()))

Java - JComboBox Invalidade Item Selection in ItemListener

I am trying to add a condition inside my ItemListener and only if the condition is verified the item gets selected, otherwise I dont want the user to be able to select that item.
How can I invalidade a selection on item listener? Make a new selection inside the item listener? won't that be a infinite loop? :o
Thanks alot in advance.
Here is my code:
private final class classeComboBoxItemListener implements ItemListener {
#Override
public void itemStateChanged(ItemEvent e) {
try {
if(e.getStateChange() == ItemEvent.DESELECTED)
updateLabelLugares(true, (Classe) e.getItem());
if(e.getStateChange() == ItemEvent.SELECTED)
updateLabelLugares(false, (Classe) e.getItem());
} catch (Exception e1) {
/// HERE I WANT TO INVALIDATE THE SELECTION
/// Returning to the item selected before!
}
}
}
How can I invalidade a selection on item listener? Make a new
selection inside the item listener? won't that be a infinite loop? :o
remove ItemListener from JComboBox, then call JComboBox.setSelectedIndex(-1), add ItemListener back to JComboBox (standard and good practicies)
create two void (standard and good practicies) in one add listener, in second remove listener
don't wrap if(e.getStateChange() == ItemEvent.DESELECTED) inside boolean for the reason, to block code executions untill reset status ended
use if - else for if(e.getStateChange() == ItemEvent.DESELECTED){ .... } else { ... }

method getSelectionIndex() in ListSelectionListener

For example, I have a JList named across_list that containing a list of items and now I add a ListSelectionListener to that JList
Considering these lines of code:
class AcrossListHandler implements ListSelectionListener {
#Override
public void valueChanged(ListSelectionEvent e) {
JList lsm = (JList) e.getSource();
int selected_index = lsm.getMaxSelectionIndex();
if (selected_index >= 0){
System.out.println(selected_index);
}
}
}
}
I have a question that: Why the line "System.out.println()" print 2 values of selected_value while i just click 1 time on an index in JList ???
The listSelectionListener registered by the ui-delegate marks the selection change as being in-process on mousePressed and resets that flag in mouseReleased, making it final. If you want to only react only to changes that are finalized, you can query the valueIsAdjusting property and do nothing if true:
class AcrossListHandler implements ListSelectionListener {
#Override
public void valueChanged(ListSelectionEvent e) {
if (e.getValueIsAdjusting()) return;
// do stuff
}
}

Categories