知道为什么 AbstractTableModel 会导致将空单元格添加到我的 table 中吗? (Java 摇摆)

Any idea why AbstractTableModel causes empty cells to be added to my table? (Java Swing)

正如标题所说,当我向基础列表添加内容时,空单元格被添加到我的 table。

主要Class:

import javax.swing.SwingUtilities;

public class Main {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                MainFrame frame = new MainFrame();
            }
        });
    }
}

主机class:

import java.awt.BorderLayout;
import java.util.ArrayList;

import javax.swing.JFrame;
import javax.swing.JTable;

public class MainFrame extends JFrame {
    private JTable table;
    private ArrayList<String> strings;
    
    public MainFrame() {
        setTitle("Stack Overflow");
        setSize(800, 800);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new BorderLayout());
        setVisible(true);
        
        strings = new ArrayList<String>();
        table = new JTable(new TableModel(strings));
        
        add(table,BorderLayout.CENTER);
        
        for (int i = 0; i < 10; i++) {
            strings.add("data");
        }
    }
}

AbstractTableModel Class:

import java.util.List;

import javax.swing.table.AbstractTableModel;

public class TableModel extends AbstractTableModel {
    private String[] colNames = {"Col1","Col2"};
    
    private List<String> strings;
    
    public TableModel(List<String> strings) {
        this.strings = strings;
    }
    
    @Override
    public String getColumnName(int column) {
        return colNames[column];
    }

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

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

    @Override
    public String getValueAt(int rowIndex, int columnIndex) {
        if (rowIndex*2 + columnIndex >= strings.size()) return "";
        return strings.get(rowIndex*2 + columnIndex);
    }
}

是否有更好的方法从我的一维数组中获取项目,以便 table 从左到右、从上到下填充(没有多余的空单元格)?

为什么会出现这个问题?

结果:

strings.add("data"); 

你应该使用类似的东西:

strings.add("data" + i); 

所以每个单元格中的值是不同的。这样您就可以判断数据是否正确显示。

The list is updated dynamically using fireTableDataChanged() whenever something is added to the list.

这是错误的。 fireTableDataChanged() 方法只能由 TableModel 内部的方法调用。一旦创建了 TableModel,您就可以忘记 ArrayList 并调用 TableModel 上的方法来更新 ArrayList。

因此您需要向您的 TableModel 添加类似 addItem(…) 的方法。然后 TableModel 将更新 ArrayList,然后调用 fireTableRowsInserted(…),如果您有奇数个项目,或 fireTableRowsUpdated(…),如果您有偶数个项目。

类似于:

public void addItem(String item)
{
    strings.add( item );

    if (string.size() % 2 == 0)
        fireTableRowsUpdated(…);
    else
        fireTableRowsInserted(…);
}

您拥有的数据和您对其建模的方式是两个不同的问题,不要害怕将它们分开以实现您的目标,例如:

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.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.Timer;
import javax.swing.table.AbstractTableModel;

public class Test {

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

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private JTable table;
        private SequentialTableModel model;

        public TestPane() {
            setLayout(new BorderLayout());
            model = new SequentialTableModel();
            table = new JTable(model);
            add(new JScrollPane(table));

            Timer timer = new Timer(500, new ActionListener() {
                private int count = 0;
                @Override
                public void actionPerformed(ActionEvent e) {
                    model.add("Data " + (++count));
                }
            });
            timer.start();
        }

    }

    public class SequentialTableModel extends AbstractTableModel {

        private String[] colNames = {"Col1", "Col2"};

        private List<List<String>> rows = new ArrayList<>(32);

        public SequentialTableModel() {
        }

        @Override
        public String getColumnName(int column) {
            return colNames[column];
        }

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

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

        @Override
        public String getValueAt(int rowIndex, int columnIndex) {
            List<String> values = rows.get(rowIndex);
            if (columnIndex >= values.size()) {
                return null;
            }
            return values.get(columnIndex);
        }

        public void add(String value) {
            if (rows.isEmpty()) {
                addNewRow(value);
                return;
            }

            List<String> lastRow = rows.get(rows.size() - 1);
            if (lastRow.size() < 2) {
                lastRow.add(value);
                fireTableCellUpdated(rows.size() - 1, lastRow.size() - 1);
            } else {
                addNewRow(value);
            }
        }

        protected void addNewRow(String value) {
            List<String> row = new ArrayList<>(2);
            row.add(value);
            rows.add(row);
            fireTableRowsInserted(rows.size() - 1, rows.size() - 1);
            return;
        }
    }
}