I'm using a JList which displays correctly. However, I'm having trouble removing elements from the list.
JList nameList = new JList(db.getAllNames());
nameList.setVisibleRowCount(6);
nameList.setFixedCellWidth(400);
JButton removeNameButton = new JButton("Remove Name");
removeNameButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
String id = nameList.getSelectedValue().toString(); //valid value when button pressed
int index = nameList.getSelectedIndex(); //valid value when value pressed
namesList.remove(index); //ERROR
}
The JList contains 4 names, which displays perfectly and seem to have the correct indexes. (If I check the value System.out.println(copiersList.getModel().getSize()); it always displays 4
Here is the error message:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 3
Oddly, if I remove Adam, I do not get an error (but visibly the list does not change and calling .getSize() method displays 4):
id selected: Adam
index selected: 0
However, any other:
id selected: BobException in thread "AWT-EventQueue-0"
index selected: 1
java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 1
at java.awt.Container.remove(Unknown Source)
Don't remove from the JList itself since the remove(...) method does not do what you think that it does. It in fact is trying to remove a component that is held in the JList as if it were a JPanel that held other components, even if no such component exists. Instead remove from the JList's model, usually a DefaultListModel. The DefaultListModel class has a removeElement(Object element) and a removeElementAt(int index) method that can help you.
i.e.,.
public void actionPerformed(ActionEvent e) {
String id = nameList.getSelectedValue().toString(); //valid value when button pressed
int index = nameList.getSelectedIndex(); //valid value when value pressed
DefaultListModel listModel = (DefaultListModel) namesList.getModel();
listModel.removeElementAt(index);
}
Related
This question already has answers here:
JList.getModel() ClassCastException
(4 answers)
Closed 6 years ago.
I have implemented a button that will simply delete a "contact" in the JList contactList. What the program is supposed to do is if the button deletes "Broadcast", which is the first element in contactList, will return an error by outputting a display message. Otherwise, it is supposed to simply remove the contact from the contact list.
My question is how do I delete the contact from the JList using DefaultListModel correctly? I saw that DefaultListModel needs to be used because remove function isn't in JList nor ListModel.
What the example contact list of size 4 may look like:
[Broadcast]
[Andro]
[Denis]
[Micheal]
...
This is the error:
[java] Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: javax.swing.JList$4 cannot be cast to javax.swing.DefaultListModel
... //rest of error
Code:
private JList<String> listContacts;
//constructor:
listContacts = new JList<String>(controller.getContacts());
//gets contact list from controller class which gets contact list from client class.
listContacts.setModel(new DefaultListModel());
JButton deleteUser = new JButton("Delete User");
menuPanel.add(deleteUser,BorderLayout.EAST);
deleteUser.addActionListener(new MyButtonListener5());
class MyButtonListener5 implements ActionListener{
public void actionPerformed(ActionEvent e){
DefaultListModel<String> list = (DefaultListModel)(listContacts.getModel());
String contact = listContacts.getSelectedValue();
int j = -1;
for(int i = list.getSize()-1; i >= 0; i--){
if(list.getElementAt(i).equals("Broadcast")) {
controller.displayMsg("[ERROR] You cannot delete broadcast\n");
}
else if(list.getElementAt(i).equals(contact)){
j = i;
}
}
if(j != -1){
list.remove(j);
}
}
(DefaultListModel)list.remove(j);
list.remove() returns the item that was removed from the list, which in your case is a String. Why are you casting it to a DefaultListModel?
or did you really mean
((DefaultListModel<String>)list).remove(j);
which casts "list" to a DefaultListModel, and then calls that model's remove() method. But "list" is already declared as a DefaultListModel, so the cast is superfluous.
Just get rid of the cast.
here is my first JList:
JPanel classe = new JPanel();
class_list = new JList();
class_list.addListSelectionListener(this);
JScrollPane classeScrollPane = new JScrollPane(class_list);
classeScrollPane.setPreferredSize(new Dimension(175,405));
classe.setBorder(new TitledBorder("Classes"));
classe.add(classeScrollPane);
here is the second:
JPanel relation = new JPanel();
relation_list = new JList();
relation_list.addListSelectionListener(this);
JScrollPane relationScrollPane = new JScrollPane(relation_list);
relationScrollPane.setPreferredSize(new Dimension(220,130));
relation.setBorder(new TitledBorder("Relations"));
relation.add(relationScrollPane);
here is my valueChanged operation:
public void valueChanged(ListSelectionEvent e){
JList source = (JList) e.getSource();
String value = (String)source.getSelectedValue();
if (value.length() > 0){
if (source == class_list){
//if(!relation_list.isSelectionEmpty()) relation_list.clearSelection();
Class_object co = declaration.getClass(value);
attribut_list.setListData(co.getAttributes().toArray());
operation_list.setListData(co.getOperations().toArray());
if(declaration.getGeneralization(value) !=null){
subClass_list.setListData(declaration.getGeneralization(value).getSubClasses().toArray());
}
//clear JList if there is no correspondent subclass
else subClass_list.setListData(new String[2]);
//add relation content to relation panel
DefaultListModel model = new DefaultListModel();
related_association = declaration.getAssociation(value);
for(Association asso : related_association){
model.addElement("(R)"+asso.getName());
}
related_aggregation = declaration.getAggregation(value);
for(Aggregation agg : related_aggregation){
model.addElement("(A)"+agg.getName());
}
relation_list.setModel(model);
}
if (source == relation_list){
int focused_list = source.getSelectedIndex();
if(focused_list < related_association.size()){
details.setText(related_association.get(focused_list).toString());
}
else {
details.setText(related_aggregation.get(focused_list-related_association.size()).toString());
}
}
}
}
Basically, when we click on item in the first JList, it displays in the second JList something (for example a variable name of this item). Then we click on item in the second JList, it displays more information about this item in a JTextArea. So you have to click first jlist to display second jlist then click second jlist to display detail information.
Here is the problem, after I have clicked first jlist and second jlist, I click another item in first JList, a NullPointerException occurs in line "
if (value.length() > 0){
I understand that the error occurs because the variable value is null, but I don't know why value is null.
Could anyone tell me whats wrong with my code. Thanks alot.
During a change in selection, the currently selected item is "deselected", this means that, momentarily, nothing is selected, the ListSelectionListeners are notified of this change, this is where your null value is coming from.
Then the selection is changed to the newly selected item and the ListSelecitonListeners are notified again.
You can test for this through the use of ListSelectionEvent#getValueIsAdjusting
The reason this occurs the second time you select a value is because the deselection event notification does not occur, only the selection event...
This question already has answers here:
Java - Updating JList after changing an object
(3 answers)
Closed 8 years ago.
I have a Jlist with a DefaultListModel with data from XML.
I want to be able change the name of the item in the Jlist. but the DefaultListModel has no update method.
So if the user clicks on a name it should edit the name.
So far I thought if I get the location of the item and remove it and update with new data. But if I update with then new name will it be put in the same location as the old or will things be messed up ?
My code :
private class EditName extends AbstractAction {
public EditName() {
putValue(NAME, "Change Name");
putValue(SHORT_DESCRIPTION, "Some short description");
}
public void actionPerformed(ActionEvent e) {
int x = objTypeJList.getSelectedIndex();
String newName = JOptionPane.showInputDialog("New Name?");
if (x >= 0) {
String oldName = ReadXMLFile.getInstance().getModel().getElementAt(x).toString();
ReadXMLFile.getInstance().getModel().removeElementAt(x);
objTypeJList.setModel(ReadXMLFile.getInstance().getModel());
}
// newText I wanna add into the the location I edit
}
}
"I want to be able change the name of the item in the Jlist. but the DefaultListModel has no update method."
What makes you say that? Have you looked carefully at the docs ?
What do you think this method does?
public void setElementAt(E element, int index) - Sets the component at the specified index of this list to be the specified element. The previous component at that position is discarded.
OR
public E set(int index, E element) - Replaces the element at the specified position in this list with the specified element.
I'm trying to get the position (as a int) of a JComboBox object, The ComboBox is generated and haves an action listener like this
for (int d=0; d<i; d++)
{
titulos.addItem(listaPraBox[d]);
}
ActionListener comboListener = new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
ItemSelectable is =(ItemSelectable)actionEvent.getSource();
objectoseleccionado = selectedString(is);
DeskMetodos.listaTexto(objectoseleccionado);
}
};
titulos.addActionListener(comboListener);
The executes
static private String selectedString(ItemSelectable is) {
Object selected[] = is.getSelectedObjects();
return ((selected.length == 0) ? "null" : (String)selected[0]);
}
But I wanted the position of the selected object to get a string from another array by that int.
Is this even possible? By the search I've made there isn't even reference to this.
JComboBox defines getSelectedIndex(). The implementation is just to loop over the data model checking equality with getSelectedItem().
That doesn't make it up into ItemSelectable, but neither does the data model itself, so you may need to use the concrete class.
Instead of storing items in a ComboBox and having to use the index to reference another array of values. Just store an object in the ComboBox that has a toString() output that matches your current displayed value and a direct reference to the object in the array. That way any object pulling the selected item or dealing with comobo box can just pull the value they need and not have to also "know" about this other array.
1) In the following method (actionListener) a user select a grade (e.g. A-F) from a JComboBox.
2) There are multiple JComboBoxes, and each selection made gets stored into a single String[] array.
PROBLEM:
Here is the dilemma, if a user goes back and changes a selection made from a random JComboBox the previous grade selection does not get replaced in the array, however the new selection made gets stored at the next array index.
How can I make the program replace the previous grade selection and not just add the new selection?
relevant variables:
int counter;
private JComboBox[] gradeField;
//grade.userGrades[] is array of grades taken from selected combo boxes
Action Listener anonymous class:
gradeField[counter].addActionListener(new ActionListener () {
#Override
public void actionPerformed(ActionEvent e) {
Object holder = e.getSource();
JComboBox tempGradeBox = (JComboBox)holder;
String theGrade = (String)tempGradeBox.getSelectedItem();
grade.userGrades[grade.getNext()] = theGrade;
grade.updateNext();
}
});
Thanks in advance for any help.
I save the grade in an array and increment the index,
Well you should not be incrementing the index. This assumes that the user selects the grades from the combo box in a sequential order. As you have discovered users can often work randomly.
Instead you need to know which combo box has been changed and then update the appropriate entry in your array.
Or a different solution might be to update your array at the end. So maybe you have a "Process Results" button. Then you can sequentually loop through all the combo boxes to get the selected value.
Update the user grade being at the same index as the combo box:
final int index = counter;
gradeField[counter].addActionListener(new ActionListener () {
#Override
public void actionPerformed(ActionEvent e) {
Object holder = e.getSource();
JComboBox tempGradeBox = (JComboBox)holder;
String theGrade = (String)tempGradeBox.getSelectedItem();
grade.userGrades[index] = theGrade;
}
});
Here's another variation of JB Nizet's answer:
class OuterClass
{
...
gradeField[counter].addActionListener( new GradeSettingActionListener( counter ) );
...
class GradeSettingActionListener implements ActionListener
{
// -- Doesn't have to be final here (it does in JB's answer), but I like to be restrictive.
private final int index;
public GradeSettingActionListener( int index )
{
this.index = index;
}
#Override
public void actionPerformed( ActionEvent e )
{
Object holder = e.getSource();
JComboBox tempGradeBox = (JComboBox) holder;
String theGrade = (String) tempGradeBox.getSelectedItem();
grade.userGrades[index] = theGrade;
}
}
}
This approach removes the anonymous class by adding an inner class. The inner class will still have access to grade. You don't gain much here unless there's a chance you'll be splitting out the inner class later.
Of course, camickr's suggestion to process all the grades at once may also be valid, depending on other requirements (i.e., whether additional processing is done after the grades are stored in the array, which seems likely).