Is TableModelListener (line 87/ HERE-1) interfering with my addRow method (line 139, HERE-2) for my JTable? If so how do I fix it?
This code will compile but an error is thrown when I use the "add row" button. The error is: (the stack trace is a lot longer but I've reduced it to the lines regarding my class and not the java API)
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException:
at HPLC.addRow(HPLC.java:142)
at HPLC.lambda$new$1(HPLC.java:109)
This has only been an issue since I've added the TableModelListener.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
class HPLC extends JFrame
{
public static void main (String [] args)
{
new HPLC();
}
HPLC()
{
//create window
JFrame frame = new JFrame();
frame.setTitle("HPLC Calculator");
frame.setSize(500,750);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setLayout(new GridBagLayout());
//row 0
JLabel title = new JLabel("HPLC Gradient Calculator");
gridBagAdd(panel, title, 0,0,4,1, GridBagConstraints.CENTER);
//row 1
JLabel flowLabel = new JLabel("Flow rate");
gridBagAdd(panel, flowLabel, 0,1,1,1, GridBagConstraints.CENTER);
JTextField flow = new JTextField(5);
gridBagAdd(panel, flow, 1,1,1,1, GridBagConstraints.CENTER);
JLabel mlMinLabel = new JLabel("ml/min");
gridBagAdd(panel, mlMinLabel, 2,1,1,1, GridBagConstraints.CENTER);
//row 2
JLabel numInjLabel = new JLabel("Number of injections");
gridBagAdd(panel, numInjLabel, 0,2,1,1, GridBagConstraints.CENTER);
JTextField numInj = new JTextField(5);
gridBagAdd(panel, numInj, 1,2,1,1, GridBagConstraints.CENTER);
//row 3
JLabel volALabel = new JLabel("Volume of A");
gridBagAdd(panel, volALabel, 0,3,1,1, GridBagConstraints.CENTER);
JTextField volA = new JTextField(5);
volA.setEditable(false);
gridBagAdd(panel, volA, 1,3,1,1, GridBagConstraints.CENTER);
JLabel volBLabel = new JLabel("Volume of B");
gridBagAdd(panel, volBLabel, 2,3,1,1, GridBagConstraints.CENTER);
JTextField volB = new JTextField(5);
volB.setEditable(false);
gridBagAdd(panel, volB, 3,3,1,1, GridBagConstraints.CENTER);
//row 4
JButton calculate = new JButton("calculate");
gridBagAdd(panel, calculate, 0,4,1,1, GridBagConstraints.CENTER);
JButton addRow = new JButton("add row");
gridBagAdd(panel, addRow, 1,4,1,1, GridBagConstraints.CENTER);
JButton removeRow = new JButton("remove row");
gridBagAdd(panel, removeRow, 2,4,1,1, GridBagConstraints.CENTER);
//the gradient table
String[] columns = {"Time", "%A", "%B"};
DefaultTableModel model = new DefaultTableModel(columns, 2)
{
public boolean isCellEditable(int row, int column)
//this overrides the default method to suit these conditions to make the 3rd column read only
{
if (column == 2)
return false;
return true;
}
};
JTable table = new JTable(model);
table.setFillsViewportHeight(true);
JScrollPane tablePane = new JScrollPane(table);
gridBagAdd(panel, tablePane, 0,5,4,4, GridBagConstraints.CENTER);
table.getModel().addTableModelListener(new TableModelListener()
//HERE-1 {
public void tableChanged(TableModelEvent e)
//overriding the TableModelListener method
{
//the basics in order to get the table cell
int row = e.getFirstRow();
int column = e.getColumn();
TableModel model = (TableModel)e.getSource();
String ColumnName = model.getColumnName(column);
Object data = model.getValueAt(row, column);
//what i do with that cell
volB.setText(data.toString());
}
});
//button methods
calculate.addActionListener(e -> calculate(model, volA));
addRow.addActionListener(e -> addRow(model));
removeRow.addActionListener(e -> removeRow(model));
//make visible
frame.add(panel);
frame.setVisible(true);
}
//method for placement of components
private void gridBagAdd(JPanel p, JComponent c, int x, int y, int width, int height, int align)
{
GridBagConstraints gc = new GridBagConstraints();
gc.gridx = x;
gc.gridy = y;
gc.gridwidth = width;
gc.gridheight = height;
gc.weightx = 100;
gc.weighty = 100;
gc.insets = new Insets(5,5,5,5);
gc.anchor = align;
gc.fill = GridBagConstraints.NONE;
p.add(c, gc);
}
//button method execution
private void calculate(DefaultTableModel model, JTextField volA)
{
int rowCount = model.getRowCount();
String msg = rowCount + " rows";
volA.setText(msg);
}
private void addRow(DefaultTableModel model)
{
int colCount = model.getColumnCount();
//HERE-2 Object [] newRow = new Object[colCount];
model.addRow(newRow);
}
private void removeRow(DefaultTableModel model)
{
int rowCount = model.getRowCount();
if (rowCount > 2)
model.removeRow(rowCount -1);
}
}
What I'd like my table to do, is to create an array based on the contents of the table, in order to perform a calculation. The TableModelListener has been added so that the %B column will auto complete to give a total of 100%.
I'm self taught and this is the first time anyone has ever seen any of my code. If you have any advise on how to improve my method of writing I'd be happy to hear it.
The TableModelListener has been added so that the %B column will auto complete to give a total of 100%
The event will tell you why it was generated. It looks to me like you only want to execute your code when you change a value in a cell.
So the code should be something like:
public void tableChanged(TableModelEvent e)
{
if (e.getType() == TableModelEvent.UPDATE)
{
// add processing here
}
}
For a working example check out: JTable -> TableModeListener