在共享表模型示例中工作时,我意识到如果我们将行过滤器附加到表的行排序器,则此过滤器对单元格更新事件没有任何影响。根据RowSorter API:
需要引用模型的具体实现,
RowSorter
例如TableModel
或ListModel
。视图类,例如JTable
和JList
,也将具有对模型的引用。为避免排序依赖项,RowSorter
实现不应在模型上安装侦听器。相反,视图类将RowSorter
在模型更改时调用。例如,如果在TableModel
JTable
调用中更新了一行rowsUpdated
。当模型发生变化时,视图可能会调用以下任何方法:modelStructureChanged
、allRowsChanged
、rowsInserted
和。rowsDeleted
rowsUpdated
因此,据我了解,单元格更新是行更新的一种特殊情况,因此rowsUpdated
应该调用并相应地过滤行。
为了说明我在说什么,请考虑这个简单的过滤器:
private void applyFilter() {
DefaultRowSorter sorter = (DefaultRowSorter)table.getRowSorter();
sorter.setRowFilter(new RowFilter() {
@Override
public boolean include(RowFilter.Entry entry) {
Boolean value = (Boolean)entry.getValue(2);
return value == null || value;
}
});
}
如果单元格值为or ,则此处的第三列应为 aBoolean
并且必须包含(行) 。如果我编辑放置在第三列的单元格并将其值设置为,那么我希望这一行只是从视图中“消失”。但是,要做到这一点,我必须再次设置一个新的过滤器,因为它似乎不能“自动”工作。entry
null
true
false
将 a 附加TableModelListener
到模型如下,我可以看到单元格编辑的更新事件:
model.addTableModelListener(new TableModelListener() {
@Override
public void tableChanged(TableModelEvent e) {
if (e.getType() == TableModelEvent.UPDATE) {
int row = e.getLastRow();
int column = e.getColumn();
Object value = ((TableModel)e.getSource()).getValueAt(row, column);
String text = String.format("Update event. Row: %1s Column: %2s Value: %3s", row, column, value);
System.out.println(text);
}
}
});
正如我所说,如果我使用它重置过滤器,TableModelListener
那么它会按预期工作:
model.addTableModelListener(new TableModelListener() {
@Override
public void tableChanged(TableModelEvent e) {
if (e.getType() == TableModelEvent.UPDATE) {
applyFilter();
}
}
});
问题:这是一个错误/实施问题吗?还是我误解了 API?
这是说明问题的完整MCVE 。
import java.awt.BorderLayout;
import javax.swing.BorderFactory;
import javax.swing.DefaultRowSorter;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.RowFilter;
import javax.swing.SwingUtilities;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
public class Demo {
private JTable table;
private void createAndShowGUI() {
DefaultTableModel model = new DefaultTableModel(5, 3) {
@Override
public boolean isCellEditable(int row, int column) {
return column == 2;
}
@Override
public Class<?> getColumnClass(int columnIndex) {
return columnIndex == 2 ? Boolean.class : super.getColumnClass(columnIndex);
}
};
model.addTableModelListener(new TableModelListener() {
@Override
public void tableChanged(TableModelEvent e) {
if (e.getType() == TableModelEvent.UPDATE) {
int row = e.getLastRow();
int column = e.getColumn();
Object value = ((TableModel)e.getSource()).getValueAt(row, column);
String text = String.format("Update event. Row: %1s Column: %2s Value: %3s", row, column, value);
System.out.println(text);
// applyFilter(); un-comment this line to make it work
}
}
});
table = new JTable(model);
table.setAutoCreateRowSorter(true);
applyFilter();
JPanel content = new JPanel(new BorderLayout());
content.setBorder(BorderFactory.createEmptyBorder(8,8,8,8));
content.add(new JScrollPane(table));
JFrame frame = new JFrame("Demo");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(content);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private void applyFilter() {
DefaultRowSorter sorter = (DefaultRowSorter)table.getRowSorter();
sorter.setRowFilter(new RowFilter() {
@Override
public boolean include(RowFilter.Entry entry) {
Boolean value = (Boolean)entry.getValue(2);
return value == null || value;
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new Demo().createAndShowGUI();
}
});
}
}