I have a standard JList that will be changed while the program is running. In order to make life easier I have created a DefaultListModel and assigned it to the JList:
JList CharList = new JList();
DefaultListModel CharListModel = new DefaultListModel();
CharList.setModel(CharListModel);
I am able to load a file into the list, and later I can add items to the list like this:
File ChFile = new File (CharListFile);
FileReader freeder = new FileReader (ChFile);
BufferedReader breeder = new BufferedReader(freeder);
String line;
while((line=breeder.readLine())!=null)
{
int pos = CharList.getModel().getSize();
CharListModel.add(pos, line);
}
...
...
//and to add items..
int pos = CharList.getModel().getSize();
CharListModel.add(pos, NewCharName);
However, I need to be able to remove items from the list, and this is giving me some considerable trouble!
I have tried the most obvious way (Yes an item is selected, and I have already retrieved both the index and the string at that index):
CharListModel.removeElement(CharList.getSelectedValue());
However, this gives me a 'java.lang.ArrayIndexOutOfBoundsException: -1' error.
I have tried all of the permutations that you can see in the code below (Some are commented out but you get the idea):
DefaultListModel model = (DefaultListModel) CharList.getModel();//CharListModel;
int selectedIndex = CharList.getSelectedIndex();
if (selectedIndex != -1) {
//model.remove(selectedIndex);
//model.removeElement(CharList.getSelectedValue());
//model.removeElementAt(selectedIndex);
}
as well as a few other permutations as well:
CharListModel.removeElementAt(CharList.getSelectedIndex());
//or
CharListModel.remove(CharList.getSelectedIndex());
//or
CharList.remove(SelItemIndex);
In each case I get the same 'ArrayIndexOutOfBoundsException' error, even though the selected index is previously found with no trouble. And yes, I know I just said 'previously' so something could have changed things, but here is the code that runs directly before I try to remove the element:
int SelItemIndex = CharList.getSelectedIndex();
if(SelItemIndex == -1)
{
JOptionPane.showMessageDialog(null, "You have to select something!");
return;
}
String SelItem = CharList.getModel().getElementAt(SelItemIndex).toString();
//Create warning
final JComponent[] inputs = new JComponent[]
{
new JLabel("<html>Bla Bla " + SelItem + " Are you sure?</html>")
};
int n = JOptionPane.showConfirmDialog( null, inputs,"Deletion Confirmation Warning", JOptionPane.YES_NO_OPTION);
if( n == 1)
{
//Do not delete
return;
}
That is all there is before trying to remove the selected element.
For the life of me I don't know why this is not working! Am I missing something really silly here?
A confusing update
In the ActionPerformed event of a JButton I have used this code - The comments in the code explain why this is so confusing!:
DefaultListModel CharListModel = (DefaultListModel)CharList.getModel();
if( CharListModel.contains(CharList.getSelectedValue()) == true)
{
//Selected item is found
int selItemIndex = CharListModel.indexOf(CharList.getSelectedValue());
if(selItemIndex != -1)
{
//Selected item index is NOT -1 and is correct
CharListModel.remove(selItemIndex);
//Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: -1
}
else
{
//NEVER reached
JOptionPane.showMessageDialog(null, "OUCH!");
}
}
As you can see, the index of the selected item is correct right up to the point of removing it, whereupon I once again get the out of bounds exception. I also tried this in the same place but with the same results:
CharListModel.removeElement(CharList.getSelectedValue());
Even more confusion
In an attempt to work out what is going on I have created a new DefaultListModel, enumerated the old one, and put each name into the new model, except the one that I want to remove (Remember I can get the index, the object and the text, I just cant delete it).
This has worked and I now have a DefaultListModel with the correct items in it, however, the moment that I try to CharList.setModel(NewModel); I once again get the out of bounds exception.
This has got me pulling out hair! Can anyone offer any ideas to try?
A Resolution of sorts
Not really a resolution at all, but to work around this maddening problem I am using the method laid out above, where I create a copy of the list model, minus the item that I want to delete and then simply catch the exception when using setModel, since the updated list model is added to the list just fine, and subsequent actions such as adding items etc. work okay, right up until I try to delete an item again anyway!
Thanks if you tried to help - and if you have any ideas about how to hunt down this problem, by all means post away!
regards
Max
For reference, I added the code below to this example. If it's not helpful, it may be a useful sscce for updating your question.
panel.add(new JButton(new AbstractAction("Remove") {
#Override
public void actionPerformed(ActionEvent e) {
int index = list.getSelectedIndex();
if (index != -1) {
model.remove(index);
}
}
}));
I had a similar problem. It turned out the error stemmed not from removing the element, but rather displaying the list. When implementing the
public void valueChanged(ListSelectionEvent e)
method, which updates the list on the screen, make sure to check if the model is null before you set the values. This is what caused the exceptions in my case.
Creating a list, removing from there, and then updating the model with the list is also a usable workaround.
I have faced the same issue. It seems when the item is removed from the model, it gets removed from the array as well. Hence is messes up the array index.
As a work around, I moved the array contents into a List and remove the List contents from the model. Now it works fine for me.
I have the same problem, i fix this doing that:
Button Action
int index = mylist.getSelectedIndex();
MyObject = (MyObject) mylist.getSelectedValue();
int Size = mylistmodel.getSize();
if (index >= 0 && MyObject != null && Size > 0) {
modeloLista.removeElementAt(indice);
}
And.
listValueChanged
if (list.getSelectedValue() != null) {
your code..
}
Related
I've been having a problem with my program that has been driving me crazy and I cannot understand why this is happening. I have a GUI that when the "Add" button is pressed, a new system listing appears (Which is a class called SystemPanel that extends JPanel and cotains system details, which is created and then put into the Frame's main panel.)
To put it shortly, when I try to add a new SystemPanel, it does not appear for whatever reason. I have code using JSch that connects to the system and verifies whether its processes are online or not, but the line of code that does this is after the creation of the SystemPanel. It is only after the code for testing the processes of the system are executed that the SystemPanel becomes visible, and I can't understand why this is the case. Here is the code for adding a new SystemPanel:
public void actionPerformed(ActionEvent e) {
//If the "Add" button is pressed
if (e.getActionCommand() == "Add") {
PopupWindow popup = new PopupWindow(this);
popup.setVisible(true);
String[] results = popup.getResults();
if (results[0] != null && results[1] != null && results[2] != null && results[3] != null && results[4] != null) {
SystemPanel newSystem = new SystemPanel(this, results[0], results[1], results[2], results[3], results[4]);
systemsPanel.add(newSystem);
revalidate();
systemsList.add(newSystem);
System.out.println("Did the stuff");
boolean[] status = SystemChecker.checkOnline(results[0], results[1], results[2], results[3]);
}
}
}
The PopupWindow is a custom JDialog that allows the user to enter the required information which is returned in a String array and is used to create a new SystemPanel. The checkOnline function grabs the user's inputs and uses them to connect to the system and determine whether the processes are working or not, and returns the results into a boolean array, true for working, false for not.
What's even weirder is that I have another part of my program that reads from an .ini file to obtain existing systems and then creates SystemPanels based on the data that it reads. Through this method, the SystemPanels are added the way I want and work perfectly for some reason, even though the code for adding the panels is hardly any different. Code:
for (int i = 0; i < systems.size(); i++) {
SystemPanel newSystem = new SystemPanel(this, systems.get(i)[0], systems.get(i)[1], systems.get(i)[2], systems.get(i)[3], systems.get(i)[4]);
systemsPanel.add(newSystem);
revalidate();
systemsList.add(newSystem);
}
for (int i = 0; i < lineNum; i++) {
boolean[] status = SystemChecker.checkOnline(systems.get(i)[0], systems.get(i)[1], systems.get(i)[2], systems.get(i)[3]);
systemsList.get(i).updateIcons(status);
}
This code grabs the details from the file and then makes the SystemPanels based on those details. Here, all of the SystemPanels are added and show up before the connection is tested, which is what I want to happen when I add one normally.
Why is it that the SystemPanel doesn't appear until the connection is tested, even though the code for displaying the SystemPanel is executed before the connection test? Any help would be greatly appreciated, thanks.
Try it of the current event queue handling, on which actionPerformed is done.
public void actionPerformed(ActionEvent e) {
EventQueue.invokeLater(() -> { ... your code here ... });
}
Also you cannot add the same component to two parents, every component object has a single parent (container).
(Java 8 notation)
I seem to be having an issue with not properly syntaxing my code, but as I've just started out with learning I seem to be missing the error. It's a homework assignment, where I need to use an Array of JxploreFile-objects. This is the part of the code I'm having trouble with:
private JxploreFile[] getSubFolders()
{
File subFiles[];
subFiles = file.listFiles();
File subFolders[];
int p = 0;
for(int i = 0; i < subFiles.length; i++)
{
if(subFiles[i].isDirectory() == true)
{
Array.set(subFolders, p, subFiles[i]);
}
}
JxploreFile foldersToReturn[] = new JxploreFile[subFolders.length];
for(int i=0; i < subFolders.length; i++)
{
foldersToReturn[i] = new JxploreFile(subFolders[i]);
}
return foldersToReturn;
}
Specifically, the for-loop where I'm trying to add the files marked as .isDirectory into a new Array. I've also tried other methods by placing each new file coming from the subFiles Array manually into the subFolders Array by declaring indexnumbers, but this also turned out faulty. At this point I'm out of ideas and I hope there is someone who can point me out the obvious, as I'm probably missing something reallly basic.
Edit:
I'm sorry for the incomplete post, It's the first time I actually post here as I usually try to filter my own problems out of the posts of others. The error I got was indeed that 'subFolders' had not been initialized yet, which I didn't understood because on the sixth line I wrote
File subFolders[];
which as far as I know should declare the variable subFolders to become an Array, or is this where I went wrong?
Also, my question might not have been specific enough, I'm looking for what causes the error (which I didn't mention at all): why 'subFiles' wasn't initialized.
The array subFolders has not been initialized properly. In order to use the array in the Array.set method it must be initialized and allocated with a size.
An alternative approach for this is to use a List instead. Lists are good when you are working with data that is more dynamic e.g. when you do not know the size of the array. Then you can simplify your code like this:
File[] subFiles = file.listFiles();
// Create the list
List<JxploreFile> subFolders = new ArrayList<>();
// Add all the sub folders (note that "file" is a bit magic since it
// is not specified anywhere in the original post
for (File subFile : file.listFiles()) {
if (subFile.isDirectory()) {
subFolders.add(new JxploreFile(subFile));
}
}
// Return an array
return subFolders.toArray(new JxploreFile[subFolders.size()]);
You can also simplify the whole thing even further by using a Java 8 stream like this:
return Arrays.stream(file.listFiles())
.filter(File::isDirectory)
.toArray(JxploreFile[]::new);
For more info:
Creating Objects in Java
Arrays
There is no question in your post, but anyway here the problems I found in your code :
File subFolders[];
int p = 0;
for(int i = 0; i < subFiles.length; i++)
{
if(subFiles[i].isDirectory() == true)
{
Array.set(subFolders, p, subFiles[i]);
}
}
when calling Array.set you never initialized subFolders which will throw a NullPointerException.
Also, you dont need to do
if(subFiles[i].isDirectory() == true)
you can simply do
if(subFiles[i].isDirectory())
as subFiles[i].isDirectory() is already a condition.
My project consists of 2 class files and a test application GUI interface to use the data. The two class files, both created by me, are ToolItem (defines a hardware tool with get() and set() methods, display() method, etc) and HardWareStore, which is used to manipulate the data and place it into an array using methods like insert(), delete(), searchArray() ect.
The GUI interface, which includes the same relative buttons (insert, delete) calls HardWareStore when the corresponding button is pressed.
So far everything works perfectly EXCEPT the delete button/delete() method. My methods are as follows, including the searchArray() method I created which is used inside delete() to evaluate a unique ID and determine if the ID already exists or not:
searchArray:
public int searchArray(int id)
{
for (index = 0; index < toolArray.length; index++)
{
if (toolArray[index].getToolID() == id)
{
System.out.println("ID found at location " + index);
return index;
}
}
return -1;
}//end searchArray
delete:
public int delete(int ID)
{
testArray = searchArray(ID);
if (testArray != -1)
{
toolArray[testArray].setQuality(0);
toolArray[testArray].setToolName("");
toolArray[testArray].setID(0);
toolArray[testArray].setNumberInStock(0);
toolArray[testArray].setPrice(0.0);
//counter for number of items in array. Array holds 10 objects
numberOfItems--;
//shifting cells
for (index = testArray + 1; index < toolArray.length; index++)
{
toolArray[index - 1] = toolArray[index];
}
toolArray[toolArray.length - 1] = null;
System.out.println("Successful deletion");
return 1;
}
else
System.out.println("ID not found");
return -1;
}//end delete
And here is the corresponding GUI button used to delete the data in my test application:
else if (ev.getSource() == deleteBtn)
{
input = idFld.getText();
idInput = Integer.parseInt(input);
responseCode = store.delete(idInput);
if (responseCode == 1)
{
messageFld.setText(idInput + " - Successful deletion");
}
else if (responseCode == -1)
{
messageFld.setText(idInput + " - ID not found");
}
}//end delete button
Now, everything inserts fine, detects duplicate ID's, and so on. The delete method also works, letting me know that the user passed ID has been deleted at toolArray[index] as well as all of it's related data members.
The error occurs when I go to display the items in the array. The first 9 items display fine using JOptionPane, but when I reach item 10(my delete method is supposed to shift all cells to the left after deletion) I get several runtime errors starting with:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException.
I'm pretty sure my error starts with the delete() method in HardWareStore, specifically my loop to delete and shift the items to left. I've messed with it for a few hours but I cannot seem to find why, and my attempts to change the loop either result in another runtime error, or the method doesn't behave like it should.
I have only one general remark, and that's not to use Java primitive Arrays. Save yourself a lot of trouble and use ArrayList. That way you can simply remove an element at an index, there's no need then to manually manage elements in a primitive array.
Without a clear exception trace and a code snippet that shows how things are displayed I'm just speculating, but when you delete an item you shift everything manually and append a null value at the end of the array. When your array is then displayed you are most likely hitting a NullPointerException when dereferencing a null object.
In general you should only rarely have the need for primitive arrays. Use an ArrayList instead and delete items using its remove method.
public void returnRental(Customer cust){
Rental toDelete = null; //Rental to be removed from list.
LinkedList<Video> toReturn = null; //List of videos to be added to inventory.
//Find appropriate rental according to customer name.
for(int i = 0; i < rentals.size(); i++){
if(cust.getName() == rentals.get(i).getRentee().getName()){
toReturn = rentals.get(i).getRented();
toDelete = rentals.get(i);
}
}
here is the snippet of code that is giving me problems. I've debugged it in eclipse quite a bit which ended up just confusing me more. It hits the if, and passes the condition. But once it gets to assigning values to "toReturn" it assigns it an empty list with size 0. Where as I check my rentals Linked list and the correct value are there, but for some reason it is not getting assigned to my variables correctly :( The same happens to "toDelete" but this isn't a list, it is one instance of my class Rental. (The linked list is a list of rentals, which contains a linked list of videos)
No errors are thrown...
Its a little difficult to explain, if you need more information please let me know and i'll clarify.
I'm at a loss, possibly because I'm not iterating through my linked list correctly?
Replace
if (cust.getName() == rentals.get(i).getRentee().getName()){
by
if (cust.getName().equals(rentals.get(i).getRentee().getName())){
You can't compare strings with == (except if your algorithm can ensure this is the same instance, which is almost never the case).
But the missing equals is not the only bug. It may be inside getRented() or elsewhere (you don't show what you do with toReturn and toDelete, so it's not clear if you don't have problems here).
Now, to go on chasing your bugs, you should either
debug, and put a breakpoint in your loop to check the state of rentals.get(i) and the execution at this point
if you can't debug, put a lot of System.println, so that you know what you have...
I've upvoted dystroy's answer because incorrect string comparison is always wrong.
But because that would fail differently (customer names not matching rentee names), I'm wondering if your issue is really caused by either of the following:
a problem in getRented(); or
cust having a null name on call, which would match a Rentee with a null name.
Possibly, your if condition is being hit more than once. First of all, check if this is actually happening. If so, check your logic and determine if you want to stop at the first occurence or at the last (this case seems to be the latter).
If you want to stop at the first occurence, break the iteration:
for(int i = 0; i < rentals.size(); i++){
if(cust.getName() == rentals.get(i).getRentee().getName()){
toReturn = rentals.get(i).getRented();
toDelete = rentals.get(i);
break;
}
}
for(int i = 0; i < rentals.size(); i++){
if(cust.getName().equals( rentals.get(i).getRentee().getName())){
toReturn.addAll(rentals.get(i).getRented());
//assumming it returns the list of Video object
toDelete = rentals.get(i);
}
}
im currently working on a multiple class assignment where i have to add a course based on whether the prerequisites exist within the program.
im storing my courses within the program class using a hashmap. (thought i would come in handy) however, im having a bit of trouble ensuring that these preReqs exist.
here is some code ive currently got going
public boolean checkForCourseFeasiblity(AbstractCourse c) throws ProgramException
{
AbstractCourse[] tempArray = new AbstractCourse[0];
tempArray= courses.keySet().toArray(tempArray);
String[] preReqsArray = new String[1];
preReqsArray = c.getPreReqs();
//gets all course values and stores them in tempArray
for(int i = 0; i < preReqsArray.length; i++)
{
if(courses.containsKey(preReqsArray[i]))
{
continue;
}
else if (!courses.containsKey(preReqsArray[i]))
{
throw new ProgramException("preReqs do not exist"); //?
}
}
return true;
}
ok so basically, tempArray is storing all the keySets inside the courses hashmap and i need to compare all of them with the preReqs (which is an array of Strings). if the preReqs exist within the keyset then add the course, if they dont do not add the course. return true if the course adds otherwise through me an exception. keep in mind my keysets are Strings e.g. a keyset value could be "Programming1" and the required prerquisite for a course could be "programming1". if this is the case add then add the course as the prereq course exists in the keyset.
i believe my error to be when i initialize mypreReqsArray with c.getPreReqs (note: getPreReqs is a getter with a return type String[]).
it would be really great if someone could aid me with my dilemma. ive tried to provide as much as possible, i feel like ive been going around in circles for the past 3 hours :(
-Thank you.
Try something like this, you don't need tempArray. The "for each" loop looks lots nicer too. If you want to throw an Exception I would put that logic in the place that calls this method.
public boolean checkForCourseFeasiblity(AbstractCourse c)
{
for(String each : c.getPreReqs())
{
if(! courses.containsKey(each))
{
return false;
}
}
return true;
}