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

标签 java swing model jtable tablemodel

我有一个名为 transactionListJTable,每一行代表一个 Transaction,其中第一列包含实际的 Transaction 对象和每个后续列显示有关 Transaction 的一些数据。

我不希望向用户显示 Transaction 对象,因此我将其从 ColumnModel 中删除:

TableColumnModel cm = transactionList.getColumnModel();
cm.removeColumn(cm.getColumn(0));
transactionList.setColumnModel(cm);

这很好用,然后我可以使用以下方法检索选定的 Transaction:

(Transaction) transactionList.getModel().getValueAt(transactionList.getSelectedRow(), 0))

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

(Transaction) transactionList.getValueAt(transactionList.getSelectedRow(), 0));

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


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

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

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

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

transactionList.getValueAt(transactionList.getSelectedRow(), 0));

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

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

transactionList.getModel().getValueAt(transactionList.getSelectedRow(), 0))

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

transactionList.getColumnCount(); //return 5
transactionList.getColumnModel().getColumnCount(); //return 5
transactionList.getModel().getColumnCount(); //returns 6

我看到的一个可能的解决方案是在用户单击列标题时将 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();
        }
    }
}

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

            }
        });
    }
}

最佳答案

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

  • 列索引可能因重新排序而不同
  • 行索引可能因排序/过滤而不同

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

model.getValueAt(table.convertRowIndexToModel(table.getSelectedRow()), 0);

关于java - 在用户对列进行排序后访问隐藏的 JTable 模型列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21038028/

相关文章:

java - 如何在play框架中使用javaWS获取特定响应json

java - VLCJ - 透明背景时空白屏幕

cakephp:如何在模型中使用 find 语句而不是 Controller

java - 在不同的图形环境中查找 JFrame 标题和边框的大小

java - 如何在 Android 中的两个图像之间放置文本

java - 在quartz中动态调度作业

java - JFileChooser 在 OS X 中返回不正确的路径(仅文件夹模式)

java - 构建类来创建 JFreeChart,如何将其添加到主界面中的 JPanel 中?

ruby-on-rails - Rails 建模问题 - 关系和主键

c++ - 更改模型后 QTableView 中的项目数量保持不变