Working with data and a JTable? - java

I have a JTable that I want to use to display some data (a String and a Boolean in each row). The data is maintained by my own class. Is there some way to bind the data model to the JTable, so that when I add to the model, the JTable is dynamically updated and when I remove something from the model, the row is removed from the JTable?
I have previously worked with Flex and Actionscript, and this is very easy to do there with data binding, so I'm just wondering how it's done in Java.
Thanks.

You will need to have your dataset implement the TableModel interface. if you do that then you can apply it to the JTable. If you extend AbstractTableModel you will inherit some event firing methods that your table will handle and will update the view. see this tutorial. Note that the default implementation of JTable will renderer your data for you, and if a Boolean is found, it will show up as a check box.

You'll probably find both the Java JTable tutorial and the JTable API documentation helpful in understanding how JTable works, but otherwise here's a quick rundown.
The premise of a JTable is that it is paired with an object that implements the TableModel interface, which by default is an instance of DefaultTableModel. The table model object is made up of a list of columns, each of which has its own data type (String and Boolean in your case), and a list of rows containing the actual data for the table.
Whenever the JTable is drawn by the swing drawing code, it repeatedly calls the method:
public Object getValueAt(int row, int col)
Thus, when you add data to the table model, it is always rendered as you expect in the next screen refresh (dynamically).
The only thing you really need to worry about, then, is getting the data from your object into the table model and back out again. Other than that, JTable takes care off all the heavy lifting.

While implementing TableModel is easy enough for simple cases, you might want to consider a true binding approach (my favorite is Glazed Lists - watch the 30 second video on how easy this is and you'll be won over). Beans Binding (now Better Beans Binding) also has an implementation of observable lists that might be useful (although I much prefer the Glazed Lists approach)

Related

JTable.clearSelection() vs Jtable.getSelectionModel.clearSelection() - When to use what?

I need to cancel all selections within a JTable model object. Java provides this function "clearSelection()" which does, what I need, as far as I understand.
But I am confused why this function can be called on a JTable object as well as on a selection model for a JTable object:
1) mytable.clearSelection();
2) mytable.getSelectionModel().clearSelection();
Both ways work, but I do not understand in what situation a clearSelection() of a SelectionModel (like at 2) ) would make any sense. As far as I understood SelectionModels, they are used to decide what kind of selections a JTable allows. I use the SelectionModel to only allow a Selection of exactly one row
//allow only one row to be selected
mytable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
Which way is to be preferred in what kind of situation? Is there a good reason not to use way 1?
I would be glad if anyone has some beginner friendly explanation for that. Thx in advance.
Here is the implementation of JTable#clearSelection()
public void clearSelection() {
selectionModel.clearSelection();
columnModel.getSelectionModel().clearSelection();
}
As you can see, there is two ListSelectionModel which are cleared, because you can select column and/or row and/or cell.
From Oracle tutorial :
JTable uses a very simple concept of selection, managed as an
intersection of rows and columns. It was not designed to handle fully
independent cell selections.
A ListSelectionModel handle all aspect of the selection such as which row is selected, how can we select some rows, etc... Not only the kind of selection !
More information in the Oracle JTable tutorial
Usually when you see two methods like that it is because the table will invoke the SelectionModel.clearSelection() method for you. So the table method is a convenience method.
In this case the actual code is:
public void clearSelection()
{
selectionModel.clearSelection();
columnModel.getSelectionModel().clearSelection();
}
So both the row and column selection models are cleared.

Java reorganizable grid

Is there any layout or library in Java to make GUIs that contain a list of data with separate items, and the rows can be reordered by clicking the top of the column. I'm sure that was a terrible job of explaining what I want, so here is a screenshot showing what I mean:
(taken from Spotify's desktop client, but you can find GUIs like this in all kinds of apps.)
How about a JTable?
Your criteria:
A list of data – yes. A table model can be as simple as an Object[][] or as complex as a custom class.
Reordering by clicking header – yes. You can use a TableRowSorter to sort when the column header is clicked.
For information on tables, see the "How to Use Tables" section of The Java Tutorial.
This document also has a section, "Sorting and Filtering", that talks about sorting with the column header. Here's an excerpt:
Table sorting and filtering is managed by a sorter object. The easiest
way to provide a sorter object is to set autoCreateRowSorter bound
property to true:
JTable table = new JTable();
table.setAutoCreateRowSorter(true);
This action defines a row sorter that is an instance of
javax.swing.table.TableRowSorter. This provides a table that does a
simple locale-specific sort when the user clicks on a column header.
This is demonstrated in TableSortDemo.java, as seen in this screen
shot:
More reference:
JTable javadoc
TableRowSorter javadoc

Swing MVC - Data in Model

I'm starting to learn how implement MVC pattern in swing. I have a confusion when in comes to the data in model.
In the application that I'm doing, I have several JTextFields. The data set in the fields come from JTable. I have a ListSelectionListener in my controller added to that jtable (in the view) so that when selection has changed, the data from the selected row will be reflected to the respective textfields
public void transferTableDataToFields(){
if(tblProduct.getSelectedRows().length != 0){
int selRow = tblProduct.getSelectedRow();
txtID.setText(tblProduct.getValueAt(selRow, 0).toString());
txtName.setText(tblProduct.getValueAt(selRow, 1).toString());
txtDescIn.setText(tblProduct.getValueAt(selRow, 2).toString());
txtSupplier.setText(tblProduct.getValueAt(selRow, 4).toString());
txtPrice.setText(tblProduct.getValueAt(selRow, 5).toString());
}
}
My question is, am I doing it the right way? Should I define fields in the model that corresponds to the textfields in my view, then change my code to controller setting the model's fields to values from view's jtable then let the model fire a property change notification to its listener, then let the listener call the update method in the view based on the property change event?
My problem with this approach is that, the view should have a method that will return the row selected from the jtable which I find a bit ugly.
EDIT
#trashgod this is what I'm saying.
Inside my TableModel implementation, is it better to populate the data here?
public MyTableModel extends AbstractTableModel{
List<Row> data;
Row header;
public MyTableModel(){
initializeData();
}
public void initializeData{
//query database here then put it in the list
}
//other methods to implement e.g. getvalueAt(int x, inty){data.get(x).get(y);}
}
Is it better if I make it like this? because currently I stored and populate the data of my table in my main model (also containing fields with corresponding textfields in the SelectedRow view) then I pass the data in my JTable's model.
In this case, the current selection is a property of the view, an instance of JTable, not the model, an implementation of TableModel.
If you choose to supersede editing in the JTable itself, a ListSelectionListener is the correct way to update your (anonymous) dependent view, e.g. SelectedRow. Your controller should have little to do except add SelectedRow as a listener to your JTable. As SelectedRow contains (presumably) editable fields, you are responsible for several things:
Propagate any changes back to the original table's TableModel, typically via setValueAt().
Convert between view and model coordinates, mentioned here.
Preclude (or synchronize via the ListSelectionListener) editing in the source JTable.
Addendum: Inside my TableModel implementation, is it better to populate the data here?
The answer depends on the application. Your TableModel implementation should expose a public API that provides as much (or as little) as required to support the application's requirements for concurrency and latency. For reference, DefaultTableModel is a general purpose example, although you'll want to use something more recent than Vector internally.

JTable help (resizing of headers and data source)

I am quite new to JTable and am perplexed over the plethora of information on it. There are several questions that I wish could be answered by you guys.
How can I set each cell value individually? Is it through implementation of a TableModel (I don't quite know how to use this)? I understand that a 2D matrix can be used to set the data beforehand.
How can I make it such that the below table's headers are nicely positioned(the entries are fully displayed)? If you look carefully at the first entry in the table, Job Grade is hidden partially. I have searched high and low for solution to this but to no avail.
http://i45.tinypic.com/24pxvmx.jpg
The concept is that you subclass DefaultTableModel with your own class. If you wanted to show a table of jobs for example, you might create a class called JobsTableModel. The JobsTableModel would typically have a collection of objects of type Job which might be passed in to the constructor. Your JobsTableModel has to be able to provide answers to the following questions:
How many rows are there
How many columns are there
What is the name of column X
What is the data type of column X
What is the value in cell (X,Y)
It does this by overriding the following methods:
public int getRowCount()
public int getColumnCount()
public String getColumnName(int columnIndex)
public Class<?> getColumnClass(int columnIndex)
public Object getValueAt(int rowIndex, int columnIndex)
The JTable implementation can then use this information to populate the table without you having to worry about setting the values in each cell. Furthermore, the JTable implementation will automatically give you sorting and column re-ordering for free. If you had to populate each cell directly, these would be a nightmare to work with.
As regards getting width right, I don't believe there's any automatic way of doing this, you just have to use some trial and error. You can set the width of column in pixels as follows:
TableColumn column = table.getColumnModel().getColumn(i);
column.setPreferredWidth(width);
As I commented above, the best thing you can do is go through http://docs.oracle.com/javase/tutorial/uiswing/components/table.html.
But to answer your two specific questions:
1) Yes you need a TableModel. You can create a new JTable by passing it arrays, but it just creates a DefaultTableModel in the background anyway. Look up Model-View-Controller architecture for more info on why you need the model.
2) You can set a preferred width on the columns with something like this
table.getColumnModel().getColumn(1).setPreferredWidth(100);
Which will give column 1 a preferred width of 100 pixels (I think it's pixels... don't quote me on that though!).
JTable is one of the most sophisticated components of Swing. So takes some time to give it a kick start. But when you get the handle of it, you will see that JTable is very strong and flexible. Having said that, let me try to answer your questions.
1)How can I set each cell value individually? Is it through
implementation of a TableModel(I don't quite know how to use this)? I
understand that a 2D matrix can be used to set the data beforehand
JTable uses a TableModel instance for the data. If you have an available array or Vector with pre-loaded data, you can simply use DefaultTableModel. If DefaultTableModel is not flexible enough for your requirements, then do not hesitate to implement your TableModel by extending AbstractTableModel. AbstractTableModel has only the following three abstract methods, so it is really easy to implement a concrete TableModel by extending AbstractTableModel. :
public int getRowCount();
public int getColumnCount();
public Object getValueAt(int row, int column);
2)How can I make it such that the below table's headers are nicely
positioned(the entries are fully displayed)? If you look carefully at
the first entry in the table, Job Grade is hidden partially. I have
searched high and low for solution to this but to no avail.
http://i45.tinypic.com/24pxvmx.jpg
You can find an example for automatically setting column widths here: http://www.exampledepot.com/egs/javax.swing.table/PackCol.html
The code example in this link uses all column data for calculating preferred column width. I guess it can be adapted for your requirement as well.

fireTableDataChanged has no effect on JTable

I have a problem with updating my JTable in Java Swing.
The datas I want to show changes a few times per second and I look for a efficient way to update the data in the JTable.
I used the method setModel() to update the data, and it works, BUT it has 2 drawbacks:
If the user resize the table columns in the header, then he wil get about 10 exceptions (I think because the model is no longer available because it changes a few times per second)
The information of the length of the resized column (in Pixel) get lost, every time the data (and so also the TableModel) changed.
For the TableModel i use my own model ResultSetTableModel which extends AbstractTableModel.
This ResultSetTableModel has a method setResultSet(ResultSet rs) and overwrites the method getValueAt(x,y)...
As I told if I set a new ResultSet to my ResultSetTableModel and then add it to the JTable by the method setModel(resultSetTableModel) it works, but it has the 2 drawbacks i told.
So I think I can solve this problem with the method fireTableDataChanged() but I tried many possibilities but get no change.
Do you know, where I have to place the fireevent?
At the moment I try this, but it doesn't work and I don't know why:
private ResultSetTableModel resultSetTableModel;
private DataFetcher dataFetcher;
private JTable table;
...
//works fine
public void initaialUpdateTable() {
resultSetTableModel = new CachingResultSetTableModel(dataFetcher.getRS());
table.setModel(resultSetTableModel);
}
//does not work
public void updateTable(){
resultSetTableModel.setResultSet(dataFetcher.getRS());
resultSetTableModel.fireTableDataChanged();
}
If I every times call initaialUpdateTable(), it works fine, but i want that just the data changes and not the whole model
Thanks for your answers
Michael
but i want that just the data changes and not the whole model
Hmm how can I..., there is no only one ...
1) Something that you can see in the GUI is TableView, only presentation layer, and all data are always stored in the TableModel
2) If you don't declare any TableModel, this doesn't mean that there isn't exist, still are there DefaultTableModel
3) Your private ResultSetTableModel resultSetTableModel; must extend AbstractTableModel,
4) If you'll to block any of fireXxxXxxChanged();, then no changes goes back to the TableView,
5) Basic stuff here, start with fireTableCellUpdated(row, col);
EDIT
More informations about TableModels here, here or search for ResultSetTableModel, TableFromDatabase
Sorry I don't have a concrete answer to your question, but I couldn't quite fit all that I want to say in a comment.
I used the method setModel() to update the data
You should probably stick to a single model that provides methods to modify its data. These methods should appropriately notify listeners when something has changed.
Here's a really awesome article that shows how to implement a high-performance, multi-threaded table with frequently changing data. You could probably use a lot of the example source code.
How to Create Frequently-Updated JTables that Perform Well

Categories

Resources