Reputation: 1764
I want to design this JTable.
The goal is the user to be able to edit the cells by double clicking on them. Any changes should be able to be saved and stored on a database later.
My code is the following:
public class BirthGUI extends JFrame implements TableModelListener {
//..//
//-------------------- BIRTH TABLE --------------------
table = new JTable();
table.setModel(myModel);
myModel.reloadBirthJTable();
table.getColumnModel().getColumn(0).setPreferredWidth(100);
table.getColumnModel().getColumn(1).setPreferredWidth(80);
table.getColumnModel().getColumn(2).setPreferredWidth(115);
table.setRowHeight(20);
JScrollPane scroller = new JScrollPane(table );
table.setBounds(49, 85, 295, 374);
table.getModel().addTableModelListener(this);
panel.add(scroller,BorderLayout.CENTER);
@Override
public void tableChanged(TableModelEvent e) {
System.out.println("TableModelEvent triggered!");
int row = e.getFirstRow();
int column = e.getColumn();
Object test = myModel.getValueAt(row, column);
System.out.println("row: " + row + " column: " + column);
System.out.println(test.toString());
}
and my TableModel:
public class BirthTableModel extends DefaultTableModel {
private String[] columnNames = {"Date", "Children", "Complications/Comments"}; //column header labels
private Object[][] data = new Object[20][3];
private List<Birth> list;
public void reloadBirthJTable() {
System.out.println("loading birth table..");
for(int i=0; i<20; i++){
data[i][0] = "";
data[i][1] = "";
data[i][2] = "";
this.addRow(data);
}
}
public void clearJTable() {
this.setRowCount(0);
}
@Override
public void addRow(Object[] arg0) {
// TODO Auto-generated method stub
super.addRow(arg0);
}
public String getColumnName(int col) {
return columnNames[col];
}
public Object getValueAt(int row, int col) {
return data[row][col];
}
public Class getColumnClass(int c) {
for(int rowIndex = 0; rowIndex < getRowCount(); rowIndex++) {
Object[] row = data[rowIndex];
if (row[c] != null) {
return getValueAt(rowIndex, c).getClass();
}
}
return String.class;
}
@Override
public int getColumnCount() {
return columnNames.length;
}
@Override
public boolean isCellEditable(int row, int col) {
return true;
}
}
The problem is that while the cells are editable after I double click on them and the tableChanged() is triggered, any change I make to them is deleted as soon the cell loses focus...
My output while modifying cells is this:
loading birth table..
TableModelEvent triggered!
row: 1 column: 0
TableModelEvent triggered!
row: 0 column: 0
so test
seems to be empty..
Upvotes: 3
Views: 4460
Reputation: 285403
Recommendations:
fire***(...)
notification methods whenever you make changes to the data held by the model.addRow(...)
method.An example of what I mean by AbstractTableModel:
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.*;
public class TestTableModel {
public static void main(String[] args) {
BirthTableModel2 dm2 = new BirthTableModel2();
JTable table = new JTable(dm2);
JOptionPane.showMessageDialog(null, new JScrollPane(table));
dm2.reloadBirthJTable();
JOptionPane.showMessageDialog(null, new JScrollPane(table));
}
}
// I had to guess at this class
class Birth {
private Date date;
private String children;
private String comments;
public Birth(Date date, String children, String comments) {
this.date = date;
this.children = children;
this.comments = comments;
}
public Date getDate() {
return date;
}
public String getChildren() {
return children;
}
public String getComments() {
return comments;
}
public void setDate(Date date) {
this.date = date;
}
public void setChildren(String children) {
this.children = children;
}
public void setComments(String comments) {
this.comments = comments;
}
}
@SuppressWarnings("serial")
class BirthTableModel2 extends AbstractTableModel {
public final static String[] COLUMN_NAMES = { "Date", "Children",
"Complications/Comments" }; // column header labels
private List<Birth> birthList = new ArrayList<>();
@Override
public Class<?> getColumnClass(int columnIndex) {
if (columnIndex == 0) {
return Date.class;
}
return super.getColumnClass(columnIndex);
}
@Override
public int getColumnCount() {
return COLUMN_NAMES.length;
}
@Override
public String getColumnName(int column) {
return COLUMN_NAMES[column];
}
@Override
public int getRowCount() {
return birthList.size();
}
public void reloadBirthJTable() {
System.out.println("loading birth table..");
clearModel();
for (int i = 0; i < 20; i++) {
addRow();
}
}
public void clearModel() {
birthList.clear();
fireTableDataChanged();
}
public void addRow() {
birthList.add(new Birth(null, "", ""));
fireTableRowsInserted(getRowCount() - 1, getRowCount() - 1);
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return true;
}
@Override
public Object getValueAt(int rowIndex, int colIndex) {
if (rowIndex < 0 || rowIndex >= getRowCount()) {
// throw exception
}
if (colIndex < 0 || colIndex >= getColumnCount()) {
// throw exception
}
Birth birth = birthList.get(rowIndex);
switch (colIndex) {
case 0:
return birth.getDate();
case 1:
return birth.getChildren();
case 2:
return birth.getComments();
}
return null;
}
@Override
public void setValueAt(Object aValue, int rowIndex, int colIndex) {
if (rowIndex < 0 || rowIndex >= getRowCount()) {
// throw exception
}
if (colIndex < 0 || colIndex >= getColumnCount()) {
// throw exception
}
Birth birth = birthList.get(rowIndex);
switch (colIndex) {
case 0:
birth.setDate((Date)aValue);
break;
case 1:
birth.setChildren(aValue.toString());
break;
case 2:
birth.setComments(aValue.toString());
}
fireTableRowsUpdated(rowIndex, rowIndex);
}
}
Upvotes: 5