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 ....
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
I have two radiobuttons(Say rbtn_Asia,rbtn_Europe)and one JTable. When I select rbtn_Asia, table must contains Asia's data. Similarly when I select rbtn_Europe, table must contains Europe's data. (Asia's data and Europe's data is in same database which will be updated periodically). I have implemented upto this.
My problem is like this: Consider the following case: I have selected rbtn_Asia and obviously table will contain Asia's data. Now let database has got two new tuples of Asia, how can I update the JTable dynamically without selecting the rbtn_Asia once again (because rbtn_Asia is already in selected state).
In your button handler, update your implementation of TableModel, which should then fire the appropriate event. A structure that supports clear() such as Map, shown here, is convenient. More examples may be found here.
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.