java jspinner change listener trigger - java

I have 2 comboboxes and a spinner, that work like this: if the selected item of the first combo is changed, the second combo keeps its selected item but re-calls the spinner (the spinner is linked only to the second box). My problem is that I can't trigger the stateChange listener of the spinner when I do this.
Here is the code for forcing the second box to reselect its last item when the first one is changed (nothing wrong here, it works just fine):
String orientare = (String) orientareComboBox.getSelectedItem();
orientareComboBox.setSelectedItem(orientare);
This is the code for the second box actionListener:
public void actionPerformed(ActionEvent e) {
JComboBox combo = (JComboBox) e.getSource();
String value = combo.getSelectedItem().toString();
if (value.equalsIgnoreCase("oblica"))
{
unghiSpinner.setEnabled(true);
double unghi = (double) unghiSpinner.getValue();
unghiSpinner.setValue(new Double(unghi));
}
}
And the spinner's Listener:
public void stateChanged(ChangeEvent e)
{
if (unghiSpinner.isEnabled())
{
// do something
}
}
I do not know what command I should use for unghiSpinner to trigger its listener, because setValue() can't do it.

I don't see you changing the value of your JSpinner in the code above. It appears that all you do is set the spinner's value to the same value that it held previously, and that shouldn't trigger the listener. To trigger a change listener to fire you must change the state of the observed entity.

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;
}
}

How to update JComboBox with method "addItem()" without Selected Item being changed

I want to update JComboBox when I type in the JComboBox editor. It will get the text of JComboBox editor in real time and add some items based on the text. I have tried like this:
final JTextField tfListText = (JTextField) comboBox1.getEditor().getEditorComponent();
tfListText.addCaretListener(new CaretListener() {
private String lastText;
#Override
public void caretUpdate(CaretEvent e) {
String text = tfListText.getText();
if (!text.equals(lastText)) {
lastText = text;
comboBox1.removeAllItems();
// get some items based on text
comboBox1.addItem(someItems1);
...
}
}
});
However, the selected item of JComboBox was changed when using method removeAllItems() or addItem(), and it caused an endless loop triggering the CaretListener again.
So how to update JComboBox without selected item being changed, or is there any other way to add items based on the input content in real time

ComboBoxCellEditor only setting value on focus lost

Is there a way to set the value in a ComboBoxCellEditor other then when the focus is lost on the cell? I'm using it in each cell of a column in a TreeViewer and the only time that the setValue method is called is when focus is lost on the cell. So when a user makes a selection and doesn't click off of the cell the value is never set to the new selection. I've tried adding listeners on the ComboBoxCellEditor and on the control of the ComboBoxCellEditor but nothing seems to pick up the selection event.
I figured out that I needed to cast the control to a CCombo in order to add the correct type of listener to the ComboBoxCellEditor. Here's what I did:
CCombo combo = (CCombo) cellEditor.getControl();
combo.addSelectionListener(new SelectionListener()
{
#Override
public void widgetSelected(SelectionEvent paramSelectionEvent)
{
//selection code here...
}
#Override
public void
widgetDefaultSelected(SelectionEvent paramSelectionEvent)
{
//do nothing here...
}
});

Set the checkbox of a CheckboxTableViewer when the row is clicked

I am very new to SWT. Started working on it today actually. I have a table of type CheckboxTableViewer. What i want to be able to do is whenever the user selects the row (i.e clicks anywhere on the row) I want the check box to be checked (ticked). Currently I have a listener on the CheckboxTableViewer as follows:
diagnosesTableViewer.addCheckStateListener(new ICheckStateListener() {
#Override
public void checkStateChanged(CheckStateChangedEvent event) {
Nomenclature changedStateNomenclature = (Nomenclature) event
.getElement();
if (event.getChecked()) {
selectedNomenclatures.add(changedStateNomenclature);
} else {
selectedNomenclatures.remove(changedStateNomenclature);
}
}
});
I am able to select the row by checking on the checkbox. But i want to select the check box even when the user selects the row by clicking anywhere on that row on any column (not just the checkbox).
I guess that logic would go somewhere in the addSelectionChangedListener for the addSelectionChangedListener. But I am not sure how to go about it. Can anyone help me with this?
Use this code: Add selection listener to the table. ctv is the instance of of your CheckboxTableViewer.
Also I assumed CheckboxTableViewer allow only single selection not multi.
ctv.getTable().addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
int df = ctv.getTable().getSelectionIndex();
ctv.setChecked(ctv.getElementAt(df), !ctv.getChecked(ctv.getElementAt(df)));
}
});

JComboBox itemStateChanged event called twice at a time

resultCombo = new JComboBox();
resultCombo.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent ie) {
sampleText=resultCombo.getSelectedItem().toString();
System.out.println("SampleText : "+sampleText);
}
});
output:
SampleText : selectedword
SampleText : selectedword
Why this event is called twice when selecting item in combobox.?
JComoboBox ItemListener does get called twice for a single change. Once for SELECTED event and once for DESELECTED event.
See this tutorial page on how to write an ItemListener.
Basically what you have to do is
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
//Do any operations you need to do when an item is selected.
} else if(e.getStateChange() == ItemEvent.DESELECTED){
//Do any operations you need to do when an item is de-selected.
}
}
Based on the documentation of ItemListener
Invoked when an item has been selected or deselected by the user. The
code written for this method performs the operations that need to
occur when an item is selected (or deselected).
This suggested that you will receive an event when an item is deselected or selected. Seen as a change in the selected item in the combo box requires that the currently selected item has to be deselected first, it stands to reason that you will receive a ItemEvent.DESELECTED and ItemEvent.SELECTED event

Categories