My GUI includes a JTable and several forms that may trigger INSERT, UPDATE or DELETE SQL queries. Whenever it happens, I want my table to be updated accordingly. Since both the TableModel and the remote SQL table must be updated, there are several ways to proceed.
Update the SQL table first, then SELECT the modified data, and call fireTableDataChanged(). This is what I am currently doing. It guarantees that the table and the database are perfectly synchronized. However, the TableModel is not updated until its data is extracted from the ResultSet, and it the whole thing takes between 0.5 and 1 second on average in my case. Which is not too bad, but not too good either.
Update both of them at the same time, modifying the TableModel to match what I would expect to previous method to do. This could improve performance on the client's side, since changes would be almost instantaneous, and SQL stuff would be ran "in the background". But I feel unsure about losing sync between the table and the database, this looks like the dirty way.
Mix these two methods. Perhaps quick, single-cell updates should use the second method, while INSERTs and DELETEs would require the first one? It feels inconsistent, though more efficient.
Is there another way?
How should I proceed? Please share your experience on this matter.
I like your first choice with updating JTable from SQL table using SELECT.
If you worry about 0.5-1 second pauses - you can mix first and second variant in following way: instantly update table with "expected" result, execute SQL, then SELECT modified data and check if it is the same as current. I think in most cases they will be the same so no updating of JTable will be needed, but also you get synchronized models.
The first approach that came to my mind is to create a subclass of AbstractTableModel, and store the data in its private ArrayList<?> field. In its constructor, query the database with the data you want to show in the table.
If a row is added to the table, an INSERT statement with the data inserted will be fired to the DB.
If an update to a cell in the table is done, validate if the update is possible. If possible, an UPDATE will be fired to the DB
If a row is deleted, a DELETE FROM statement will be fired to the DB.
public class MyTableModel extends AbstractTableModel{
private List<Person> dataSource;
public MyTableModel(){
dataSource = new ArrayList<Person>();
//query the database then add the queried data to the dataSource,
//you should do it in the background, using SwingWorker
//call fireTableRowsInserted with proper arguments
}
#Override
public int getColumnCount() {
return 3;
}
#Override
public int getRowCount() {
return dataSource.size();
}
#Override
public Object getValueAt(int row, int col) {
Object retVal = null;
if(col == 0)dataSource.get(row).getFirstName();
else if(col == 1)dataSource.get(row).getLastName();
else if(col == 2)dataSource.get(row).getOccupation();
return retVal;
}
#Override
public void setValueAt(Object value, int row, int col){
//validate if the update is possible, if yes proceed
//update the value in the DB
//update the value in the arraylist
//call super.setValueAt(value, row, col);
}
public void addRow(Person p){
//validate if the person is insertable, if yes proceed
//INSERT the person to the DB
//add the person to the arraylist
//call fireTableRowsInserted
}
public void deleteRow(int row){
//call fireTableRowsDeleted
}
}
Update the SQL table first, then SELECT the modified data, and create a new TableModel using the returned ResultSet. This is what I am currently doing. It guarantees that the table and the database are perfectly synchronized. However, the TableModel is not updated until its data is extracted from the ResultSet, and it the whole thing takes between 0.5 and 1 second on average in my case. Which is not too bad, but not too good either.
wrong idea there is more than contraproductive to create a new XxxTableModel, one XxxTableModel can be used for all views, for a few JTables/JLists notice only in the case if isn't there used RowSorter or RowFilter, then logics in code must contains filtering sorting for all JTables based on one XxxTableModel
for static data (StandingData) to create separate XxxTableModels
Update both of them at the same time, modifying the TableModel to match what I would expect to previous method to do. This could improve performance on the client's side, since changes would be almost instantaneous, and SQL stuff would be ran "in the background". But I feel unsure about losing sync between the table and the database, this looks like the dirty way.
no idea, basically if the value from input mask (form) are stored in Databases, JTable should be refreshed and input form ended with default value
could be way, but required to synchonize databases, its mirror in JTable and input mask
Mix these two methods. Perhaps quick, single-cell updates should use the second method, while INSERTs and DELETEs would require the first one? It feels inconsistent, though more efficient.
maybe not in context of a.m. 3 points
Is there another way?
yes therer are a few ways but My GUI includes a JTable and several forms that may ... can complicating the simple things
create one JFrame with
JSplitPane and there could be one area for all input masks laid by CardLayout, second for JTable, only one JTable, with one XxxTableModel (you can to add StandindData in JList or another JTable on south or west/east area with intention to fill free space in the container)
use BorderLayout, in center are input masks layed by CardLayout, see rest in above mentioned point 1st.
add a few JTables/Lists (see for example the screens for Bloomberg or Reuters Xtra3000) to one JFrame, add JPopupMenu for these Objects with JMenuItems add, amend, delete, modify .... items in JTables/Lists, then to create only one JDialog layed by CardLayout, and contains on apps startup all input masks, then output from JPopupMenu will be contains three code lines switch to card based on source, call pack for JDialog, call setVisible(true) for JDialog, but must be wrapped into invokeLater,
reset all JComponents in the input mask after data are saved in database, before setVisible(false) is called, otherwise next visibility can to flashing/refresh with value in JComponent
nobody guarantee that data from input masks are saved in database and correctly,
e.g. there could be defined triggers, that fills value for rest of columns, then all dataflow could be asynchronous, delayed by internal database rulles
data flow must be to save data to database, if PreparedStatement is executed without exception, then you can to refresh input mask to default value, next step could be to load data to XxxMableModel, and if is there popup JDialog, then now is moment to hide JDialog
if is there an exception, then nothing will be happened with input mask and theirs value, better and safe for user, is possible to simulating in based on, can to create an screenshot and then to report it ....
Related
Hello every one I m lost with this problem :
I have a Jtable and I fill data from mysql database ,
but I want the table to be refresh by a timer every
xx seconds. Really i don't know how to do ?
I would appreciate some direction/help.
Use a javax.swing.Timer, with setRepeats(true) so that it repeatedly fires an ActionEvent. In your ActionListener, run the query against the database. The easiest approach is to throw away your old table model, generate a new one from the new database results, and call setTableModel on your JTable. (A more sophisticated approach is to work out the differences to the previous query results and only update those table cells that have changed, but you may not need this refinement.)
So far, I talked about an ActionListener doing the work of regenerating the table model, but a more elegant solution might be to have a custom table model that knows how to update its own data from the database - and will do so, for example, on invocation of (say) an updateFromDatabase() method. So the TableModel has the responsibility of updating itself and the Timer/ActionListener has the responsibility of deciding when these updates should happen.
As already mentioned by Kalathoki, changes to the model layer are not seen in the JTable view component unless the model layer notifies the JTable that the model has changed. If you're calling setTableModel on JTable, then the JTable knows that the model has changed, but if you have a custom table model that (from the point of view of the JTable) 'secretly' refreshes itself from the database, then you need to make sure that the JTable is notified by calling the fireTableDataChanged() method.
Another consideration is how long the database refresh takes. You would not want your UI to freeze up for long periods while the JTable refreshes, so a further refinement would be to use a SwingWorker so that the database query is run in a background thread. In this case the Swing timer would be used to initiate the SwingWorker, and the SwingWorker would use its done() method to update the table model and fire an event to the JTable view component.
Use fireTableDataChanged() Method. Click Here fore more details
I'm using a JTable, and I need to allow moving of its columns. But there comes the problem. Once they have rearranged, it's like just they have changed there content and title only. But I also need their indexes to be changed as well.
To make this more clear, I'll give an example. Let's say my first column is called "names". When calling the 'setName()' method, a name must always go to that column, no matter where the column is. But not to the first column..Hope you got my point!
I've finished writing required methods. Hope there is a way to achieve this without touching the finished methods.
Any help is much appreciated!!!
To make this more clear, I'll give an example. Let's say my first column is called "names". When calling the 'setName()' method, a name must always go to that column, no matter where the column is. But not to the first column..Hope you got my point!
If you want to change the data, simply alter the underlying TableModel directly. The order of the columns never changes in the TableModel, it is only in the view (the JTable) that those columns are re-ordered.
If you do want to go through the table, you will have to convert from 'view-coordinates' to 'model-coordinates' by using the available JTable#convertColumnIndexToModel (view -> model) and the JTable#convertColumnIndexToView (model->view) methods as #MadProgrammer mentioned.
You should certainly not update the setValueAt method of the TableModel as you mentioned in one of your comments. As said before, the TableModel does not change the order of the columns, so the setValueAt should always be called with 'model coordinates', hence there is no need to transform those
Oh yeah, I love this, it always gets me ;)
Check out JTable.convertColumnIndexToModel(int viewColumnIndex) and JTable.convertColumnIndexToView(int modelColumnIndex)
Essentially, you need convert the column index to and from the view index.
You shouldn't need to worry about this with the TableModel as it's taken care for you my the JTable.
You'll have a similar issue with the RowSorter
So I am working on a GUI that involves working with tables that can be sorted. I am noticing that when I sort a table, and I select a row from the newly sorted table, the selected row index of that row points to the data row from before the sort. I understand that this is because the view has changed, but the model has not; thus, you have the need for convertRowIndexToModel. It is also to my understanding that one can automatically update the view based on changes to the model by firing TableModelEvent's.
So here is my question: is it possible to automatically update the TableModel, based on changes to the view, so that I would not have to worry about converting the view index to table index?
All the default table code does this automatically so you don't need to worry about this. That is if you reference the model by using the table.getValueAt(...) and table.setValueAt(...) methods then you won't have a problem.
Only code that you write that tries to access the TableModel directly will have a problem. In this case thats what the convertXXX(...) methods are for.
In my system we use JTable with data model.
when data changes we remove it from the model, iterate the model and fire for each row listElementPropertyChanged (I think its intellij's). In this way removed lines are not deleted cause they are not in the model.
How do I refresh the whole table according to the model?
Simply use fireTableDataChanged(). This way, all listeners will now that all data may have changed.
However, use it with care, as usual behaviour for listeners will be to refresh the whole table.
You would have better using fireTableRowsDeleted(int, int) with the removed rows indexes.
I am doing project on java.
In one of the class, I am working on jtable.
Now what i am doing is,
In the table data will be loaded from the database.
Now i want to change some value at some exact row and column.
so for that i am using jtable's setValue function.
which is like this....
grayCardTbl.setValueAt(Float.valueOf(String.valueOf(pdiff)),1,4);
I have checked the "pdiff" variable, it is perfect.
i had total 5 columns and 10 rows. So now problem with rowindex and column index.
and after this i have also refresh the table. but still it is not reflecting on table.
The JTable.setValueAt(...) method calls TableModel.setValueAt(...).
My guess is that you've not implemented it in the model and the data doesn't get updated.
Edit: if your model calls JTable.setValueAt(...), it's going to loop into a stackoverflow. What you need to do is actually update the underlying data.
For instance if your model's getValueAt(...) does return data[row][column], then setValueAt(...) needs to do data[row][column] = value;