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

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);
}
}
}
}

Related

JTable choose other rows and get their data when certain cell is clicked

I have a JTable. I want to create an event for one cell that if the user clicks on it, he is able to choose one or more rows from the table and the corresponding IDs are saved in that cell.
So in the example the user would click on "Click here to choose" in row 2 and then click on e.g. row 1 and row 3. The cell "click here to choose" should then be overwritten with something like 1 and 3 afterwards:
I'm thinking of somehow creating a MouseAdapter Event on click on the cell but I have no real idea how to do it. Any idea how I can approach this?
Use a ListSelectionListener with MULTIPLE_INTERVAL_SELECTION. In the handler, update the table's model using setValueAt() to reflect the change.
yes you definitely need to use MouseAdapter as below(you have the cell if "if condition become true"):
jt.addMouseListener(new java.awt.event.MouseAdapter() {
#Override
public void mouseClicked(java.awt.event.MouseEvent evt) {
int r = jt.rowAtPoint(evt.getPoint());
int c = jt.columnAtPoint(evt.getPoint());
if (r >= 0 && c >= 0) {
......
}
}
});

JTable cell updating issue

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.

<JTable>.getSelectedRow() is returning -1

I have written a "double-click" event on my JTable. My JTable, viz. myTaskTable is populated with a number of rows having multiple columns. I want the row index to be retrieved when I double click on one of the rows of the JTable. I am not sure why is it always returning me an index of -1 resulting in an exception. Am I am overlooking something? What could be going wrong?
This is how I am retrieving the index of the selected row from the JTable - myTaskTable
int selRow = myTaskTable.getSelectedRow();
Thank you!
Edit
Here is the code:
...
myTaskTable.addMouseListener(this);
...
public void mouseClicked(MouseEvent e)
{
if(e.getModifiers() == MouseEvent.BUTTON1_MASK)
{
if(e.getClickCount() == 2)
{
e.consume();
int selRow = myTaskTable.getSelectedRow();
System.out.println("GridReport double clicked on row="+selRow);
}
}
}
Get the row index using the event, not the table selection:
final int selectedRowIndex = table.rowAtPoint(mouseEvent.getPoint());
// If the rows are sorted or filtered
final int modelRowIndex = table.convertRowIndexToModel(selectedRowIndex);
getSelectedRow() would not work with multiple selected rows (multiple selections allowed), as it will always return "the index of the first selected row".
have you tried to put e.consume(); as the last statement?
public void mouseClicked(MouseEvent e){
if(e.getModifiers() == MouseEvent.BUTTON1_MASK){
if(e.getClickCount() == 2){
int selRow = myTaskTable.getSelectedRow();
System.out.println("GridReport double clicked on row="+selRow);
e.consume();
}
}
}
normaly e.consume(); is called when you are done with your reactive code. This clears dependencies of the Event, so it might also clear the selected Row.

JTable boolean values not updating when using JOptionPane

I'm trying to write a bit of code that can allow the user to fill in text fields by clicking on boolean cells in a JTable.
I can get the program to enter the data from the table into a text-field but my current method of doing this involves a JOptionPane which for some strange reason stops the table from changing the check-box values (i.e. the check-box doesn't change from black to ticked). Not only this but the selection doesn't update so the value in the last column remains false, even though the selection should switch it to true.
I think it might be something to do with the JOptionPane somehow overriding the selection event, but I don't know enough about the JOptionPane object to say how. My code is:
table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
ListSelectionModel selectionModel = table.getSelectionModel();
selectionModel.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
ListSelectionModel lsm = (ListSelectionModel) e.getSource();
if (lsm.isSelectionEmpty()) {
//no rows are selected do nothing
} else {
//First find the row clicked
int selectedRow = lsm.getLeadSelectionIndex();
/*
* put a popup here to ask the user which peak to associate
* the energy with.
*/
System.out.println(selectedRow);
//Get user to associate with a peak
availablePeaks = getAvailablePeaks();
String returnVal = (String) JOptionPane.showInputDialog(
null,
"Select the peak:",
"Peak Matching",
JOptionPane.QUESTION_MESSAGE,
null,
availablePeaks, null);
System.out.println(returnVal);
//Determine the selection
int index = 0;
for (int i = 0; i < availablePeaks.length; i++) {
if (availablePeaks[i] == returnVal) {
index = i;
} else {
}
}
//Set the peak value in the peak specifier to the energy in the row
double energy = (Double) table.getValueAt(selectedRow, 0);
System.out.println(energy);
frame.getPeakSetter().getPeakSpecifiers()[index].setEnergy(energy);
frame.getPeakSetter().getPeakSpecifiers()[index].getTextField().setText("" + energy);
}
}
});
Does anyone know why a JOptionPane in the ListSelectionListener would stop the table from updating the check-boxes?
Thanks!
I assume that your model returns true for isCellEditable() and that getColumnClass() returns Boolean.class for the JCheckBox column. This enables the default rednerer/editor, listed here.
It looks like the gesture of selecting the row is bringing up the dialog. It's not clear how this prevents the DefaultCellEditor from concluding; it works for me. As you are not checking getValueIsAdjusting(), I'm surprised you don't see two ListSelectionEvent instances.
In any case, bringing up a dialog each time the selection changes seems cumbersome. Several alternatives are possible:
Keep the ListSelectionListener, make the cell non-editable by returning false from isCellEditable(), and set its value in the model only if the dialog concludes successfully.
Drop the ListSelectionListener in favor of a JButton editor, shown here.
Drop the ListSelectionListener in favor of a custom CellEditor, as outlined below.
table.setDefaultEditor(Boolean.class, new DefaultCellEditor(new JCheckBox()) {
#Override
public boolean stopCellEditing() {
String value = JOptionPane.showInputDialog(...);
...
return super.stopCellEditing();
}
});

How to add a type of listener to a JTable (Java)?

I have a column with plain text in it.
If the user double-clicks a row in that column, the column allows itself to be edited for that row (as it should).
I need something to detect when that text is done with being edited (when the user hits the enter key, for example). When that happens, I need something to get the row ID of that change (0-based of course).
Any ideas?
Thanks!
You should add a listener to the TableModel:
table.getModel().addTableModelListener(new TableModelListener() {
public void tableChanged(TableModelEvent e) {
// your code goes here;
}
});
TableModelEvent contains row and column number and type of modification.
I think the easiest way to get the location of the click in terms of row and column would be this:
table.addMouseListener(new java.awt.event.MouseAdapter() {
#Override
public void mouseClicked(java.awt.event.MouseEvent e) {
int row = table.rowAtPoint(e.getPoint());
int column = table.columnAtPoint(e.getPoint());
if (row >= 0 && column >= 0) {
......
}
}
});

Categories

Resources