Link to home
Start Free TrialLog in
Avatar of justinbh3
justinbh3Flag for Canada

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.

Avatar of bpmurray
bpmurray
Flag of Ireland image

Actually you shouldn't have to call fireXXX() methods directly. However, without some code, I'm just guessing. A few things to look for:
* 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.
Avatar of justinbh3

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.TableModel#getColumnCount()
       */
      public int getColumnCount() {

            return this.colNames.length;
      }

      /* (non-Javadoc)
       * @see javax.swing.table.TableModel#getRowCount()
       */
      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+monthlyInterestRate),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).toString()));
                  newRow.add((Object)(new Double(this.principal).toString()));
                  newRow.add((Object)(new Double(this.balance).toString()));
                  
                  data.add(newRow);
                  

                  
                  if (this.balance < 0)
                      this.balance = 0;
                  
                  this.interest = 0;
                  this.principal = 0;
                  this.monthlyPayment = 0;
                  
                  
            }
      


            
            
      }
      

}
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.

Avatar of Mick Barry
yes, you do need to call fireXXX()
can u post where u use your table model?
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.setBorder(new TitledBorder
                                                ("Enter Loan Amount, " +
                                                 "Number of Years, and Annual " +
                                                 "Interest Rate"));
            
            this.calcLoanPaymentSchedule = new JButton("Get Schedule");
            this.loanDataFields[0].setText("Loan Amount                   ");
            this.loanDataFields[1].setText("Number of Years            ");
            this.loanDataFields[2].setText("Annual Interest Rate     ");
            
      }
      
      private void createGUI()
      {
            this.setDefaultCloseOperation(this.EXIT_ON_CLOSE);
            this.contentPane = this.getContentPane();
            
            this.setLayout(new BorderLayout());
            

            this.loanInfoPanel.setLayout(new BorderLayout());
            
            this.loanBoxes[0].add(this.loanDataFields[0]);
            this.loanBoxes[0].add(this.loanData[0]);
            this.loanBoxes[1].add(this.loanDataFields[1]);
            this.loanBoxes[1].add(this.loanData[1]);
            this.loanBoxes[2].add(this.loanDataFields[2]);
            this.loanBoxes[2].add(this.loanData[2]);
            
            this.bigLoanBox.add(this.loanBoxes[0]);
            this.bigLoanBox.add(this.loanBoxes[1]);
            this.bigLoanBox.add(this.loanBoxes[2]);
            
            this.masterBox.add(this.bigLoanBox);
            this.masterBox.add(this.calcLoanPaymentSchedule);
            this.loanInfoPanel.add(this.masterBox);
            
            this.tablePanel.add(new JScrollPane(this.loanTable));
            this.add(this.loanInfoPanel,BorderLayout.NORTH);
            this.add(this.tablePanel, BorderLayout.SOUTH);
            
            this.pack();
            this.setVisible(true);
      }
      
      private void initButtonListener()
      {
            this.calcLoanPaymentSchedule.addActionListener(new ActionListener() {
                  public void actionPerformed( ActionEvent actionEvent )
                {

                        cTable.setData(((Integer)loanData[0].getValue()).doubleValue(),
                                                  ((Integer)loanData[1].getValue()).doubleValue(),
                                                    ((Integer)loanData[2].getValue()).doubleValue());
                  
                        cTable.fireTableDataChanged(); // 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(TableModelEvent e). Thanks.
that won't work.
move the fireXXX() call inside the setData() method

                  this.interest = 0;
                  this.principal = 0;
                  this.monthlyPayment = 0;
                  fireTableDataChanged();
                 
            }(
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.
ASKER CERTIFIED SOLUTION
Avatar of Mick Barry
Mick Barry
Flag of Australia image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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.
thanks!

a second pair of eyes(or third or fourth) is great.