JTable runtime error - java

I have set a JTable to initialize at the beginning of the program, and I set it to a DefaultTableModel:
public DefaultTableModel usernameScraperTableModel = new DefaultTableModel();
private JTable usernameScraperTable;
I then initialize the table inside the constructor as below,
this.usernameScraperTable = new JTable(this.usernameScraperTableModel);
this.usernameScraperTableModel.addColumn("Username");
and then in my actionPerformed(ActionEvent) for my startButton, I run a method. If something is collected, it is supposed to add it to the table.
this.usernameScraperTableModel.addRow(new Object[] { user.getName() } );
It works somewhat. During run-time, the table is blank and doesn't show anything. I know this because in my Eclipse console it's working like it's supposed to. But after the method is done running, it then has the JTable update and all of the names are there.
I'm wondering how I can have my table update in real time inside of an ActionEvent of a button.
EDIT
Thanks for this. It still doesn't work though. I used WindowBuilder from the Eclipse website, and it's a JFrame. When I click start, the GUI kind of "freezes" (I can't click anything else, can't press the exit button, anything) until the method is done with

So I believe you want the method fireTableDataChanged() which is part of DefaultTableModel, which is usernameScraperTableModel in your case

Related

Concurrency problem in updating Jtable/Jframes?

I will try to describe the problem as accurately as possible, since this is a legacy project from someone else that I am trying to fix (to the best of my abilities).I cannot build an accurate working example due to the way this project is done. The way this program was built is wrong in many places so just pinpointing the problem would help me immensely.
There is a Jframe with a menu bar and table. The frame switches between Tables based on which option you click within the menu bar. Here's the problem: When updating the table, the first table seems to be fine, but the other ones fails to update its view properly if something is changed (specifically, it doesn't update upon deletion, but insertion seems fine). This is how the main table is made:
public void start(){
mainTable=new Jtable(model){
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
/* tons of styling here */
};
}
/* a bit more styling? */
renderSecondTable();
renderThirdTable();
}
I apologize for this ugly code, the codebase itself is even worse. Does rendering other tables by calling a method within this "start()" function lead to concurrency problems? Which is why updating the view is problematic? Extra information that might help:
each table has a seperate Frame, so there is a main frame and then a smaller frame that displays the tables
buttons for each table (delete, update etc.) are also added in by calling in extra methods like RenderButtonsForTable1()
They are all AbstractTableModel
calling FireTableDataChanged() or other similar functions do not seem to do work for non-main-tables
revalidate and repaint also doesn't work
The table does NOT use removeRow or fireTableRowsDeleted to remove the rows, there are seperate functions that do this with object streams (I don't quite understand this yet). The view seems to update automatically for the main table just fine.
Again I apologize if this is extremely confusing and ugly, the original creator didn't seem to understand what he was doing either :/
Edit: More clarification!
It seems that it does in fact only have one MAIN frame, and this
frame swaps out multiple Jpanels (each with a different Table). Within each Panel there is also a scrollpane
Deleting from the main Panel causes no problems, but deleting entries from other Panels require the Frame to be reopened or else the entry just stays there (also breaks the frame/panel completely if you empty the entire table)
The entry is properly disposed of in the backend (as far as I can tell)
any insert/delete is done through an action listener for the corresponding button
Each table has a seperate Tablemodel (all extends AbstractTableModel) with its seperate functions that all do the same thing
Table is filled with data read from a database
all tables are made in the same fashion as the main one above with prepareRenderer
I also drew up a vague diagram of how the Jframe looks:

swing tableChanged() not responding to table changes

I'm coding in Swing in Java. I'm using the Netbeans layout manager. I'm having trouble with a jTable. I've applied a customer model to it which extends AbstractTableModel. I want the third column to contain boolean values in the form of checkboxes (this I have done successfully). The dialog I have the jTable in implements TableModelListener. My tableChanged() method has only the following code: System.out.println("Table changed!");
However, whenever I try to check one of the checkboxes, it does the little "suppression" thing when I click and hold, then when I release, it doesn't change the checkbox's state. It also does not print out "The table has changed!" This has been driving me crazy. I've read all about it, but can't figure out why mine's not working. Please help. Here's the relevant code:
In jDialog constructor:
this.chapterTableModel = new ChapterTableModel(chapterList);
chapterTableModel.addTableModelListener(this);
And then a method which does this: chapterTable.setModel(chapterTableModel);
Then below my constructor, I have this method:
#Override
public void tableChanged(TableModelEvent tme) {
System.out.println("Table Changed!");
}
The entire code can be found here: http://collabedit.com/ttcds
and here: http://collabedit.com/qn3kx
Thanks for your help in advance!
Are you calling one of the fire-methods of the parent AbstractTableModel class in the mutators of ChapterTableModel?
You are not overriding setValueAt anywhere so the value in your table isn't being changed.

Java Swing Threading Problem

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

Cast Object to JTable?

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.

focus issue using a JComboBox as a cell editor in a JTable

I'm having issues with the following code, where I use a JComboBox to change a String value in a table cell. The JComboBox works fine, but if I click in the box and then click away without selecting anything the JComboBox's dropdown remains visible, even if I delete the row. Clicking on another Swing component like a JButton often causes it to go away, but not always.
TableColumn col = myTable.getColumnModel().getColumn(0);
JComboBox eq = new JComboBox();
eq.addItem("==");
eq.addItem("!=");
DefaultCellEditor editor = new DefaultCellEditor(eq);
col.setCellEditor(editor);
Edit:
I had neglected to mention that earlier I set:
myTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
If I comment this line out or set it false, then clicking on other Swing components does NOT cause the box to vanish. With it in, clicking on anything that takes focus causes the box to go away, making the problem less annoying but possibly masking the cause of the behavior.
Am I doing something wrong here, or forgetting a step? Alternately, is there a way to force it to close itself?
Thanks!
To understand this you'll need to understand what goes on with an editable table. A short bit of theory:
Every cell has a potential renderer and editor. The renderer just tells the cell how to draw and does not interact with events. The editor however is a component that can interact with events. When an event happens that triggers an edit, the editor component is added on top of the table. When the edit finishes, the component is removed.
In order to get the component to go away, you'll have to make sure the cell is not still in the "editing" state. This is why terminateEditOnFocusLast causes the JComboBox to vanish. If you want other things to get the box to go, you'll need to probably call removeEditor() in response to certain events, possibly focus, or cell selection.
To really get a handle on what happens I'd recommend having a quick look at the source code to removeEditor(), editCellAt() etc., and maybe step through once in a debugger. It's possible you've overridden some of the event handling code, or are calling it when you shouldn't. The editor/event handling code in JTable is fairly fragile, and it's quite easy by accident to get calls to happen in the wrong order with funny side effects.
Also, Java very subtly changed the event and focus behaviour of JTable between versions once, I think it was between 1.4 and 1.5, when the focus handling for swing changed. So the first thing I'd recommend trying is your code with a different Java version. The bug may have been caused by Sun (some of our complicated editor code had to be changed) and if it differs between releases it is easier to report to Sun.
I know this question is old but for reference here is my solution. I extend the DefaultCellEditor and listen for the JComboBox to be canceled then force the editor to cancel.
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
public class ComboBoxCellEditor extends DefaultCellEditor {
public ComboBoxCellEditor(JComboBox comboBox) {
super(comboBox);
comboBox.addPopupMenuListener(new PopupMenuListener() {
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
}
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
}
public void popupMenuCanceled(PopupMenuEvent e) {
cancelCellEditing();
}
});
}
}
Then ...
DefaultCellEditor editor = new ComboBoxCellEditor(combobox);
column.setCellEditor(editor);

Categories