JTable row selection without changing the data - java

Hi Im doing a project for college and have a JTable in my GUI. I want the user to be able to select rows without being able to change the data in the table. I am using two arrays to crate the table not the table model. Thanks
I dont want to use tablemodels!!!!

You can implement the isEditable() method in your table model and return false and your table will not be editable:
public class MyTableModel extends AbstractTableModel{
public void isEditable(){
return false;
}
}
Then you have a table and you set its model to a MyTableModel object eg.
JTable table = new JTable();
table.setModel(new MyTableModel());
Extra Information:
AbstractTableModel.isCellEditable(int,int) returns false by default, so you don't need to override it to get that behavior.
The DefaultTableModel implementation of that method returns true by default, so that one must be overriden if you wish to make cells un-editable.
Resource of this answer.

You should define your own table model, by extending AbstractTableModel, or DefaultTableModel. Just override isCellEditable(int row, int col) and make it return false.

You will need to override the table model's isCellEditable() method to always return false.

Related

How to refresh a JTable without setting a new table model?

I am trying to refresh a JTable using the DefaultTableModel without accessing the table itself again, but only the existing, but then updated table model.
Yet, I tried to update the table model itself and then notify the model about it (see in the code). For some reason, the table will not update. I do not know, if this is an access problem or if it is just not possible.
//in the Gui_Main class
private static void addTables(){
JTable tblMain = new JTable(Util_Tables.dtm);
}
//in the Util_Tables class, if the tables needs to be updated
public static DefaultTableModel dtm;
public static void updateTable(){
dtm = new DefaultTableModel(data, columns);
dtm.fireTableDataChanged();
}
So you're basic structure is all over the place. When you create a new instance of DefaultTableModel and assign it to dtm, this won't be reflected by the JTable, as it is still using the instance it first grabbed when it was created.
Exposing dtm the way you have, opens it up to undesirable modification and voids one of the principles of OO - encapsulation, where the class is responsible for the management of its properties. This is also a reason to reconsider the use of static
A better start would be to create a getter which returns a single instance of DefaultTableModel, so each call to it is guaranteed to return the same instance of DefaultTableModel and stops any one else from changing the underlying reference
private static void addTables(){
JTable tblMain = new JTable(Util_Tables.getModel());
}
//in the Util_Tables class, if the tables needs to be updated
private DefaultTableModel model;
public static DefaultTableModel getModel() {
if (model == null) {
model = new DefaultTableModel();
}
}
Okay, so how about updating the model? Well, you need to start by modifying your updateTable method, so it can be used to actually update the model in some meaningful way
public static void updateTable(Object[][] data, Object[] columnIdentifiers){
model.setDataVector(data, columnIdentifiers);
}
The model will then generate the events it needs itself. If you find yourself calling the fireXxx methods yourself, then it's a good indication that you're doing something wrong.

Populate JTable given an object

Let's say I have a List of Items(my own class that I created that have 5 fields). I want to somehow inject these items into the JTable.
And in the JTable I want to have some kind of method like public String determineColumnText(Object o, int col) where I can convert the received Object into Item and then based on the col take out a specific value from the Item and return it so that it will be shown.
I have tried searching and saw numerous answers saying create AbstractTableModel however all the tutorials I looked at do not provide anything that I desired. Closest I saw was public Object getValueAt(int rowIndex, int columnIndex) however that would mean that I would have to store all the objects I want to display inside the AbstractTableModel. But what if I want to make it so that the Object is not stored inside AbstractTableModel but at the same time can be send into the AbstractTableModel.
Any suggestion as to how to go about doing this?
But what if I want to make it so that the Object is not stored inside AbstractTableModel
The Object should always be stored inside the TableModel. You can create the Object externally but then you need to add the Object to the TableModel. Once the Object is part of the model you should only manipulate it through the TableModel methods.
See the Row Table Model for a TableModel that will allow you to store Objects in the model but allow you to retrieve the data as a complete Object if you desire.
You will need to extend the class to implement your own getValueAt() and setValueAt() methods. These methods will access individual properties of your Object. The JButtonTableModel.java example shows how you can do this.
Option 1:
Loop through your list of items.
Build arrays of the data for all cells
Pass that array to a DefaultTableModel's constructor, which you will use in a JTable
Option 2:
Extend DefaultTableModel and override getValueAt(), like you describe
Store a reference to the list in your table model
Option 1 can be simple if the data is not changing. Option 2 is the most flexible but you seem to have an object to it that isn't explained.
I will paste you how I've used AbstractTableModel to populate table.
public class InventoryModel extends AbstractTableModel {
private static final String[] columnNames = { "Owner", "Location", "Sample Name", "Form Factor" };
private List<Samples> samplesList;
public InventoryModel(){
samplesList = SampleQueries.getAvailableSamples();
}
#Override
public int getColumnCount() {
// TODO Auto-generated method stub
return columnNames.length;
}
#Override
public int getRowCount() {
return samplesList.size();
}
#Override
public String getColumnName(int column) {
return columnNames[column];
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
switch (columnIndex) {
case 0:
return samplesList.get(rowIndex).getCurrentOwner();
case 1:
return samplesList.get(rowIndex).getSampleLocation();
case 2:
return samplesList.get(rowIndex).getSampleName();
case 3:
return samplesList.get(rowIndex).getFormFactor();
}
return null;
}
And this is how I call it from the Panel.
table = new JTable();
model = new InventoryModel();
model.fireTableDataChanged();
panel.setLayout(new BorderLayout(0, 0));
table.setModel(model);
JScrollPane scroll = new JScrollPane(table);
panel.add(scroll);
Hope it will work for you

Java: Proper way to update TableModel's data?

This is a simplifed version of what I'm trying to do. I have a map which maps an integer id to a list of strings. One of these lists from the map is displayed by a JTable at all times. (Depending on which id needs to be displayed) All information for the map is coming from a database, and is constantly being added to and removed from.
My DataClass which stores the full map and receives the updates from the database:
DataClass {
Map(Integer, List<String>) map;
// TabelModel gets list here
public List<String> getList(int id) {
return map.get(id);
}
// Updates from database come here
public updateList(int id, String info) {
if (map.containsKey(id) {
map.get(id).add(info);
}
else {
map.put(id, new List<String>(info));
}
}
// Remove from list, etc all down here
...
}
My Table model class:
MyTableModel extends DefaultTableModel {
List data;
public void updateData(int id) {
data = getList(id)
fireTableDataChanged();
}
... All the other stuff needed ...
}
Since database updates occur in batches, I know that at the end of a batch I have to update the table. So the DataClass informs the UI class which informs the table to update. This causes the updateData(id) to be called which retrieves a new set of data from the DataClass and calls fireTableDataChanged();
My Question are:
Is this the right way to go about updating/storing the data in the table?
Should getList return a clone of the data? If I just return the reference all updates from the database would be accessing that same reference and since these updates aren't running in the EDT wouldn't that be bad/frowned upon/wrong?
How can I do this using Java Events? PropertyChangeEvent? If so, how?
To the extent that your questions are related,
No; when new data is available, your updateData() method should update the internal data structure of your TableModel and fire an appropriate event; because DefaultTableModel knows nothing of your List, extend AbstractTableModel, as shown here; the JTable will update itself in response.
No; your database access layer should retain no references to queried objects, and no cloning should be necessary; forward queried objects to your display layer from the process() method of SwingWorker, or similar.
Use a TableModelListener to learn when and how the TableModel has changed; update the database accordingly.

JTable Not Updating Data

For some reason, nothing changes about this JTable when this is called (this method updates the JTable after a user submits an SQL query).
Givens:
The dataVector and columnNamesVector are verified to be populated correctly.
JTable is a private class variable.
private void updateData() {
updateDataVariables();
table = new JTable(dataVector, columnNamesVector)
{
#SuppressWarnings({ "unchecked", "rawtypes" })
public Class getColumnClass(int column)
{
for (int row = 0; row < getRowCount(); row++)
{
Object o = getValueAt(row, column);
if (o != null)
{
return o.getClass();
}
}
return Object.class;
}
};
}
Any ideas?
It's a common beginner's fallacy to confuse objects with reference variables, but you need to understand that they are quite distinct. When you call this:
table = new JTable(dataVector, columnNamesVector) {.....
You are creating a new JTable object and having the table variable refer to it, but this has no effect on the JTable object that is displayed by the GUI, the one that the table variable was referring to previously. So you're changing the property of the reference variable, but leaving the original object unchanged.
The solution: You should not be creating a new JTable but rather you should be creating a new TableModel and then place that TableModel into the existing and visualized JTable. You can change a table's model by calling setModel(newModel) on it.
Edit: or as wolfcastle noted you could update the existing TableModel rather than create one anew.
You need to tell JTable that the data in model was updated with firing appropriate event.
See this tutorial

Switching values when editing a cell

I have a JTable which uses a custom TableModel to display a series of object instances. There's a switch case inside getValueAt(int row, int column) to return values according to given attributes (see below). One return statement involves returning a value of 1/0 as true/false.
Is there a way that I can modify this TableModel so that it displays a 1/0 when a cell is edited?
public Object getValueAt(int row, int column) {
User user = (User)dataVector.get(row);
switch (column) {
case ID_INDEX:
return user.getId();
case USERNAME_INDEX:
return user.getUserName();
case PASSWORD_INDEX:
return "****";
case ACTIVATED_INDEX:
return (user.getActivated())?"true":"false";
default:
return new Object();
}
}
The default renderer and editor for Boolean is a JCheckBox. Consider using
case ACTIVATED_INDEX:
return Boolean.valueOf(user.getActivated());
Alternatively,
case ACTIVATED_INDEX:
return (user.getActivated())?"1":"0";
Addendum: As an example, DefaultTableModel does not override getColumnClass(), and AbstractTableModel simply returns Object.class. Your TableModel should override getColumnClass() accordingly:
DefaultTableModel dtm = new DefaultTableModel() {
#Override
public Class<?> getColumnClass(int col) {
return getValueAt(0, col).getClass();
}
};
// add some data
JTable table = new JTable(dtm);
You need to have a look at TableCellRenderer and TableCellEditor:
A TableCellRenderer is responsible for rendering cell data when it is not being edited, where as a TableCellEditor is responsible for providing a component used to edit the value of a cell. You can therefore represent the data in two separate ways depending on whether it is being edited or just rendered as per normal.
You should however consider that if you return a Boolean type from the getValueAt() method, your JTable should automatically render a JCheckBox, when the cell is in edit mode, the JCheckBox value can be changed by clicking on it as usual. To do this just return:
case ACTIVATED_INDEX:
return Boolean.valueOf(user.getActivated());

Categories