justinbh3
asked on
Using fireTableDataChanged() within a custom table extending AbstractTableModel
Product: Java, SE 6
It seems I need help.
I am using AbstractTableModel to create a custom table and when I invoke fireTableDataChanged() after editing my table data in my table model nothing seems to happen.
I thought that AbstractTableModel implicitly handles the delegation to update the view, the JTable.
It seems I am missing something in my code to help this along. I am asking you because I want to stop banging my head against a wall.
What I have done is implement the three necessary methods from the table model interface which is implemented by AbstractTableModel:
public int getColumnCount()
public int getRowCount()
public Object getValueAt(int row, int column)
as well as the getColumnName method to add columns.
Since my data model is not editable externally (directly through the cells) I decided not to implement setValueAt.
I am using a vector of vectors for my main data structure. My nested vectors hold Object types of the loan payment info.
I thought it was my data structure but I can initialize my table with data using the vector structure in the constructor of MyCustomTable. However, when i fire a change from elsewhere nothing happens(either using the code that tested the data structure and classes correctness from my constructor or the loan info.). I must be missing something and don't know what. The only other thing I haven't really considered is my JScrollPane but that really shouldn't be an issue.
What I have considered is:
1)providing my own implementation for delegation and updating the view: this seems unnecessary since the docs say its already there.
2) my datastructure: works fine in the constructor
3) where I call fireTableDataChanged(): doesn't seem to matter if i can from within class or from the JTable object, still doesn't work.
4) what i am storing: i am storing vectors of objects that are really strings(maybe cant update table with this object type?)
I hope you can help.
regards,
Justin.
It seems I need help.
I am using AbstractTableModel to create a custom table and when I invoke fireTableDataChanged() after editing my table data in my table model nothing seems to happen.
I thought that AbstractTableModel implicitly handles the delegation to update the view, the JTable.
It seems I am missing something in my code to help this along. I am asking you because I want to stop banging my head against a wall.
What I have done is implement the three necessary methods from the table model interface which is implemented by AbstractTableModel:
public int getColumnCount()
public int getRowCount()
public Object getValueAt(int row, int column)
as well as the getColumnName method to add columns.
Since my data model is not editable externally (directly through the cells) I decided not to implement setValueAt.
I am using a vector of vectors for my main data structure. My nested vectors hold Object types of the loan payment info.
I thought it was my data structure but I can initialize my table with data using the vector structure in the constructor of MyCustomTable. However, when i fire a change from elsewhere nothing happens(either using the code that tested the data structure and classes correctness from my constructor or the loan info.). I must be missing something and don't know what. The only other thing I haven't really considered is my JScrollPane but that really shouldn't be an issue.
What I have considered is:
1)providing my own implementation for delegation and updating the view: this seems unnecessary since the docs say its already there.
2) my datastructure: works fine in the constructor
3) where I call fireTableDataChanged(): doesn't seem to matter if i can from within class or from the JTable object, still doesn't work.
4) what i am storing: i am storing vectors of objects that are really strings(maybe cant update table with this object type?)
I hope you can help.
regards,
Justin.
ASKER
I have posted some code. Maybe this is clearer.
public class MyCustomTable extends AbstractTableModel {
private String colNames [] = { "Payment#", "Interest", "Principal", "Balance" };
private Vector data;
double balance, principal, interest, monthlyPayment;
int noOfYears;
public MyCustomTable()
{
data = new Vector(new Vector());
}
public String getColumnName(int column)
{
return this.colNames[column];
}
/* (non-Javadoc)
* @see javax.swing.table.TableMod el#getColu mnCount()
*/
public int getColumnCount() {
return this.colNames.length;
}
/* (non-Javadoc)
* @see javax.swing.table.TableMod el#getRowC ount()
*/
public int getRowCount() {
return this.data.size();
}
/* (non-Javadoc)
* populates table
*/
public Object getValueAt(int row, int column) {
return ((Vector)(data.get(row))). get(column );
}
public void setData(double loanAmnt, double noOfYears, double interestRate)
{
Vector newRow;
double monthlyInterestRate = 0;
data.removeAllElements();
monthlyInterestRate = interestRate / 12;
this.balance = loanAmnt;
while (this.balance != 0)
{
this.monthlyPayment = loanAmnt * monthlyInterestRate /
(1 - (Math.pow(1/(1+monthlyInte restRate), noOfYears *12)));
this.interest = monthlyInterestRate * this.balance;
this.principal = this.monthlyPayment - this.interest;
this.balance -= this.principal;
newRow = new Vector();
newRow.add((Object)(new Double(this.monthlyPayment ).toString ()));
newRow.add((Object)(new Double(this.interest).toSt ring()));
newRow.add((Object)(new Double(this.principal).toS tring()));
newRow.add((Object)(new Double(this.balance).toStr ing()));
data.add(newRow);
if (this.balance < 0)
this.balance = 0;
this.interest = 0;
this.principal = 0;
this.monthlyPayment = 0;
}
}
}
public class MyCustomTable extends AbstractTableModel {
private String colNames [] = { "Payment#", "Interest", "Principal", "Balance" };
private Vector data;
double balance, principal, interest, monthlyPayment;
int noOfYears;
public MyCustomTable()
{
data = new Vector(new Vector());
}
public String getColumnName(int column)
{
return this.colNames[column];
}
/* (non-Javadoc)
* @see javax.swing.table.TableMod
*/
public int getColumnCount() {
return this.colNames.length;
}
/* (non-Javadoc)
* @see javax.swing.table.TableMod
*/
public int getRowCount() {
return this.data.size();
}
/* (non-Javadoc)
* populates table
*/
public Object getValueAt(int row, int column) {
return ((Vector)(data.get(row))).
}
public void setData(double loanAmnt, double noOfYears, double interestRate)
{
Vector newRow;
double monthlyInterestRate = 0;
data.removeAllElements();
monthlyInterestRate = interestRate / 12;
this.balance = loanAmnt;
while (this.balance != 0)
{
this.monthlyPayment = loanAmnt * monthlyInterestRate /
(1 - (Math.pow(1/(1+monthlyInte
this.interest = monthlyInterestRate * this.balance;
this.principal = this.monthlyPayment - this.interest;
this.balance -= this.principal;
newRow = new Vector();
newRow.add((Object)(new Double(this.monthlyPayment
newRow.add((Object)(new Double(this.interest).toSt
newRow.add((Object)(new Double(this.principal).toS
newRow.add((Object)(new Double(this.balance).toStr
data.add(newRow);
if (this.balance < 0)
this.balance = 0;
this.interest = 0;
this.principal = 0;
this.monthlyPayment = 0;
}
}
}
ASKER
One more comment. I thought with AbstractTableModel that you needed to call one of the fire methods when updating your model data. Also, you will notice that fireTableDataChanged() isnt being invoked above. It will not matter if I put it at the end of my setData function or not, the table will not update.
yes, you do need to call fireXXX()
can u post where u use your table model?
can u post where u use your table model?
ASKER
public class Lab03Frame extends JFrame {
private JPanel tablePanel, loanInfoPanel;
private JTable loanTable;
private Box [] loanBoxes;
private Box bigLoanBox, masterBox;
private Container contentPane;
private JSpinner [] loanData;
private JLabel [] loanDataFields;
private JButton calcLoanPaymentSchedule;
private MyCustomTable cTable;
public Lab03Frame()
{
this.initMembers();
this.createGUI();
this.initButtonListener();
}
private void initMembers()
{
this.loanData = new JSpinner[3];
this.loanDataFields = new JLabel[3];
this.loanBoxes = new Box[3];
this.cTable = new MyCustomTable();
for (int i = 0; i < 3; ++i)
{
this.loanData[i] = new JSpinner();
this.loanDataFields[i] = new JLabel();
this.loanBoxes[i] = new Box(BoxLayout.X_AXIS);
}
this.tablePanel = new JPanel();
this.loanTable = new JTable(new MyCustomTable());
this.loanInfoPanel = new JPanel();
this.bigLoanBox = new Box(BoxLayout.Y_AXIS);
this.masterBox = new Box(BoxLayout.X_AXIS);
this.loanInfoPanel.setBord er(new TitledBorder
("Enter Loan Amount, " +
"Number of Years, and Annual " +
"Interest Rate"));
this.calcLoanPaymentSchedu le = new JButton("Get Schedule");
this.loanDataFields[0].set Text("Loan Amount ");
this.loanDataFields[1].set Text("Numb er of Years ");
this.loanDataFields[2].set Text("Annu al Interest Rate ");
}
private void createGUI()
{
this.setDefaultCloseOperat ion(this.E XIT_ON_CLO SE);
this.contentPane = this.getContentPane();
this.setLayout(new BorderLayout());
this.loanInfoPanel.setLayo ut(new BorderLayout());
this.loanBoxes[0].add(this .loanDataF ields[0]);
this.loanBoxes[0].add(this .loanData[ 0]);
this.loanBoxes[1].add(this .loanDataF ields[1]);
this.loanBoxes[1].add(this .loanData[ 1]);
this.loanBoxes[2].add(this .loanDataF ields[2]);
this.loanBoxes[2].add(this .loanData[ 2]);
this.bigLoanBox.add(this.l oanBoxes[0 ]);
this.bigLoanBox.add(this.l oanBoxes[1 ]);
this.bigLoanBox.add(this.l oanBoxes[2 ]);
this.masterBox.add(this.bi gLoanBox);
this.masterBox.add(this.ca lcLoanPaym entSchedul e);
this.loanInfoPanel.add(thi s.masterBo x);
this.tablePanel.add(new JScrollPane(this.loanTable ));
this.add(this.loanInfoPane l,BorderLa yout.NORTH );
this.add(this.tablePanel, BorderLayout.SOUTH);
this.pack();
this.setVisible(true);
}
private void initButtonListener()
{
this.calcLoanPaymentSchedu le.addActi onListener (new ActionListener() {
public void actionPerformed( ActionEvent actionEvent )
{
cTable.setData(((Integer)l oanData[0] .getValue( )).doubleV alue(),
((Integer)loanData[1].getV alue()).do ubleValue( ),
((Integer)loanData[2].getV alue()).do ubleValue( ));
cTable.fireTableDataChange d(); // Here is where i use my fire method
}});
}
}
As I mentioned before it doesnt matter if I call it in the model or here it wont update. I have also tried using fireTableStructureChanged( ) and fireTableDataChanged(Table ModelEvent e). Thanks.
private JPanel tablePanel, loanInfoPanel;
private JTable loanTable;
private Box [] loanBoxes;
private Box bigLoanBox, masterBox;
private Container contentPane;
private JSpinner [] loanData;
private JLabel [] loanDataFields;
private JButton calcLoanPaymentSchedule;
private MyCustomTable cTable;
public Lab03Frame()
{
this.initMembers();
this.createGUI();
this.initButtonListener();
}
private void initMembers()
{
this.loanData = new JSpinner[3];
this.loanDataFields = new JLabel[3];
this.loanBoxes = new Box[3];
this.cTable = new MyCustomTable();
for (int i = 0; i < 3; ++i)
{
this.loanData[i] = new JSpinner();
this.loanDataFields[i] = new JLabel();
this.loanBoxes[i] = new Box(BoxLayout.X_AXIS);
}
this.tablePanel = new JPanel();
this.loanTable = new JTable(new MyCustomTable());
this.loanInfoPanel = new JPanel();
this.bigLoanBox = new Box(BoxLayout.Y_AXIS);
this.masterBox = new Box(BoxLayout.X_AXIS);
this.loanInfoPanel.setBord
("Enter Loan Amount, " +
"Number of Years, and Annual " +
"Interest Rate"));
this.calcLoanPaymentSchedu
this.loanDataFields[0].set
this.loanDataFields[1].set
this.loanDataFields[2].set
}
private void createGUI()
{
this.setDefaultCloseOperat
this.contentPane = this.getContentPane();
this.setLayout(new BorderLayout());
this.loanInfoPanel.setLayo
this.loanBoxes[0].add(this
this.loanBoxes[0].add(this
this.loanBoxes[1].add(this
this.loanBoxes[1].add(this
this.loanBoxes[2].add(this
this.loanBoxes[2].add(this
this.bigLoanBox.add(this.l
this.bigLoanBox.add(this.l
this.bigLoanBox.add(this.l
this.masterBox.add(this.bi
this.masterBox.add(this.ca
this.loanInfoPanel.add(thi
this.tablePanel.add(new JScrollPane(this.loanTable
this.add(this.loanInfoPane
this.add(this.tablePanel, BorderLayout.SOUTH);
this.pack();
this.setVisible(true);
}
private void initButtonListener()
{
this.calcLoanPaymentSchedu
public void actionPerformed( ActionEvent actionEvent )
{
cTable.setData(((Integer)l
((Integer)loanData[1].getV
((Integer)loanData[2].getV
cTable.fireTableDataChange
}});
}
}
As I mentioned before it doesnt matter if I call it in the model or here it wont update. I have also tried using fireTableStructureChanged(
that won't work.
move the fireXXX() call inside the setData() method
this.interest = 0;
this.principal = 0;
this.monthlyPayment = 0;
fireTableDataChanged();
}(
move the fireXXX() call inside the setData() method
this.interest = 0;
this.principal = 0;
this.monthlyPayment = 0;
fireTableDataChanged();
}(
ASKER
I have already tried that as i mentioned in my first post. I could put it practiaclly anywhere and it wont update my view.
I just find that strange. Since the delegation to update the view should be provided as long as you call firetabledatachanged() within the table model implementation.
I just find that strange. Since the delegation to update the view should be provided as long as you call firetabledatachanged() within the table model implementation.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
ill give it a try, and thanks.
one thing though... did you mean cTable since a dont have a cData member of type MyCustomTable. I do, however, have a cTable. I think that is what you were referring to.
ill let you know how it goes.
one thing though... did you mean cTable since a dont have a cData member of type MyCustomTable. I do, however, have a cTable. I think that is what you were referring to.
ill let you know how it goes.
ASKER
thanks!
a second pair of eyes(or third or fourth) is great.
a second pair of eyes(or third or fourth) is great.
* If the data values are not the right type, you won't get an update, but you should see an exception
* Is the table in edit mode? Can you call editor.StopCellEditing?
* Is your renderer code being called? This is probably the most likely.