I have a cuttingOperationComboBox ComboBox and a method that changes items and value of this ComboBox:
public void changeGlass(Glass newGlass)
{
ObservableList<Operation> list = new FilteredList<Operation>(ProductGlassCuttingUI.this.operationsDB.getOperationsList(), operation -> operation.getOperationType().toString().equals("RE") &&
operation.getGlassThickness() == newGlass.getGlassThickness());
if(!list.contains(this.cuttingOperationComboBox.getValue()))
cuttingOperationComboBox.setValue(list.get(0));
cuttingOperationComboBox.setItems(list);
}
I also have change listener added to cuttingOperationComboBox.valueProperty().
It is fired first time by cuttingOperationComboBox.setValue(list.get(0)); and here everything is fine. But when cuttingOperationComboBox.setItems(list); fires change listener, newValue in it is null although list is not empty. Moreover it happens only when ComboBox is visible. Tobe more precise: cuttingOperationComboBox is displayed in TreeView as a part of TreeCell graphics. As long as tree view node containing combobox is collapsed everything is ok, but when i expand this node and combobox shows, the above problem appears.
Anybody know what i am doing wrong?
Whenever you call setItems() of a ComboBox (or other controls involving list of items), the ComboBox (or the respective control) will always clear all selection. I believe this is the behavior caused by the underlying selection model, and I believe it is the desired behavior for most use-cases.
Without knowing exactly what you are achieving, it's hard to give you an exact solution. If you simply want to retain the value after setting new list, then you might need to keep a copy of the old selection item, and then manually set it in after setItems(). If you don't want the ChangeListener to respond to setItems(), either check for null newValue in the listener, or keep a boolean flag somewhere that would tell the listener that the particular call was triggered by setItems().
Related
I'm working on a Task-Manager like application, where the whole backing list of a TableView gets replaced by the result of periodically running a command line program. I'm using setAll to set the table view to the newest items. It works, but it resets the selection in the view.
Interestingly, the blue focus bar does not move, but a very small outline is shown on the first item of the table view after it was updated with setAll. I guess this is how the selected index is rendered. When I use the arrow keys to navigate, the selection will jump periodically back to the first item of the list.
Does anybody know how to solve this problem?
I found a way to do it, but I'm sure there is a better way. I manually calculate the difference between the new and the previous state. Then I call the removeAll, and addAll methods respectively:
object PortBindingLock
private fun reloadBindings() {
synchronized(PortBindingLock) {
val previous = this.portBindings.toSet()
val current = processService.processPortBindings().toSet()
val toRemove = Sets.difference(previous, current)
val toAdd = Sets.difference(current, previous)
this.portBindings.removeAll(toRemove)
this.portBindings.addAll(toAdd)
}
}
i have a jComboBox, it happens that i may have the same value for more than on item. In this case, when selecting one of them, , the selection goes always to the first item on the list. Right after the click.
Have someone experienced that?Have some solution for that, so the selection doesn't change?
When i select:
http://i.stack.imgur.com/IjlYM.png
Checking again:
http://i.stack.imgur.com/c1lcQ.png
it happens that i may have the same value for more than on item.
Then it sounds like you are adding a custom object to the combo box.
If it displays the same value but is a different item, then you need to implement the equals() method in your Object so the proper Object can be selected.
If you need more help then post a proper SSCCE that demonstrates the problem because we don't have enough information to keep guessing what you might be doing.
A JComboBox always tries to synchronize what is selected in the lists with what is shown in the display field. To do that, it searches the list sequentially for a match of the editor field. So it will always find the first one if there are identical items in the list. Thus you can't just use String objects if there is a possibility for identical Strings in the list. You need to do what #camickr said and use a custom object that has some way to distinguish between two objects whose toString() method returns the same thing (assuming you use the default model and editor).
I was trying to create a new UI component for the user to specify an integer value in two ways: using either a scrollbar, or a textfield. I wanted this to be a single UI component from which I can call something like integerField.getValue() and have it return the current integer value represented by the component.
My problem is, a classic cyclical update situation: when the underlying integer value is changed using the scrollbar, the textfield value needs to be updated, which triggers another event that causes the scrollbar to update - cycle complete.
In other words, scrollbar.setValue()->component.setValue()->textField.setText()->component.valueChanged()->component.setValue()->scrollbar.setValue()
Now, I can prevent this by having the first item in this chain setting a boolean flag and the other items in the component checking the flag before responding to a value change event. However, I'm not convinced that's an elegant solution.
Anyone have any better ideas?
Thanks!
A technical solution to the problem would be to read your text field and the last update time then your slider and the last update time. On the firing of the event, you would read the most recently updated value and if the values match stop updating and reacting.
SpinSlider, seen here and here, may be a good choice. It combines a JSpinner and a JSlider so that each component's ChangeListener listens to the other's ChangeListener.
I'm busy on a GUI application in Java in which I sometimes encounter IndexOutOfBoundsExceptions when a value is added to a jList.
The exception seems to occur when a value is selected, and then another is added. I have a listener for selection changes because something needs to happen when the user selects an index, but this event is fired when a new value is added as well. I use a custom ListModel that just extends AbstractListModel and overrides the necessary methods in a perfectly valid way.
Why does the selection change in the program when a value is added to the list? This is not visually represented.
Why does the jList allow selection of an index that is not really there?
I have used jList twice now (we've recently started doing GUI in school) and I've had the problem both times. First time I solved it by clearing selection before a value is added, but that's not a really good solution. I don't think this should be necessary.
I don't know why this occurs, I have no strange code or anything. In pseudo-code, this is what happens:
listmodel.addValue(object);
listmodel.fireIntervalAdded();
//selection event occurs
selectedObject = listmodel.getValueAt(list.getSelectedIndex()); //indexoutofboundsexception
//index = 5, size = 3 (for example) when there are 2 objects in list and first is selected.
I'm not providing more code right now because I think it's not really relevant. I think anyone that understands perfectly how a jList, its listmodel and its selectionmodel work, will understand what's wrong. Any help on this is appreciated.
The problem is most likely that you're calling fireIntervalAdded(this, 0, list.size()) when a single item is added to your list model. The signature is:
protected void fireIntervalAdded(Object source, int index0, int index1)
Note that index0 is the starting index of the added item and index1 is the ending index. Thus for a single item index0 should be the same as index1. When you call fireIntervalAdded with 0, list.size(), you are telling the JList that N items have been added, where N=list.size(). Thus the JList thinks there are more items than are in your list model.
The same goes for when you remove an item.
I have a JComboBox. I add a ActionListener using the following code:
addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
textComboActionPerformed(evt);
}
});
This is what it looks like when it is first displayed. It has a couple options in it.
You will notice that Basic Text Box is the first element, and so it will be the element that shows when the JComboBox is first displayed.
If you click on the JComboBox, you will see the options that are available under it.
However, if I select "Basic Text Box" it will not cause the ActionEvent to fire. It has something to do with it being the first element in the list. If I select any other JComboBox, then the ActionEvent is fired.
EDIT: On Linux, say you select an element, and the event fires. Then you select that element again, it will not fire the second time. It is not isolated to just the first element. It has to do with selecting the already selected element twice.
This behavior only happens on Linux. On Windows, the Event fires not matter which element I click on, even the first. Any ideas on why this would be? Does behavior like this vary from JVM to JVM?
Thanks
First, I think the correct listener to use is ItemListener (instead of an ActionListener).
As you state in your comment this gives you consistent behavior across platforms: you don't get an event at all when the already selected item is "re-selected". This is exactly how an ItemListener is supposed to work according to the JavaDocs:
aListener will receive one or two
ItemEvents when the selected item
changes.
When you select the same value that's already selected, obviously you don't change the value, so no event is fired. However, that's not quite what you want apparently. As an alternative, I suggest displaying the JComboBox without a preselected item:
JComboBox comboBox = new JComboBox(model);
comboBox.setSelectedItem(null);
I don't know if that's possible for your application but this way you'll definitely get an event whenever an actual value is selected. (It also makes more sense from a usability point of view, I think, because why would a non-expert click on a combo box to select the value that's already selected?)