Как правильно обновить AbstractTableModel с помощью fireTableDataChanged ()? - PullRequest
3 голосов
/ 26 октября 2011

Я все еще борюсь с JTable, который должен автоматически обновляться.

Ситуация следующая: Я создаю экземпляр MyTable (расширяет JTable) и задаю его в своем классе пользовательского интерфейса (MyView). Класс MyTable принимает класс пользовательского интерфейса и экземпляр класса, который содержит логику в качестве параметров):

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

MyTable сам выглядит как ниже. На него установлено расширение AbstractTableModel (MyTableModel). Расширение 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 компилирует данные для таблицы: A Vector<Vector<Object>>, которая состоит из трех Vector<Object> s (данные таблицы) и 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 оставил комментарий к ответу в предыдущем сообщении:

не вызывать методы fireXX модели из любого кода, внешнего по отношению к модели. Вместо этого реализуйте модель, чтобы сделать это, когда что-то изменилось

Итак: Можно ли вообще назвать fireTableDataChanged() внутри такой структуры? И если да, то где и как?

Заранее благодарим за все просветления!

Ответы [ 4 ]

4 голосов
/ 26 октября 2011

из того, что я прочитал, я могу просто вызывать fireTableDataChanged () для модели, и таблица должна обновляться сама

Ваша программа не вызывает методы fireXXX длямодель.Сам TableModel отвечает за вызов этих методов всякий раз, когда изменяется какая-либо из данных в модели.Посмотрите на пример Создание модели таблицы из учебного пособия по Swing.Метод setValueAt (...) показывает, как вызвать соответствующий метод fireXXX.

Если вы создаете совершенно новую TableModel, вам нужно использовать метод setModel ().

Комментарий Клеопатрыбыло то, что все показанные методы fireXXX были вызваны из самого класса TableModel.Если вы хотите понять, как это делается, взгляните на исходный код DefaultTableModel.Если есть пример того, когда вы вызываете метод fireTableDataChanged () вместе с другими методами fireXXX.

3 голосов
/ 26 октября 2011

Вам не нужно заменять всей модели, чтобы обновить одну строку.Вместо этого обновите соответствующие ячейки и позвольте setValueAt() запустить требуемое событие, как показано здесь .Кроме того, этот связанный пример использует DefaultTableModel, который обрабатывает события для вас, как предложено @mKorbel & @ camickr.

Если вы остаетесь с AbstractTableModel рассмотрите List<List<MyData>>, если вам не нужен Vector по какой-либо другой причине.

2 голосов
/ 26 октября 2011

чтобы не отвечать на ваш вопрос, предложение об использовании DefaultTableModel

, если вам не нужно что-то ограничивать для JTable, действительно веская причина, тогда вы не можете использовать AbstractTableModel , лучшая работа по-прежнему, если вы реализуете DefaultTableModel , используя DefaultTableModel, вы никогда не будете беспокоиться об этом, какой из FireXxxXxxChanged() вы должны использовать для каждого из setXxx() методы,

0 голосов
/ 19 октября 2016

Вот простая программа, которая имеет 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;
    }
}
...