Here is my problem.
I have a generic class called FilteredComboBox that extends ComboBox. It is basically an editable combobox that filteres choices according to user input. This FilteredCombobox is feed by ObservableList of type Book, which is just a simple class with 2 fields, name and id (obviously it has getters, setters and toString).
After user makes his choice and clicks on book that he wants from the dropdown, I would like to get this book id by the method in book class called getBookId. Unfortunately when I say bookComboBox.getValue.getBookId I get cast exception, because getValue automatically calls toString method.
Is there a way around it? I would like to make getValue() method to return an object of type book and just a\call my getBookId() from there.
Any ideas?
For combo like
ComboBox<Book> combobox = new ComboBox<>(your_book_list);
get the selected book item on event (on button action event for instance)
Book selectedBook = combobox.getSelectionModel().getSelectedItem();
Integer id = selectedBook.getBookId();
Yes it does extend ComboBox
I solved my problem by doing his:
public T getChosenValue() {
int index = getSelectionModel().getSelectedIndex();
if(filter.size() != 0)
{
System.out.println("filter size is not 0");
return filter.get(index);
}
else
{
System.out.println("filter size is 0");
return items.get(index);
}
}
Since i have 2 observable lists, items and filtered I had to do this if, else. Works well, I will see if it doesnt give me any bugs when I test it.
Related
i have a combobox that displays items at a restaurant, i want to be able to select the item then click a button below that will add it to a DefultListModel, i have managed to do this but i have to use many if statements
if(comboBoxStarters.getSelectedItem() == "Sticky Chicken Wings") {
selectedItems.addElement("Sticky Chicken Wings");
}
if (comboBoxStarters.getSelectedItem() == "French Onion Soup") {
selectedItems.addElement("French Onion Soup");
}
if (comboBoxStarters.getSelectedItem() == "Bacon and Salmon Brochettes") {
selectedItems.addElement("Bacon and Salmon Brochettes");
}
if (comboBoxStarters.getSelectedItem() == "Sesame Chicken Skewers") {
selectedItems.addElement("Sesame Chicken Skewers");
}
i know you can do this in just a couple of lines of code but i cant remember how, i have this so far:
selectedItems.addElement(this.comboBoxStarters.getSelectedItem());
itemList.setModel(selectedItems);
but this isnt compiling
(selectedItems is my DefaultListModel)
(itemList is my Jlist)
also all the code above is inside a button action event listener
Cast the getSelectedItem() return value
selectedItems.addElement((String)this.comboBoxStarters.getSelectedItem()); // added (String) cast
itemList.setModel(selectedItems);
this may still be referring to your ActionEventListener; you might need to use a "qualified this" to refer to your outer class's this pointer, like OuterClassName.this.
getSelectedItem() can return null if no item is selected, so it is wise to first check if it is non-null.
Object selected = OuterClassName.this.comboBoxStarters.getSelectedItem();
if (selected != null) {
selectedItems.addElement((String) selected);
itemList.setModel(selectedItems);
}
Even safer would be if (selected instanceof String) {, unless you are completely sure your combo box will only contains strings.
I suppose you are using Java 7 or an upper version. In java 7 DefaultListModel definition is like that
DefaultListModel<E> model = new DefaultListModel<E>
So you must cast the selected item to E
selectedItems.addElement((E) this.comboBoxStarters.getSelectedItem());
And of course getSelectedItem() should return an object with type E.
I have a comboBox cb and an ObservableList<StringProperty> data
I have bound the cb's Items to data as follows:
Bindings.bindContent(cb.getItems(), data);
Suppose data has the following items: str1, str2, str3, str4
When I change data, the combobox gets the new list without any problem.
But if str3 is selected in cb and I change the value of str3 to NewStr3 in data, that change is not getting displayed in cb. And sometimes the list displayed is also wrong (it shows str3 instead of NewStr3) eventhough underlying data it refers is correct.
How can I force combobox to display new values when the underlying model is changed?
The selected item in a combo box is not required to be an element of the combo box's items list. (For example, in an editable combo box, you can type in an item which is not in the list.) If you think about your example from this perspective, it's no surprise that it behaves as you describe.
If you want to force the selected value to be an element of the underlying list when that list may change, you need to define how the selected item should change if the list changes in a way in which it no longer contains the selected item (it is not obvious how you will do this, and probably depends on your application logic). Once you know what you want to do, you can implement it with a ListChangeListener:
cb.getItems().addListener((ListChangeListener.Change change) -> {
String newSelectedItem = ... ; // figure item that should be selected instead
cb.setValue(newSelectedItem);
});
The simplest implementation would be just cb.setValue(null);, which would mean no item was selected if the list changed so that it no longer contained the currently selected item.
Oops ... mis-read the comboBox for a choiceBox - while the basics of this answer apply to both combo- and choiceBox, I don't have a custom ComboBoxX - yet :-)
Basically, it's the responsibility of the SelectionModel to update itself on changes to the items. The intended behaviour implemented in core is to completely clear the selection - that is, null the selectedItem and set selectedIndex to -1 - if the old item was the selectedItem and is replaced or removed. The typical solution for custom behaviour is to implement a custom selection model and set it:
/**
* A SelectionModel that updates the selectedItem if it is contained in
* the data list and was replaced/updated.
*
* #author Jeanette Winzenburg, Berlin
*/
public static class MySelectionModel<T> extends ChoiceBoxSelectionModel<T> {
public MySelectionModel(ChoiceBoxX<T> cb) {
super(cb);
}
#Override
protected void itemsChanged(Change<? extends T> c) {
// selection is in list
if (getSelectedIndex() != -1) {
while (c.next()) {
if (c.wasReplaced() || c.wasUpdated()) {
if (getSelectedIndex() >= c.getFrom()
&& getSelectedIndex() < c.getTo()) {
setSelectedItem(getModelItem(getSelectedIndex()));
return;
}
}
}
}
// super expects a clean change
c.reset();
super.itemsChanged(c);
}
}
// usage
myChoiceBox.setSelectionModel(new MySelectionModel(myChoiceBox));
Unfortunately, core choiceBox doesn't play by the rule - it severely interferes with model's responsibilities (probably because the model implementation doesn't stand up to its duties) which requires a complete re-write of the whole collaborator-stack (choiceBox, -skin, copied -behaviour) such as ChoiceBoxX - which I did just to learn a bit, try remove some of its smells and fix some bugs.
the Original code of set selected Item is:
public void setSelectedItem(Object anObject) {
Object oldSelection = selectedItemReminder;
Object objectToSelect = anObject;
if (oldSelection == null || !oldSelection.equals(anObject)) {
if (anObject != null && !isEditable()) {
// For non editable combo boxes, an invalid selection
// will be rejected.
boolean found = false;
for (int i = 0; i < dataModel.getSize(); i++) {
E element = dataModel.getElementAt(i);
if (anObject.equals(element)) {
found = true;
objectToSelect = element;
break;
}
}
if (!found) {
return;
}
}
in my opinion the line
if (anObject.equals(element)) {
should be
if (element.equals(anObject)) {
Consider a Combo box displaying eg. languages
then you hav a class like
class Language {
String code; // eg. "en"
String name; // eg. "English"
...
}
if you add Language items to your ComboBox the toString function is used to Display an Item. In the above class the toString function would return the name. A call setSelectedItem("en") fails because
String.equals(Language) will fail because Language.toString() will return "English"
the other way round Language.equals(String) would be helping because the class Language could override
boolean equals(String comp) {
return comp.equals(code)
}
Just for clarification, I know how to create a Combobox with the desired behaviour, my question is: is the comparison in the original code a bug or did I miss something fundamental?
The properly implemented Object.equals is symmetric, meaning that there should be no difference between anObject.equals(element) and element.equals(anObject).
You are describing a situation where the combobox model contains objects of type Item, but you want to select select an item by specifying an object of type Prop, where the value of Prop describes some property of Item.
Using technically incorrect implementation of equals() method you can select a combobox item by passing an instance of Prop instead of Item.
With the original code, you will have to provide broken equals() implementation in Prop class, and with your modification you will have to provide broken equals() implementation in Item class. If the Prop is some library class (as String in your example) then the former case is, of course, impossible, and i assume that the reason for your proposed modification is to allow the latter case.
I am not sure that library creators tried to prevent programmers from implementing broken equals() by choosing that specific anObject.equals(element) expression, but even if it was element.equals(anObject) it would still be bad practice to provide deliberately incorrect equals() implementation just for the sake of simplifying the combobox selection.
The proper way to perform selection by property would be to search the combobox data for the item with the required properties or to create a completely new instance of Item with the desired properties and then pass that item into the setSelectedItem.
If you are lucky to already use Java 8 then selecting the required item from a list is one-liner, and if not then you will have to write some boilerplate code with cycle, but at least you will have the proper equals implementation and clean conscience.
To override the inherited equals method, you should pass an object as parameter and not String
public boolean equals(Object obj){
//code goes here
}
I have this DefaultListModel
DefaultListModel listModel;
//constructor does the right hting... etc.. I skipped over a lot of code
JList jlist_available_items;
....
jlist_available_items= new JList(cartModel); //etc
Everything is working almost perfectly the issue is that
listModel.addElement(product);
if I change it to product.name it will look correctly, but behave wrongly [the object itself won't be accesisble, only the name]
Is adding the object to the view, and all I want to add is the object name.
When I change it to the name it causes all sorts of issues, because I store the objects in a hashmap, and the hashmap uses objects as keys, not the product.name string.
The reason is so that this method can search the hashmap for the right object.
for (Product p : store.database.keySet()) {
if (jlist_available_items.getSelectedValuesList().contains(
(Product) p)) { // if item is selected
cart.addItem(p);
}
}
How can I fix this?? I have been trying to fix it and related bugs for almsot two hours = ( !
Also sample output is
Product [description=descrion test, name=test]
That is what it is printing. I just want it to print the name. = (!
Also the objects are in a hashmap. I can just iterate through the hashmap until an object has the same name value and then use that, but I don't want to. I want a more proper and scalable solution, namely because I am having so much trouble thinking of one.
BY THE WAY! This is a GUI app in Swing! If you want images just ask = )!
EDIT: And now nmy list cell renderer is broken! It was working just a moment ago... = (
#Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
Product product = (Product) value;
return this;
}
}
By default, the toString() method of the objects in the model is called to display the list element. And your Product.toString() method returns Product [description=descrion test, name=test].
If you want to display something else, then use a ListCellRenderer, as explained in the swing tutorial about JList.
EDIT: your renderer has a bug: it doesn't set the text of the returned component (which is a JLabel). It should be:
Product product = (Product) value;
setText(product.getName());
return this;
I need to remove all items from the combo box
int itemCount = combo.getItemCount();
for(int i = 0; i < itemCount; i++){
combo.removeItemAt(0);
}
This code will remove all items except the last one. It gives a NullPointerException.
How to fix that?
The code in the question would normally work. However, it looks like a threading issue. Another thread may be messing with the items.
However, I sugeest you should better use the removeAllItems(); method:
combo.removeAllItems();
How about JComboBox.removeAllItems()?
You can use
this.combo.removeAllItems();
to remove all the items in JComboBox.
In second line:
combo.removeItemAt(0);
I think instead of 0 it should be i.
do it in reverse order as:
for(int i=combo.getItemCount()-1;i>=0;i--){
combo.removeItemAt(i);
}
But in my case combo.removeAllItems() works fine
use .removeAllItems() methods to remove all items from combo box.
The assumption that it is related to another thread is not always true. It can be the thread itself causing the issue.
This exception may happen because an event is triggered when a combo item is removed and in this event handling method you still refer to combobox items.
For example when you delete somewhere (other than in actionPeformed()) in your code the last item from a combo box with combo.removeItemAt(0) or removeAllItems() then still the event actionPerformed will be fired/executed. But very often the actionPerformed() method contains code to react on user actions (user clicked somewhere on the combobox). So, when the last item has been deleted there is no more item in the combobox and any reference to an item or index in actionPerformed() will cause an exception.
The solution to this is to move the code from actionPerformed() to e.g. mouseClicked() or another event handler depending on what you want to do.
removeAllItems() it does remove all things but after the add data to the combo box it will not show there ,the nullPointException will shows
Use this to remove all the elements from the combo box :
DefaultComboBoxModel model = (DefaultComboBoxModel) ComboBox.getModel();
model.removeAllElements();
Usually it happens because you have an event associated JComboBox. It is solved if you have control item in the JComboBox to act, for example:
jComboBoxExample.addActionListener (new ActionListener () {
public void actionPerformed (ActionEvent e) {
do_run ();
}
});
public void do_run() {
int n=jComboBoxPerfilDocumentos.getItemCount(); <--THIS IS THE SOLUTION
if (n> 0) {
String x = jComboBoxPerfilDocumentos.getSelectedItem (). ToString ();
}
}