JTable cell updating issue - java

I got a problem I can't resolve alone and with help of other topics there. Found some 1 pretty similar but it hasn't help.
My problem is kind of tricky ones I think, I'll try to explain this as good as I can.
So, I got a JTable with couple of columns, column 2 and 3 are editable and column 4 is a product of these two (col4 = col2*col3). What I am going to do is when I edit column 2 or 3, column 4 will automaticly update it's value. I acomplished that but not fully.
The cell is updating only when I finish editing by mouseclick. I'd like to cell react with same way if editing is finished by ENTER key.
I was trying a little bit with:
if(recipeTable.getCellEditor()!=null)recipeTable.getCellEditor().stopCellEditing();
but it isn't changing anything.
Here is my code:
recipeTableModel = new DefaultTableModel(COLUMN_HEADLINE, 0) {
#Override
public boolean isCellEditable(int row, int column)
{
model.updateTotalPriceInTable(recipeTable);
return (column == 2) || (column == 3);
}
};
And:
public void updateTotalPriceInTable(JTable table)
{
double totalPrice;
DefaultTableModel tableModel = (DefaultTableModel) table.getModel();
for(int i = 0; i < tableModel.getRowCount(); i++)
{
totalPrice = Double.parseDouble(tableModel.getValueAt(i, 2).toString()) * Double.parseDouble(tableModel.getValueAt(i, 3).toString());
tableModel.setValueAt(totalPrice, i, 4);
}
tableModel.fireTableDataChanged();
}
~~~~~~~~~~~~~~~~~~~~~~~~
Ok I figured it out, that is code the code that resolved my problem:
#Override
public void setValueAt(Object aValue, int row, int column)
{
Vector rowVector = (Vector)dataVector.elementAt(row);
rowVector.setElementAt(aValue, column);
rowVector.setElementAt(Double.parseDouble((String) rowVector.get(2))*Double.parseDouble((String) rowVector.get(3)), 4);
fireTableDataChanged();
}

Override the setValueAt(...) method of your TableModel. You invoke super.setValueAt(...) to save the data normally.
Then whenever the data in column 2 or 3 changes, you then calculate the value of column 4 and update the model.

Related

JTable does not refresh on fireTableChanged

We have fairly complicated model in a JTable. In new development I noticed that GUI does not refresh when I call fireTableChanged(...) for individual cells.
So, my question is:
What do I put into TableModelEvent - model row id or view row id?
Looking into JTable code (I have jdk1.8.0_202):
public class JTable extends JComponent implements TableModelListener, Scrollable,
...
public void tableChanged(TableModelEvent e) {
...
int modelColumn = e.getColumn();
int start = e.getFirstRow();
int end = e.getLastRow();
Rectangle dirtyRegion;
if (modelColumn == TableModelEvent.ALL_COLUMNS) {
// 1 or more rows changed
dirtyRegion = new Rectangle(0, start * getRowHeight(),
getColumnModel().getTotalColumnWidth(), 0);
}
else {
// A cell or column of cells has changed.
// Unlike the rest of the methods in the JTable, the TableModelEvent
// uses the coordinate system of the model instead of the view.
// This is the only place in the JTable where this "reverse mapping"
// is used.
int column = convertColumnIndexToView(modelColumn);
dirtyRegion = getCellRect(start, column, false);
}
I see that in order to calculate dirty region, it converts column index, but does not do the same for row.
What does "reverse mapping" comment mean?
Looks like a bug in Swing to me.
What do you think?
UPDATE
My code is simple:
model.fireTableChanged(new TableModelEvent(model, rowNumber, rowNumber, columnNumber));
GUI does NOT refresh the cell.
UPDATE2
The issue is in my model which is too complicated to post it here. :(
I cannot blame JTable. It is designed this way. The only possible addition to it is RowSorter, and in there it does correct conversion:
private void repaintSortedRows(ModelChange change) {
...
int modelIndex = change.startModelIndex;
while (modelIndex <= change.endModelIndex) {
int viewIndex = convertRowIndexToView(modelIndex++);
if (viewIndex != -1) {
Rectangle dirty = getCellRect(viewIndex, columnViewIndex,
false);
int x = dirty.x;
int w = dirty.width;
if (eventColumn == TableModelEvent.ALL_COLUMNS) {
x = 0;
w = getWidth();
}
repaint(x, dirty.y, w, dirty.height);
}
}
}
Thanks everybody. Sorry for disturbance.
My code is simple:
model.fireTableChanged(new TableModelEvent(model, rowNumber, rowNumber, columnNumber));
That is not how you change data in a JTable. You should NOT be invoking that method directly. It is the responsibility of the TableModel to invoke that method when data is changed.
The point of using a TableModelListener is to listen for changes in the TableModel. You only need to implement the listener if you want to do special processing AFTER the data has changed as I demonstrated in the link I provided in my comment.
If you have data in an existing cell and you want to change its value then can do something like:
model.setValueAt("new value", 0, 0);
If you want to add a new row of data you use:
model.addRow(...);
The point is all changes should be done via the TableModel.
Note the JTable also has a convenience setValueAt(...) method which will invoke the model for you.

Updating checkboxes in Jtable goes into recursion, causes stack overflow error

I have a Jtable set up in a tabbed pane that is filled with an id and checkboxes. The table looks something along the lines of this, where . are the checkboxes.
| VAR1 |
ID | ALL | subVar1 | subVar2 |
------------------------------
id1| . | . | . |
Now, I also have a TableListener attached to this table. What I would like to happen is that, whenever a user presses the ALL checkbox, all the checkboxes in that row need to be selected (ie true). This is the table listener code.
#Override
public void tableChanged(TableModelEvent e) {
if(e.getSource() == assignedTableModel) {
for (int i = 0; i < aTable.getRowCount(); i++) {
boolean isAllChecked = (Boolean) aTable.getValueAt(i, 1);
if(isAllChecked) {
assignedTableModel.setValueAt(Boolean.TRUE, i, j);
}
else {
...
}
}
}
}
Clicking the ALL checkbox causing the table to change, assignedTableModel.setValueAt(Boolean.TRUE, i, j); is called, the table is changed again and therefore calls the listener, which calls this function again.
My question, is there another way of updating the checkboxes? Or is there a way to set a base to get out of the recursion?
EDIT The rows are added dynamically. I'm wondering if adding an actionListener to the ALL checkbox as it's being added will be a solution. I'll come back with how it turns out.
EDIT2 I'd forgot to mention that the whole table is generated dynamically. That means I have no way of knowing how many columns and rows will be present, the only columns I know are ID and the ALL col. Most answers already present deal with hard coded implementations.
whenever a user presses the ALL checkbox, all the checkboxes in that row are selected
So why are you looping through all the rows in your code? The event will be generated only for the row you click and you only need to select the check marks for the columns on that row. Get rid of the looping code.
the table is changed again and therefore calls the listener, which calls this function again.
You need an if condition to identify when the check box in the first column is checked:
if (e.getType() == TableModelEvent.UPDATE)
{
int row = e.getFirstRow();
int column = e.getColumn();
if (column == 0)
{
TableModel model = (TableModel)e.getSource();
model.setValueAt(Boolean.true, row, 1);
...
}
}
Now the change of state on the other columns will be ignored.
Based off of #camickr's response, the following piece of code seems to be doing the trick. Thanks.
#Override
public void tableChanged(TableModelEvent e) {
if (e.getType() == TableModelEvent.UPDATE && e.getSource() == assignedTableModel)
{
int row = e.getFirstRow();
int column = e.getColumn();
if (column == 1)
{
DefaultTableModel model = (DefaultTableModel) e.getSource();
for(int i=2 ; i<model.getColumnCount() ; i++) {
if((boolean) model.getValueAt(row, 1))
model.setValueAt(Boolean.TRUE, row, i);
else
model.setValueAt(Boolean.FALSE, row, i);
}
}
}
}

Get selected cell value in JTable [duplicate]

This question already has answers here:
How to get cell value of jtable depending on which row is clicked
(2 answers)
Closed 7 years ago.
When I double click the cell of the JTable, I want it to take the value of that cell and write it in the textfield. What should I do? Here is what I have tried so far, but I don't know where to go from here:
table_1.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent me) {
JTable table = (JTable) me.getSource();
Point p = me.getPoint();
int row = table.rowAtPoint(p);
if (me.getClickCount() == 2) {
textfield.settext(???????????);
}
}
});
i understand how it works:
int row = table.rowAtPoint(p);
int column = table.columnAtPoint(p);
textfield.settext(table_1.getValueAt(row, column));
Jtable table = (JTable)e.getsource();
int row = table.getSelectedRow();
int column = table.getSelectedColumn();
ObjectType o = (ObjectType)target.getValueAt(row, column) );
Do this. Will get the value in your JTable based on the row and column selected and then casts the returned value to your object type in the table and returns the value at the row, column. This is inside your Listener.
Shown in similar question Possible Dup?
You can get the value of the table by using:
table.getModel().getValueAt(row, col);
where
row - the row whose value is to be queried
col - the column whose value is to be queried
table - your object name (class jTable)
Note: The column is specified in the table view's display order, and not in the TableModel's column order. This is an important
distinction because as the user rearranges the columns in the table,
the column at a given index in the view will change. Meanwhile the
user's actions never affect the model's column ordering.
In addition, I recommend to read this documentation.
Try to write something like this:
table.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(final MouseEvent e) {
if (e.getClickCount() == 1) {
final JTable jTable= (JTable)e.getSource();
final int row = jTable.getSelectedRow();
final int column = jTable.getSelectedColumn();
final String valueInCell = (String)jTable.getValueAt(row, column);
textfield.setText(valueInCell);
}
});

Selected row in JTable is not highlighting

Well, this is my first post here. But I am little frustrated because I have search everywhere but nothing is working. I have JTable and code works as expected below lines right after if (value.equals("CMAU1294522")) .. however only one cell is show square box. I mouse clicked on a particular row, I want the entire row to show light gray (I think that is standard).
table = new JTable(sorter) {
public Component prepareRenderer(TableCellRenderer renderer, int row, int col) {
Component comp = super.prepareRenderer(renderer, row, col);
Object value = getModel().getValueAt(row, col);
UIManager.put("Table.editRow", new javax.swing.plaf.ColorUIResource(Color.YELLOW));
if(editingRow ==1){
table.setSelectionBackground(Color.red);
}
if (getSelectedRow() == row) {
table.setSelectionBackground(Color.red);
}
if (value.equals("CMAU1294522")) {
comp.setBackground(Color.red);
} else if (value.equals("PNCT")) {
comp.setBackground(Color.green);
} else if (NewJApplet.contReady.containsKey(value)) {
comp.setBackground(Color.CYAN);
} else if (NewJApplet.badCont.containsKey(value)) {
comp.setBackground(Color.red);
} else {
comp.setBackground(Color.white);
}
return comp;
}
Is there any way to do it in prepareRenderer function I already have?
I there any way to do it in PreparRenerere function I already have?
You code to get the "value" is wrong. You always get the value of the current cell being rendered. If you want to highlight the entire row based on a specific value then you need to hardcode the column:
Object value = getModel().getValueAt(row, ???);
Also, it looks like you are sorting the data in the table so you should be using getValueAt(...) instead of getModel().getValueAt(), so you check the data in the sort table, not the data in the unsorted model.
Check out the example code in Table Row Rendering for a working example.

JTable - Disallow selection and focusing of some cells while allowing others to be selected or focused

I'm looking for a way to disallow the selection or focusing of some cells (neither a complete column or row) in a JTable.
For example: I have a very tiny table with 2 rows and 2 columns and i only want the cells (0,0) and (1,1) to be selectable and focusable, while the cells (1,0) and (0,1) can not be selected or focused.
Does someone know how to achieve this behavior? So far i only found the way to implement a custom ListSelectionModel. But it only works for columns or rows (two different models).
Try overriding JTable's changeSelection method with you custom constraints and you'll likely need to disable editing via overriding isCellEditable too. E.g.:
final JTable table = new JTable( data, columnNames ) {
#Override
public void changeSelection( int row, int col, boolean toggle, boolean expand ) {
if( ( row + col )%2 == 0) { // here you set your own rules
super.changeSelection( row, col, toggle, expand );
}
}
#Override
public boolean isCellEditable( int row, int col ) {
return false; // disabling editing separately
}
};

Categories

Resources