How to refresh data in JTable I am using TableModel

风流意气都作罢 提交于 2019-12-17 07:39:11

问题


Hi,

I have created my TableModel and want to refresh JTable once I added a new row. What should be added to the listener to "refresh" 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) {
    }
}

Here is my listener of my Add row Button:

 @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!!!
}

I've tried to use method firetabledatachanged() of AbstractTableModel in my actionPerformed() but with unluck, it is appeared ClassCastException.

UPDATE 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 "";
    }
}


回答1:


You've done it the hard way.

First of all, you've implemented directly from TableModel and secondly you've failed to implement the listener requirements...

Instead, try extending from the AbstractTableModel instead, which already includes the implementations of the listener registration and notification.

You will need to provide a method that will allow you to add a row to the table model. In this method you need to use the fireTableRowsInserted method which will notify any tables using the model, that a new row has been added...

Update with example

This is VERY, VERY basic example. It's only intention is to demonstrate the use of fireTableRowsInserted. It uses a Swing Timer to add a new row every 125 milliseconds until you kill it ;)

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);
        }            
    }                    
}

Updated with another example

Because your table model is backed by its own List, it has no connection to your factory. It doesn't know when you add or remove objects from it. This means you become responsible for updating the model:

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 "";
    }
}

And your 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();  
    }
}



回答2:


Your class MyTableModel implements TableModel, but it has no event handling mechanism to connect the model to the view. Instead extend AbstractTableModel, as shown here and here. AbstractTableModel provides the fireTable* methods needed for this.

public void setValueAt(Object value, int row, int col) {
    data[row][col] = value;
    fireTableCellUpdated(row, col);
}



回答3:


Well, first of all, find more about Observer pattern (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.




回答4:


myTableModel.fireTableDataChanged(); should be just enough to force a refresh of your table. As usual, if you have further problems, do feel free to leave a comment.




回答5:


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.




回答6:


Use this type of casting.

((AbstractTableModel)student.getModel()).fireTableCellUpdated();


来源:https://stackoverflow.com/questions/16785982/how-to-refresh-data-in-jtable-i-am-using-tablemodel

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!