4

你好,

我已经创建了我的 TableModel,并且想在添加新行后刷新 JTable。应该向侦听器添加什么来“刷新”JTable?

public class MyTableModel implements TableModel  {
    private Set<TableModelListener> listeners = new HashSet<TableModelListener>();

    //List<Staff> staffs = Factory.getInstance().getStaffDAO().getAllStaff();
    private List<Staff> staffs;

    public MyTableModel(List<Staff> staffs){
        this.staffs = staffs;
    }

    @Override
    public int getRowCount() {
        return staffs.size();
    }

    @Override
    public int getColumnCount() {
        return 5;  
    }

    @Override
    public String getColumnName(int columnIndex) {
        switch (columnIndex){
            case 0:
                return "First Name";
            case 1:
                return "Second Name";
            case 2:
                return "Date";
            case 3:
                return "Position";
            case 4:
                return "Salary";
        }
        return "";  
    }

    @Override
    public Class<?> getColumnClass(int columnIndex) {
        return Object.class;  
    }

    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
        return true;  
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        Staff staff = staffs.get(rowIndex);
        switch (columnIndex){
            case 0:
                return staff.getName();
            case 1:
                return staff.getSurname();
            case 2:
                return staff.getDate();
            case 3:
                return staff.getPosition();
            case 4:
                return staff.getSalary();
        }
        return "";  
    }

    @Override
    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
    }

    @Override
    public void addTableModelListener(TableModelListener l) {
    }

    @Override
    public void removeTableModelListener(TableModelListener l) {
    }
}

这是我的添加行按钮的侦听器:

 @Override
    public void actionPerformed(ActionEvent e) {
        Staff staff = new Staff();
        staff.setName(JOptionPane.showInputDialog("Enter First Name"));
        staff.setSurname(JOptionPane.showInputDialog("Enter Second Name"));
        staff.setDate(JOptionPane.showInputDialog("Enter Date"));
        staff.setPosition(JOptionPane.showInputDialog("Enter Position"));
        staff.setSalary(JOptionPane.showInputDialog("Enter Salary"));
        try {
            Factory.getInstance().getStaffDAO().addStaff(staff);
        } catch (SQLException e1) {
            e1.printStackTrace();  
        }
!!!Here should be some code that will be firing my table after adding new row!!!
}

我尝试在我的 actionPerformed() 中使用 AbstractTableModel 的 firetabledatachanged() 方法,但不幸的是,它出现了 ClassCastException。

更新 1

WorkPlaceGui.java

public class WorkPlaceGui extends JFrame implements ActionListener {

    AbstractTableModel model;
    JTable jTable;
    JScrollPane jScrollPane;

    public WorkPlaceGui()throws SQLException{


        List<Staff> staffs = Factory.getInstance().getStaffDAO().getAllStaff();
        for(int i = 0; i < 0; i++) {
                staffs.add(new Staff("First Name " + staffs.get(i).getName(), "Second Name " + staffs.get(i).getSurname(), "Date " + staffs.get(i).getDate(), "Position " + staffs.get(i).getPosition(), "Salary " + staffs.get(i).getSalary()));
        }

        model = new MyTableModel(staffs);
        jTable = new JTable(model);
        JButton jBtnAdd = new JButton("Добавить");
        JButton jBtnDel = new JButton("Удалить");
        JButton jBtnUpd = new JButton("Обновить");
        JButton jBtnAdmin = new JButton("Админка");
        JPanel panelNorth = new JPanel();
        JPanel panelCenter = new JPanel();
        JPanel panelSouth = new JPanel();
        jTable.setPreferredScrollableViewportSize(new Dimension(350, 150));
        jScrollPane = new JScrollPane(jTable);


        panelNorth.setLayout(new FlowLayout());
        panelNorth.add(jBtnAdd);
        panelNorth.add(jBtnDel);
        panelNorth.add(jBtnUpd);
        panelNorth.add(jBtnAdmin);
        panelCenter.add(jScrollPane);

        setLayout(new BorderLayout());
        add(panelNorth, BorderLayout.NORTH);
        add(panelCenter, BorderLayout.CENTER);

        jBtnAdd.addActionListener(this);

        setPreferredSize(new Dimension(550, 300));
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setTitle("Staff data base");
        pack();
        setVisible(true);
        setLocationRelativeTo(null);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        Staff staff = new Staff();
        staff.setName(JOptionPane.showInputDialog("Enter First Name"));
        staff.setSurname(JOptionPane.showInputDialog("Enter Second Name"));
        staff.setDate(JOptionPane.showInputDialog("Enter Date"));
        staff.setPosition(JOptionPane.showInputDialog("Enter Position"));
        staff.setSalary(JOptionPane.showInputDialog("Enter Salary"));
        try {
            Factory.getInstance().getStaffDAO().addStaff(staff);
        } catch (SQLException e1) {
            e1.printStackTrace();
        }
        model.fireTableDataChanged();
    }
}

MyTableModel.java

public class MyTableModel extends AbstractTableModel {

    private List<Staff> staffs;

    public MyTableModel(List<Staff> staffs){
        this.staffs = staffs;
    }

    @Override
    public int getRowCount() {
        return staffs.size();
    }

    @Override
    public int getColumnCount() {
        return 5;
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        Staff staff = staffs.get(rowIndex);
        switch (columnIndex){
            case 0:
                return staff.getName();
            case 1:
                return staff.getSurname();
            case 2:
                return staff.getDate();
            case 3:
                return staff.getPosition();
            case 4:
                return staff.getSalary();
        }
        return "";
    }
}

4

6 回答 6

12

你已经做到了艰难的方式。

首先,您直接从实现TableModel,其次您未能实现侦听器要求......

相反,尝试从AbstractTableModel已经包含侦听器注册和通知的实现的相反扩展。

您将需要提供一种方法,允许您向表模型中添加一行。在此方法中,您需要使用fireTableRowsInserted将通知使用模型的任何表的方法,即已添加新行...

更新示例

这是非常非常基本的例子。它的唯一目的是演示fireTableRowsInserted. 它使用 SwingTimer每 125 毫秒添加一个新行,直到你杀死它;)

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.AbstractTableModel;

public class DynamicTable {

    public static void main(String[] args) {
        new DynamicTable();
    }

    public DynamicTable() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }
                
                final MyTableModel model = new MyTableModel();
                JTable table = new JTable(model);
                
                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new JScrollPane(table));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
                
                Timer timer = new Timer(125, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        model.addRow();
                    }
                });
                timer.start();
            }
        });
    }
    
    public class MyTableModel extends AbstractTableModel {

        private List<String[]> rows;

        public MyTableModel() {
            rows = new ArrayList<>(25);
        }
        
        @Override
        public int getRowCount() {
            return rows.size();
        }

        @Override
        public int getColumnCount() {
            return 4;
        }

        @Override
        public Class<?> getColumnClass(int columnIndex) {
            return String.class;
        }

        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            String[] row = rows.get(rowIndex);
            return row[columnIndex];
        }
        
        public void addRow() {
            int rowCount = getRowCount();
            String[] row = new String[getColumnCount()];
            for (int index = 0; index < getColumnCount(); index++) {
                row[index] = rowCount + "x" + index;
            }
            rows.add(row);
            fireTableRowsInserted(rowCount, rowCount);
        }            
    }                    
}

用另一个例子更新

因为您的表模型有其自己的支持List,所以它与您的工厂没有任何联系。它不知道您何时向其中添加或删除对象。这意味着您将负责更新模型:

public class MyTableModel extends AbstractTableModel {

    private List<Staff> staffs;

    public MyTableModel(List<Staff> staffs){
        this.staffs = staffs;
    }

    @Override
    public int getRowCount() {
        return staffs.size();
    }

    @Override
    public int getColumnCount() {
        return 5;
    }
    
    public void add(Staff staff) {
        int size = getSize();
        staffs.add(staff);
        fireTableRowsInserted(size, size);
    }

    public void remove(Staff staff) {
        if (staffs.contains(staff) {
            int index = stafff.indexOf(staff);
            staffs.remove(staff);
            fireTableRowsDeleted(index, index);
        }
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        Staff staff = staffs.get(rowIndex);
        switch (columnIndex){
            case 0:
                return staff.getName();
            case 1:
                return staff.getSurname();
            case 2:
                return staff.getDate();
            case 3:
                return staff.getPosition();
            case 4:
                return staff.getSalary();
        }
        return "";
    }
}

你的actionPerformed

@Override
public void actionPerformed(ActionEvent e) {
    Staff staff = new Staff();
    staff.setName(JOptionPane.showInputDialog("Enter First Name"));
    staff.setSurname(JOptionPane.showInputDialog("Enter Second Name"));
    staff.setDate(JOptionPane.showInputDialog("Enter Date"));
    staff.setPosition(JOptionPane.showInputDialog("Enter Position"));
    staff.setSalary(JOptionPane.showInputDialog("Enter Salary"));
    try {
        Factory.getInstance().getStaffDAO().addStaff(staff);
        ((MyTableModel)model).add(staff);
    } catch (SQLException e1) {
        e1.printStackTrace();  
    }
}
于 2013-05-28T07:23:26.677 回答
8

您的类MyTableModel实现TableModel了 ,但它没有将模型连接到视图的事件处理机制。而是扩展AbstractTableModel,如此处和此处所示AbstractTableModel提供了fireTable*为此所需的方法。

public void setValueAt(Object value, int row, int col) {
    data[row][col] = value;
    fireTableCellUpdated(row, col);
}
于 2013-05-28T07:22:29.830 回答
3

好吧,首先,找到有关观察者模式的更多信息(http://en.wikipedia.org/wiki/Observer_pattern)。

I suggest that you create a ObservableModel class that will have a list of PropertyChangeListeners. Your StaffDAO should extend this ObservableModel. When the new staff is added (i.e. addStaff is called) you should call ObservableModel's firePorpertyChange or something like that. firePropertyChange notifyies all propertyChangeListeners. One of those listeners should be registered in your Table, and its propertyChanged method should be implemented with refreshing of the table (hd1) had a good answer.

于 2013-05-28T07:33:58.270 回答
2

myTableModel.fireTableDataChanged();应该足以强制刷新您的表。像往常一样,如果您还有其他问题,请随时发表评论。

于 2013-05-28T07:22:15.880 回答
2

For a more general solution you can use the Row Table Model and just implement the getValueAt() and setValueAt() methods.

Here should be some code that will be firing my table after adding new row!

The model is responsible for invoking the proper fireXXX method.

于 2013-05-28T16:08:04.520 回答
1

Use this type of casting.

((AbstractTableModel)student.getModel()).fireTableCellUpdated();
于 2015-03-18T15:37:12.250 回答