Stephan van Hulst wrote:I don't know any tutorials, but I might be able to answer some questions.
Stephan van Hulst wrote:
JTable uses the MVC pattern. Here, TableModel is the model, it stores the data and provides methods to read and update data. JTable uses TableCellRenderer for the view, and TableCellEditor for the controller parts.
Now, you like to be able to change the data through components other than the JTable. When you do this, you will still want to display the new data in your table as soon as it is updated. This is why TableModel provides a method addTableModelListener(). JTable adds a listener to your model, to determine when an update happens. You can also add your own listeners, if you have other components that display elements from your model.
The TableModel interface provides all the definitions needed for the table to read and update data, and get notified of changes. So now all we have to do is implement it.
Stephan van Hulst wrote:
Do you really want to implement the addTableModelListener() each time you have a new model? Thankfully, AbstractTableModel already implements it, and you only have to focus on what data your model returns.
The only methods AbstractTableModel doesn't implement are:
Usually, you would also override the following methods though:
Okay, now there's one problem left. If the data underlying the TableModel changes, how will the AbstractTableModel know that it has to notify its listeners? This is where the fire... methods come in. Your underlying class calls these methods to tell the TableModel: "Hey, it's time to warn the Table that our data has changed".
As you can see, this is an implementation detail, and therefore these methods are not part of the TableModel API. They should probably have made these methods protected.
DefaultTableModel is the default model used by JTable. You should almost always extend AbstractTableModel instead.
I will see if I can make an example (yes sorry, one example) showing you how the fire methods are used.
SCJP 1.4 - SCJP 6 - SCWCD 5 - OCEEJBD 6 - OCEJPAD 6
How To Ask Questions How To Answer Questions
Rob Spoor wrote:TableModel has a representation of the different columns that can be displayed. By default, a JTable creates a TableColumnModel that uses one column for each column in the model (in JTable.createDefaultColumnsFromModel()). The latter is used to determine what columns are actually visible. You can easily create an empty DefaultTableColumnModel, then add columns, then use that to create a JTable with only the columns you need.
In your case there should be no need whatsoever to change the TableModel's columns. Once set they should remain set. It's the TableColumnModel (with DefaultTableColumnModel as its only known implementation) that you should use to hide (remove) and show (add) columns. You can move columns from one position to another if needed. You don't need to worry about calling the fire methods; that's done automatically when you add, remove or move columns.
As for the TableColumn instances you need, they only require an index of the model's column. The following little example shows you how to create a JTable with all evenly-numbered columns in reversed order:
Rob Spoor wrote:
Because this allows a table's column's position to not match the model's column's position JTable has methods for converting between the two: convertColumnIndexToView to convert from the model's index to the first index of the matching column in the JTable, and convertColumnIndexToModel to convert from the table's index to the model's index.
Rob Spoor wrote:
As for your specific situation. Whether or not a column is visible or not should not be part of the model. If you do this then hiding the column in one table will hide it in all other tables using the same model as well.
Rob Spoor wrote:So that leaves the JTable itself or, preferably, the TableColumnModel. <'quick attempt' code snipped>
Ralph Cook wrote:
Rob Spoor wrote:So that leaves the JTable itself or, preferably, the TableColumnModel. <'quick attempt' code snipped>
Why do you prefer the TableColumnModel? It was the first thing I thought of too, but it is defined to deal with visible columns only, and many of its methods are going to be confusing to the reader for a class that holds both visible and not-visible columns. addColumn(), getColumn(), getColumnCount(), etc., are all defined by Java's TableColumnModel, and if I extend the class so that "column" could mean one that was visible or not, it's just hard to keep track of what you're reading.
I can create my own class for holding "all possible columns", of course, and am somewhat inclined to do that and have my TableModel contain it separately from the 'VisibleTableColumnModel". Or maybe it's just a collection of column objects in TableModel. But I'd be interested in any other reasons you have for designing it your way.
SCJP 1.4 - SCJP 6 - SCWCD 5 - OCEEJBD 6 - OCEJPAD 6
How To Ask Questions How To Answer Questions
Ralph Cook wrote:
Why do you prefer the TableColumnModel? It was the first thing I thought of too, but it is defined to deal with visible columns only, and many of its methods are going to be confusing to the reader for a class that holds both visible and not-visible columns. addColumn(), getColumn(), getColumnCount(), etc., are all defined by Java's TableColumnModel, and if I extend the class so that "column" could mean one that was visible or not, it's just hard to keep track of what you're reading.Rob Spoor wrote:
That's the separation between model and view. The model (TableModel) is there only to store and manipulate the data. The view (JTable plus JTableHeader plus TableColumnModel plus ListSelectionModel) are for the graphical representation of that data. In your case the data doesn't (or at least shouldn't) change, only the view. So that's why I wouldn't handle the showing / hiding in the TableModel but the TableColumnModel. And if you want to show / hide the columns in all tables that's still possible, by letting them share the same TableColumnModel.
The class for holding all possible columns should be the TableModel. As such, the TableModel shouldn't contain that class, it should be that class.
Ralph Cook wrote:Representing the columns to be displayed is not entirely in the domain of the model. A number of fields and methods involved are concerned with display, such as default width, rendering classes, default order, default display etc.
Yes, they also have to do with data in the model, I'm not saying they're entirely OUT of that domain either. Even if they were entirely in that domain, I would feel free to create a class just for representing them, and have it contained by or referred to by TableModel. There is nothing that says that any part of an MVC design all has to reside in one class, thank goodness.
I don't think TableColumnModel is a good choice for representing all possible columns. It is already defined by the Swing classes to represent only visible columns, and the names of public methods, etc., just refer to them as "columns". If I extend that to represent all possible columns, the code in it will be confusing as to whether each column reference is one or the other, and I can't control the external names. I'm not saying it won't work, only that it seems a bit cleaner to leave that class definition alone and make another class with all possible columns.
SCJP 1.4 - SCJP 6 - SCWCD 5 - OCEEJBD 6 - OCEJPAD 6
How To Ask Questions How To Answer Questions
Ralph Cook wrote:I think the terminology is beginning to defeat us. You are contradicting yourself, and since I'm sure you don't mean to, I suspect you don't understand what I'm saying as well as you think you do, and certainly not well enough to help me design for it.
I understand MVC. Talking down to me - or anyone - rarely increases understanding.
SCJP 1.4 - SCJP 6 - SCWCD 5 - OCEEJBD 6 - OCEJPAD 6
How To Ask Questions How To Answer Questions
Talking down to me - or anyone - rarely increases understanding.
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime. |