I am making a student record application... I want a column in it which is editable.
I have attached table model listener on table and on that column i m saving all the updating values
if(table.getSelectedColumn() == 3 && table.getSelectedRow() != -1 && tme.getType() == TableModelEvent.UPDATE)
{
// my code here
table.cellEditAt(row,column); // this is giving me error
}
table.cellEditAt automatically calls table model event and that is producing a infinite loop... Any other method to automatically select a cell for editing????
please post an SSCCE that demonstate your issues, for example based on my question about Infinite loop by implements TabelModelListener linked to my answer,
The answer was to post an SSCCE. We are not mind readers. We can't guess what your editCellAt(...) method does. If it causes a loop, then that would be because you are somehow changing the model and generating another TableModelEvent. Don't do this!
If the problem is somehow related to placing a cell in edit mode, then I would guess you need to wrap that code in a SwingUtilities.invokeLater() to make sure the processing of the original event is completed before you place another cell in edit mode.
Related
I've read through a dozen or so actionlistener/loop related questions here, but I'm not sure I've found my answer. I started on my first large Java project, a text RPG that's spiraled into around 5K lines of logic and game features which was functioning as intended using just the console - when I decided I'd try to build a Java swing GUI for it instead. Here's my problem:
I use a Room object which handles the description of where the player is at and also has an array of options for the player to choose next which it creates dynamically based on what cell the room's id is in on a csv file and what is beside it. I stopped outputting this to the console and instead started creating JButtons based on the options array like so:
public void showNarrate(){
add(dd,gridConstraints);
optionCopy.clear();
int i = 0;
for(JButton j : optionButtons){
//adding and formatting buttons to gridBagConstraint I also set actionCommand for each button to the triggerValue (ID of the next room which the button should take the player to)
}
//I tried using a copy of my JButton array here so I could have something to iterate over in actionListener after clearing out the original
//(Since it needs to be cleared so the next Room's buttons can be built after the player chooses an option)
for(JButton j : optionButtons){
optionCopy.add(j);
}
optionButtons.clear();
//dd is a seperate drawingComponent I used for outputting room descriptions which may be totally unnecessary at this point :/
dd.repaint();
setVisible(true);
}
Over in actionlistener (Same class) this is how I tried to swing it:
for(JButton j : optionCopy){
if(e.getActionCommand().equals(j.getActionCommand())){
Main.saveRoom = Main.currentRoom;
Main.currentRoom = j.getActionCommand();
System.out.println(Main.currentRoom);
}
}}
Then in my main class I call:
narrator.narrate(currentRoom, saveRoom); which takes care of some other logic concerning locked doors, encounters, etc.
Also in Main loop are some other methods related to autosave and tracking which rooms the player has visited. I know from other q/a i'v read on here that this is all pretty bad design, and I'm sttarting to understand that now, but my issue is this:
The first room of the game loads up fine, when I click a button it outputs to console(Just for testing) the correct trigger value of the room the button should be calling, so I'm getting that far, but how can I call the same method over again now?
-If I call narrate from actionListener it will wind up calling itself again and complain about ConcurrentModification.
-If I try to keep a loop going in my Main class it will keep looping and won't allow for the player to actually choose a button.
I've never used threads before, which I wonder might be the answer,and the closest thing to a related answer I've found is this:
Java: Method wait for ActionListener in another class
but I don't think moving actionListener to Main class would resolve my problem which is actionListener winding up calling itself recursively. And as for the observer-observable pattern... I just can't understand it :(
I appreciate any and all help, I've learned a LOT trying to make this thing work without seeking help as much as possible but this has stumped me.
Your loop in actionPerformed only checks whether a JButton exists in your optionList with the given actionCommand. However this can be done before actually doing something:
boolean contained = false;
for (JButton j : optionButtons)
if (j.getActionCommand().equals(e.getActionCommand()))
contained = true;
if (contained) {
// change room
}
now you can call narrate because you have finished iterating over the collection beforehand and will not get a ConcurrentModificationException
Hi I'm trying to transfer one object from one combobox to another and vice versa.
To accomplish this,
I use actionListeners or ItemListeners, to no luck that they dont answer my problems, or maybe there's just something wrong in my implementation.
Assuming we have to comboboxes, combobox1 and combobox2.
Basically,
1. I first add the selected item to another combobox (combobox2)
2. I remove the selected item on the first combobox (combobox1)
When trying to debug this, i found out that everytime i am on the step of removing items, the listener of the other combobox fires, which does the same steps as above. This results into a loop, that just deletes the item, and places it back to the original combobox.
When using the ItemListener, with the proper if conditions of being selected or not, it throws a bigger error. Guys please help me..
*on edit mode/currently making an SSCE
Found this, as suggested by sir mKorbel.
It did the trick, setting the model via setModel(DefaultComboBoxModel model) method doesnt trigger the ActionListener when it tries to add the contents of the model passed, versus the addItem(Object obj) method that fires the ActionListener causing the havoc that i described on my question above.
Thanks guys, and i learned about a new thing called DefaultComboBoxModels!
jComboBox12.removeAllItems();
for (int t = 0; t < jComboBox11.getItemCount(); t++)
{
jComboBox12.addItem(jComboBox11.getItemAt(t));
}
so here's the problem. I have a JDialog box that consists of 3 combo boxes, a text field, a few buttons and a JTable. The JTable information is filtered based on the text field and combo boxes, so for instance it starts with all of the data and gets shrunk down to only the data that starts with any string value the user decides.
What's happening though is that while the values filter correctly, if I click in the JTable (in the white space, where there are no rows) then the rows that were deleted show up, like they were invisible until I clicked on them. I've tried almost everything:
I've tried re-creating the table every time filter is clicked (bad hack that didn't even work), I've called all of the repaint, revalidate, firechanged methods, I rewrote the dialog from scratch to make sure I didn't do any stupid mistakes (if I made one I didn't find it at least), and I've tried putting them on separate threads. The only fix I haven't tried is using a swing worker, but that's because my filtering was a little too complicated for me to figure out what goes where and how to extend the swing worker correctly. The GUI is generated by netbeans (bleh), and has worked in my other dozen or so JDialogs just fine (perfectly in fact). Here's the method that doest the filtering, if any of you can help it would be greatly appreciated.
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
nameFilter = "task1";
javax.swing.table.DefaultTableModel dm = (javax.swing.table.DefaultTableModel)jTable1.getModel();
tempParameters = parameters;
String currentString;
int rowNumber = 0;
while (dm.getRowCount()>rowNumber){
currentString = (String)(jTable1.getValueAt(rowNumber,1));
if(!nameFilter.equalsIgnoreCase(currentString.substring(0,nameFilter.length()))){
dm.removeRow(rowNumber);
parameters--;
}
else rowNumber++;
}
parameters = numOfRows;
}
Update, I also implemented the filter from the comment below, and while it filtered out the correct data, it had the exact same problem. In the future I will probably use this filter feature though, so thanks.
Another update, the code is still failing even after removing everything but this chunk, and all (at least I believe..) I am doing here is doing a simple remove row call. Hope this helps a bit.
Have you tried creating a new Model every time you want to filter, instead of clearing it by deleting rows? Create new model, copy relevant rows to new Model, set new Model in table. Really shouldn't be necessary, but it might be a quick fix.
Also, I really have to wonder why you're calling toLowerCase on two strings when you're using equalsIgnoreCase to compare them.
So long as this method is called from the EDT I don't think there would be a threading problem. Try using
SwingUtilties.isEventDispatchThread()
to make sure.
If you look at the API for DefaultTableModel, updates are being sent to your JTable which will repaint itself, so I don't think that is the problem.
I would guess that it is a logic problem. If you can extract the logic into separate methods it will be easier to test and verify whether it is updating the model as you expect.
Couple of observations:
If the filter happens to be larger than the string content of the row, it'll throw in the substring call
Calling the dm.removerow is generating a bunch of tablerowsdeleted events.
You're asking for a rowcount from the model, yet are getting the value through the table (a little inconsistent, if the model gets wrapped around another model you might be acting upon different rows), so instead of jtable1.getvalueat, use the dm.getvalueat.
I think what might be happening is that as the events get fired I see there are repaint and revalidate events fired in the JTable, these can be trampling over each other as they get enqueued in the EDT.
What I would suggest is to create a new datamodel, add the rows that you want to keep, and then reassign it to your jTable1.setModel(newDm);
Also to watch for is if someone else is modifying the model while you're in your eventlistener.
Hope this helps
I am trying to implement a ListSelectionListener for some of my JTables. Simply (at the moment) the ListSelectionListener is supposed to simply return the text of the cell that was selected.
My program design has several JTables and I would like to have one ListSelectionListener work for them all. In the valueChanged event of the ListSelectionListener I thought it was possible to do something like:
private class SelectionHandler implements ListSelectionListener {
public void valueChanged(ListSelectionEvent e)
{
JTable table = (JTable)e.getSource();
String data = (String) table.getValueAt(table.getSelectedRow(), 0);
// Print data
}
}
Behind the scenes I have used the following code to get the SelectionHandler working with the table in question:
fbTable.setCellSelectionEnabled(true);
ListSelectionModel cellSM = fbTable.getSelectionModel();
cellSM.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
cellSelectionModel.addListSelectionListener(selectionHandler);
When I run the program I get a ClassCastException error:
Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: javax.swing.DefaultListSelectionModel cannot be cast to javax.swing.JTable
at cardboardfantasy.CardboardFantasyView$SelectionHandler.valueChanged(CardboardFantasyView.java:360)
// This is the line in question: JTable table = (JTable)e.getSource();
Is there a way to do something like this? One solution I thought of was to compare the source of the event (e.getSource()) to all my JTables to see if they were equivalent (big if block) and then just calling .getValueAt inside that block but that would making the code in the future difficult if tables were to be added or removed.
Either debug your code in your IDE, set a breakpoint and see what the type of e.getTarget() is:
Object source = e.getSource();
JTable table = (JTable)source; // breakpoint on this line and inspect the variable 'source'
String data = (String) table.getValueAt(table.getSelectedRow(), 0);
Or if debugging is not possible for whatever reason do this:
Object source = e.getSource();
System.out.println(source.getClass());
But: debugging using System.out.println is evil. your debugger is your friend.
As the error implies, the source object in question is a DefaultListSelectionModel not a JTable. This makes sense since the source of the event (that is, the object which fired the event) was the selection model object, not the table. Also, models in themselves make no assumptions about what type of object is using them as a model so there is no way to get a reference to the table via the selection model.
Pass the JTable instance to your selection handler. As long as the handler listens on one table, you'll be able to use that instance instead of relying on the information from the event.
I think there are two main solutions:
Use a JList and register the listener not with model but directly with the list. Then, if the list is contained by a table you could just ask for the list's (Component) parent to find the responsible table
Override DefaultListSelectionModel to (for example) take an additional argument in the constructor, which would be a JTable instance (every table will need a new instance of that model). You would save that instance in an instance variable and could then operate directly on the table when an event occurrs
I do not think that either of these solutions is ideal. I have the feeling that you could make your life easier by using some pattern or idiom to get around having to know which table the source was. But to give you any clues there we'd have to see a lot more of your code.
I have 2 trees in my program. Iam using JTree's clearselection() method to clear the selection in 1 tree when something in the other tree is selected. The main code is something like this:(inside a valueChanged event listener and tree being the one on which the current selection has been triggered)
if ( tree == tree1 ){
tree2.clearSelection();
} else {
tree1.clearSelection();
}
When I select for the first time, it works fine. But when I try to select from a different tree after this, it appears the valueChanged method is getting called twice. Any solution?
Did you use the code I gave you in this question?
This included a flag to get round the problem of introducing an infinite loop, and should also ignore subsequent selection events when it is processing the current one.
BTW Given this relates directly to the previous question you may have been better off just commenting on the previous post. That way all the context is kept in one place.
clearSelection() triggers valueChanged as well, so you need a workaround, add some flag and do not clear selection when it's true.
EDIT. Seems like using some flag is tricky. Can you use MouseListener instead and run same code within mouseClicked event?