用户对列进行排序后访问隐藏的 JTable 模型列

Ron*_*Ron 2 java swing model jtable tablemodel

我有一个JTable被调用的transactionList,每一行代表一个Transaction,其中第一列保存实际Transaction对象,随后的每个列显示有关 的一些数据Transaction

我不希望该Transaction对象向用户显示,因此我将其从以下位置中删除ColumnModel

TableColumnModel cm = transactionList.getColumnModel();
cm.removeColumn(cm.getColumn(0));
transactionList.setColumnModel(cm);
Run Code Online (Sandbox Code Playgroud)

这非常有效,然后我可以Transaction使用以下方法检索所选内容:

(Transaction) transactionList.getModel().getValueAt(transactionList.getSelectedRow(), 0))
Run Code Online (Sandbox Code Playgroud)

当用户对表中的列进行排序时,问题就出现了,然后所选的行无法正确匹配。我通过更改上面的行来解决这个问题,以便我们直接从表中而不是从模型中获取所选行:

(Transaction) transactionList.getValueAt(transactionList.getSelectedRow(), 0));
Run Code Online (Sandbox Code Playgroud)

但现在 0 列不是我的隐藏Transaction对象,而只是它的第一个字段。


我也会尝试用另一种方式来解释。

在不允许对 JTable 列进行排序的情况下,这两个示例都有效:

1) 在第一列中显示 Transaction 对象(不要从 ColumnModel 中删除)

可以通过以下方式检索 Transaction 对象:

transactionList.getValueAt(transactionList.getSelectedRow(), 0));
Run Code Online (Sandbox Code Playgroud)

2) 在第一列中显示 Transaction 对象(从 ColumnModel 中删除)

可以通过以下方式检索 Transaction 对象:

transactionList.getModel().getValueAt(transactionList.getSelectedRow(), 0))
Run Code Online (Sandbox Code Playgroud)

如果我现在允许对列进行排序,#1 仍然有效。然而,方法 #2 现在将 JTable.getSelectedRow() 传递给 TableModel.getValueAt()。但这些索引不再相等,问题是 JTable 和 ColumnModel 不包含 Transaction 对象(只有 TableModel 包含)。

transactionList.getColumnCount(); //return 5
transactionList.getColumnModel().getColumnCount(); //return 5
transactionList.getModel().getColumnCount(); //returns 6
Run Code Online (Sandbox Code Playgroud)

我看到的一个可能的解决方案是当用户单击列标题时将 TableModel 与 JTable 一起排序。这可行吗?是否有更好的方法来实现此目标(将“隐藏”对象附加到 JTable 行)?


表模型

public class TransactionTableModel extends AbstractTableModel {
    String[] columnNames = { "<Transaction_Object>", "Date", "Name",
            "Hours", "Amount", "Notes" };

    public TransactionTableModel() {
    }
    public String getColumnName(int col) {
        return columnNames[col].toString();
    }

    public Class<?> getColumnClass(int col) {
        switch (col) {
        case 1:
            return Calendar.class;
        case 2:
            return String.class;
        }
    }

    public int getRowCount() {
        return DB.getInstance().getTransactions().size();
    }

    public int getColumnCount() {
        return columnNames.length;
    }

    public Object getValueAt(int row, int col) {
        Transaction t = null;
        t = DB.getInstance().getTransactionsChronological().get(row);
        switch (col) {
        case 0:
            return t;
        case 1:
            return t.getDate();
        case 2:
            return t.getStudent.getName();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

MCVE

有一个隐藏的第一列,其值与第二列相匹配。对于未排序的 JTable,按钮会打印正确的值,但通过单击标题对列进行排序后,模型不同步。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;

public class SwingTesting {

    JFrame frame;
    TablePane tablePane;

    public SwingTesting() {
        tablePane = new TablePane();

        frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        JButton test = new JButton("Print hidden item");
        test.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                printHiddenItem();
            }
        });

        frame.add(tablePane);
        frame.add(test, BorderLayout.SOUTH);
        frame.pack();
        frame.setVisible(true);
    }

    class TablePane extends JPanel {

        private final JTable table;
        private final TableModel tableModel;
        private final ListSelectionModel listSelectionModel;

        public TablePane() {
            table = new JTable();
            tableModel = createTableModel();
            table.setModel(tableModel);
            table.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
            table.setAutoCreateRowSorter(true);
            table.add(table.getTableHeader(), BorderLayout.PAGE_START);
            table.setFillsViewportHeight(true);

            listSelectionModel = table.getSelectionModel();
            table.setSelectionModel(listSelectionModel);

            this.add(new JScrollPane(table));

            testMethod();
        }

        private TableModel createTableModel() {
            DefaultTableModel model = new DefaultTableModel(new Object[] {
                    "First", "Second", "Third" }, 0) {
            };

            addTableData(model);
            return model;
        }

        private void addTableData(DefaultTableModel model) {
            model.addRow(new Object[] { "ONE", "ONE", "2007" });
            model.addRow(new Object[] { "TWO", "TWO", "2012" });
            model.addRow(new Object[] { "THREE", "THREE", "2009" });
            model.addRow(new Object[] { "FOUR", "FOUR", "2005" });
            model.addRow(new Object[] { "FIVE", "FIVE", "2001" });
        }


        private void testMethod() {
            TableColumnModel cm = table.getColumnModel();
            cm.removeColumn(cm.getColumn(0));
            table.setColumnModel(cm);
        }

    }

    public void printHiddenItem() {
        System.out.println(tablePane.table.getModel().getValueAt(tablePane.table.getSelectedRow(), 0));
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new SwingTesting();

            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

kle*_*tra 5

要记住的一件事是 JTable 和 TableModel 有两个独立的坐标系统,即视图系统与模型系统:

  • 由于重新排序,列索引可能会有所不同
  • 由于排序/过滤,行索引可能会有所不同

JTable 有方法 ConvertRow/ColumnToView/Model 来回映射,用于访问所选(视图!)行的模型行的具体问题:

model.getValueAt(table.convertRowIndexToModel(table.getSelectedRow()), 0);
Run Code Online (Sandbox Code Playgroud)