如何使用fireTableDataChanged()正确更新AbstractTableModel?

时间:2011-10-26 15:08:10

标签: java swing jtable listener

still正在努力应对应自动更新的JTable

情况如下: 我实例化MyTable(扩展JTable),并在我的UI类(MyView)中设置它。 MyTable类接受UI类和包含逻辑作为参数的类的实例:

...
private JPanel createTablePanel() {
    tablePanel = new JPanel();
    myTable = new MyTable(this,mymeth);
    setMyTable(myTable);
    JScrollPane scrollPane = new JScrollPane(getMyTable());
    tablePanel.add(scrollPane);
    return tablePanel;
}

MyTable本身如下所示。设置了AbstractTableModelMyTableModel)的扩展名。 TableModelListener的扩展名设置为模型。最后,ListSelectionListener的扩展名设置为模型的SelectionModel

public class MyTable extends JTable implements TableModelListener
{

public MyTable(MyView myView, MyMethods mymeth)
{

    AbstractTableModel tableModel = new MyTableModel(mymeth);
    setModel(tableModel);
    getModel().addTableModelListener(new MyTableModelListener());
    setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    setCellSelectionEnabled(true);
    getColumnModel().getSelectionModel().addListSelectionListener(new MyTableSelectionListener(this, mymeth, myView));
    setPreferredScrollableViewportSize(this.getPreferredSize());

}

}

让我们快速浏览一下模型的构造函数。

public MyTableModel(MyMethods mymeth) {
    dataObject = new MyData(mymeth);
    myData = dataObject.getMyData();
    colTitles = dataObject.getColTitles();
}

MyData编译表格的数据:Vector<Vector<Object>>,由三个Vector<Object>(表数据)和一个String[](列标题)组成。数据本身来自图mymeth,逻辑类'实例。

只要单击表,就会实例化一个弹出窗口(即JOptionPane)对象,该对象会显示所选列中第3行的值选择。用户选择一个值,该值设置为数据模型注意之后表格更新的方式。

public MyOptionPane(int i, MyMethods mymeth, MyView myView) {
    this.view = myView;
    String sourceString = mymeth.getSourceString(i); // Gets a String from a
String[]. In this Array, the order is the same as in the table.
    String tag = null;
    tag = (String) JOptionPane.showInputDialog(this, "Choose a tag for \"" + sourceString + "\"", "String tagging" , JOptionPane.PLAIN_MESSAGE, null, myView.getTags().toArray(), myView.getTags().get(0));
    mymeth.setTag(i, tag);

    // This is where fireTableDataChanged() didn't work, but this did
            MyTableModel model = new MyTableModel(mymeth); // New model instance
    view.getMyTable().setModel(model); // reset new model to table
}

这很有效。但是,根据我的阅读,我可以简单地在模型上调用fireTableDataChanged(),表格应该自行更新。但是,这不起作用。用户kleopatra在之前的帖子中有commented个答案:

  

不要从模型外部的任何代码调用任何模型的fireXX方法。   而是在发生任何变化时实施模型

所以:我可以在这样的结构中调用fireTableDataChanged()吗?如果是的话,在哪里以及如何?

提前感谢所有的启蒙!

4 个答案:

答案 0 :(得分:4)

  

从我读过的内容我可以简单地在模型上调用fireTableDataChanged()并且表应该自行更新

您的程序不会在模型上调用fireXXX方法。 TableModel本身负责在模型中的任何数据发生更改时调用这些方法。查看Swing教程中的Creating a Table Model示例。 setValueAt(...)方法显示了如何调用适当的fireXXX方法。

如果您创建一个全新的TableModel,则需要使用setModel()方法。

Kleopatra的评论是所有fireXXX方法都显示在TableModel类本身内部调用。如果您想了解这是如何完成的,那么请查看DefaultTableModel的源代码。如果有你何时调用fireTableDataChanged()方法以及其他fireXXX方法的例子。

答案 1 :(得分:3)

您不必替换整个模型来更新单行。相反,更新受影响的单元格,让setValueAt()触发所需的事件,如here所示。或者,此相关example使用DefaultTableModel为您处理事件,如@mKorbel&amp; @camickr。

如果您与AbstractTableModel保持联系,请考虑List<List<MyData>>,除非您出于其他原因需要Vector

答案 2 :(得分:2)

不回答您的问题,建议使用DefaultTableModel

如果您不需要限制某些内容JTable,这是非常好的理由,那么您就无法使用AbstractTableModel,如果您实施DefaultTableModel,最佳工作仍然是},使用DefaultTableModel您永远不会关心,FireXxxXxxChanged()您必须使用setXxx()方法中的哪一个,

答案 3 :(得分:0)

这是一个ArrayList Person的简单程序,使用ArrayList中的数据填充表格,并使用AbstractTableModel更新fireTableDataChanged()。希望这有帮助

import java.util.ArrayList;
import javax.swing.table.AbstractTableModel;

/**
 *
 * @author razak
 */
public class Table extends javax.swing.JFrame {

    ArrayList<Person> records; //arrayList of persons
    AbstractTable tableModel;  //table model --inner class

    /**
     * Creates new form Table
     */
    public Table() {
        records = new ArrayList<>();
        tableModel = new AbstractTable(records);
        addData();
        initComponents();
        recordTable.setModel(tableModel);
    }

    /**
     * Adds test values to the table
     */
    private void addData() {
        records.add(new Person("Tester", 21));
        records.add(new Person("Kofi", 20));
        records.add(new Person("Razak", 251));
        records.add(new Person("Joseph", 21));
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        jScrollPane1 = new javax.swing.JScrollPane();
        recordTable = new javax.swing.JTable();
        nameLabel = new javax.swing.JLabel();
        ageLabel = new javax.swing.JLabel();
        nameTextField = new javax.swing.JTextField();
        ageTextField = new javax.swing.JTextField();
        addButton = new javax.swing.JButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        recordTable.setModel(tableModel);
        jScrollPane1.setViewportView(recordTable);

        nameLabel.setText("Name");

        ageLabel.setText("Age");

        addButton.setText("Add");
        addButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                addButtonActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
            .addGroup(layout.createSequentialGroup()
                .addGap(52, 52, 52)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                    .addComponent(nameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(ageLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addGap(40, 40, 40)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(nameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 151, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(ageTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 61, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(66, 66, 66)
                        .addComponent(addButton, javax.swing.GroupLayout.PREFERRED_SIZE, 109, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap(39, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addGap(16, 16, 16)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(nameLabel)
                    .addComponent(nameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addGap(18, 18, 18)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(ageLabel)
                            .addComponent(ageTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 31, Short.MAX_VALUE)
                        .addComponent(addButton)
                        .addGap(18, 18, 18)))
                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 173, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap())
        );

        pack();
    }// </editor-fold>                        

    /**
     * When add button is clicked
     *
     * @param evt
     */
    private void addButtonActionPerformed(java.awt.event.ActionEvent evt) {                                          
        // TODO add your handling code here:
        String name = nameTextField.getText();
        int age = Integer.parseInt(ageTextField.getText());
        records.add(new Person(name, age));
        tableModel.fireTableDataChanged();

    }                                         

    /**
     * Inner class
     */
    class AbstractTable extends AbstractTableModel {

        String col[]; //column names
        ArrayList<Person> data; //arrayList to populate table

        AbstractTable(ArrayList<Person> record) {
            this.col = new String[]{"Name", "Age"};
            data = record;
        }

        //get number of records
        @Override
        public int getRowCount() {
            return data.size();
        }

        //get number of columns
        @Override
        public int getColumnCount() {
            return col.length;
        }

        //get a value form the table
        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            Person person = data.get(rowIndex);
            if (columnIndex == 0) {
                return person.getName();
            } else if (columnIndex == 1) {
                return person.getAge();
            }
            return null;
        }

        //set value at a particular cell 
        public void setValueAt(Person person, int row, int column) {
            data.add(row, person);
            fireTableCellUpdated(row, column);
        }

        //get column name
        public String getColumnName(int column) {
            return col[column];
        }
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(Table.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(Table.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(Table.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(Table.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new Table().setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify                     
    private javax.swing.JButton addButton;
    private javax.swing.JLabel ageLabel;
    private javax.swing.JTextField ageTextField;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JLabel nameLabel;
    private javax.swing.JTextField nameTextField;
    private javax.swing.JTable recordTable;
    // End of variables declaration                   
}


/**
 * Person class
 * @author razak
 */
public class Person {

    private final String name; //name
    private final int age; //age

    //constructor
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    //return name
    public String getName() {
        return name;
    }

    //returns age
    public int getAge() {
        return age;
    }
}