我有一个名为 transactionList
的 JTable
,每一行代表一个 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/