2
votes

I probably do not understand how the method fireTableStructureChanged() works. I am assuming that if I call the method, the implemented methods getColumnCount(), getRows() and getValueAt(int row, int col) are called so that my Table with the specified Model changes.

This is my TableModel

public class MyTableModel extends AbstractTableModel{
JComboBox box;
public MyTableModel(JComboBox choice){
    super();
    box = choice;
}

public void updateTable(){
    this.fireTableStructureChanged();
}

@Override
public int getColumnCount() {
    //implemented
}

@Override
public int getRowCount() {
    //implemented
}

@Override
public Object getValueAt(int row, int col) {
    //implemented
}

choice5 is a JComboBox

    table1 = new JTable(new MyTableModel(choice5));

When you select an item from choice5

    ((MyTableModel)table1.getModel()).updateTable();

is called (edit: for every item i can selected i probably have a diferent jtable i want to display)

What happens: I've checked that getColumnCount() and getRowCount() are indeed called, but getValueAt(...) is not. The JTable table1 (which was not displayed due to 0 rows and 0 columns) is still not displayed though both methods return (i.e.) the value 1.

What I want to happen: Obviously, I want table1 to be displayed (i.e. with one column and one row) with correct values (returned by getValueAt(...)).

Why is the method getValueAt(...) not called and therefore (I belive) the table not displayed? In general, how does fireTableStructureChanged() work?

Thanks in advance.

edit(SSCCE):

import java.awt.BorderLayout;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JTable;

public class TestTableModel extends JFrame {
 static JComboBox<String> choice5 = new JComboBox<String>(new String[]{"","1","2","3"});
 static JTable table1 = new JTable(new MyTableModel(choice5));
 static JFrame frame = new JFrame();

 public static void main(String[] args) {
    frame.setLayout(new BorderLayout());
    choice5.addItemListener(new ItemListener(){
        @Override
        public void itemStateChanged(ItemEvent e) {
            if(e.getStateChange() == ItemEvent.SELECTED) {
                ((MyTableModel)table1.getModel()).updateTable();
                frame.pack();
            }}});
    frame.add(BorderLayout.SOUTH, choice5);
    frame.add(BorderLayout.CENTER, table1);
    frame.pack();
    frame.setVisible(true);
    frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
    }
}

MyTableModel

import javax.swing.JComboBox;
import javax.swing.table.AbstractTableModel;
public class MyTableModel extends AbstractTableModel{
 JComboBox box;

public MyTableModel(JComboBox choice){
    super();
    box = choice;
}
public void updateTable(){this.fireTableStructureChanged();}

@Override
public int getColumnCount() {return box.getSelectedIndex();}
@Override
public int getRowCount() { return box.getSelectedIndex();}
@Override
public Object getValueAt(int row, int col) {return box.getSelectedItem();}
}
1
no idea and impossible to answer without seeing more of your code (as a SSCCE!) - but your setup smells fishy: having a model reference a view is the wrong way roundkleopatra
I was wondering how the method works in general. The SSCCE which should do something similar to my code works... Maybe it helps anyways. I will append it to my original post.F. Hall
still don't get it: you describe that you want one row/one column - but let your model return the selectedIndex for both row/columnCount? Which result in a "quadratic" table showing 0 to combo.getItemCount() -1 rows/columns, all containing the same value. In particular an empty table if selectedIndex <= 0kleopatra
It does not matter what any method returns. It might be a random number. I just want to update the table when i change the selection of the combobox. In the SSCCE it works fine, as you can see. But in my actual code (which does basically the same thing) fireTableStructureChanged() does not query/invoke getValueAt(...).F. Hall
then this SSCCE doesn't simulate your real code well enough :-) Also note that the method trivially will not be called if the table is empty (as in this example for selectedIndex == 0)kleopatra

1 Answers

0
votes

Table structure is rows, columns and column headers. Table data is what shows up in the cells.

  1. Try using fireTableRowsUpdated:

     public void updateTable(){this.fireTableRowsUpdated(0, this.getRowCount() - 1);}
    
  2. Try using setModel and use the EventQueue to ensure your code executes on the UI thread:

     choice5.addItemListener(new ItemListener(){
         @Override
         public void itemStateChanged(ItemEvent e) {
             if(e.getStateChange() == ItemEvent.SELECTED) {
                 EventQueue.invokeLater(() -> {
                     table1.setModel(new MyTableModel(choice5));
                     frame.pack();
                 });
             }}});
    
  3. Try your JTable in a JScrollPane. There's magic between them, like chocolate and peanut butter:

     frame.add(BorderLayout.SOUTH, choice5);
     frame.add(BorderLayout.CENTER, new JScrollPane(table1));
    

fireTableRowsUpdated

public void fireTableRowsUpdated(int firstRow, int lastRow)

Notifies all listeners that rows in the range [firstRow, lastRow], inclusive, have been updated.

Parameters:

  • firstRow - the first row
  • lastRow - the last row

See Also: TableModelEvent, EventListenerList

Source: Oracle


fireTableStructureChanged

public void fireTableStructureChanged()

Notifies all listeners that the table's structure has changed. The number of columns in the table, and the names and types of the new columns may be different from the previous state. If the JTable receives this event and its autoCreateColumnsFromModel flag is set it discards any table columns that it had and reallocates default columns in the order they appear in the model. This is the same as calling setModel(TableModel) on the JTable.

See Also: TableModelEvent, EventListenerList

Source: Oracle