0

在试图找出我问的另一个问题的答案(如何在末尾始终使用空值对 jtable 进行排序)时,我遇到了另一个问题。

我正在实现一个TableRowSorter创建自定义的自定义Comparator。但是,Comparator似乎总是将 everyObject视为 type String。这个让我莫名其妙。

如果您会在下面的 SSCCE 中注意到,该行

System.out.println(o1.getClass() + " - " + o2.getClass());

总是产生输出

class java.lang.String - class java.lang.String

即使Object[][]数据数组中的项目是不同的类型。

import java.awt.Component;
import java.util.Comparator;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;

public class Test {

    public static void main(String args[]) {
        JFrame frame = new JFrame();
        JTable table = new JTable();
        Object[][] data = new Object[8][3];
        data[0][0] = 6.5d; data[0][1] = "Name1";
        data[1][0] = new NullClassFiller(); data[1][1] = "Name2";
        data[2][0] = 2.6d; data[2][1] = "Name3";
        data[3][0] = 0d; data[3][1] = "Name4";
        data[4][0] = new NullClassFiller(); data[4][1] = "Name5";
        data[5][0] = -4d; data[5][1] = "Name6";
        data[6][0] = 0d; data[6][1] = "Name7";
        data[7][0] = -4.3d; data[7][1] = "Name8";
        table.setModel(new DefaultTableModel(data, new String[]{"One", "Two"}));

        TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(table.getModel()) {
            @Override
            public Comparator<?> getComparator(final int column) {
                Comparator c = new Comparator() {
                    @Override
                    public int compare(Object o1, Object o2) {
                        System.out.println(o1.getClass() + " - " + o2.getClass());
                        if (o1 instanceof NullClassFiller) {
                            return -1;
                        } else if (o2 instanceof NullClassFiller) {
                            return -1;
                        } else {
                            return ((Comparable<Object>) o1).compareTo(o2);
                        }

                    }
                };
                return c;
            }
        };
        table.setRowSorter(sorter);
        table.getColumnModel().getColumn(0).setCellRenderer(new CustomRenderer());
        JScrollPane pane = new JScrollPane(table);
        frame.add(pane);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setSize(500, 500);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    static class NullClassFiller {}

    static class CustomRenderer extends DefaultTableCellRenderer {

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            DefaultTableCellRenderer renderer = (DefaultTableCellRenderer) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);

            if(value instanceof NullClassFiller)
                renderer.setText("");

            return renderer;
        }

    }
}
4

3 回答 3

3

有很多复合问题...

第一个是与DefaultTableModel. DefaultTableModel#getColumnClass返回Object.class

第二个是与TableRowSorterTableRowSorter检查Class模型返回的是否为Comparable,如果不是,则自动转换为String,因为Object不是Comparable...

因此,基本的解决方案是覆盖返回特定列getColumnClass的适当类型DefaultTableModelClass

TableModel model = new DefaultTableModel(data, new String[]{"One", "Two"}) {
    @Override
    public Class<?> getColumnClass(int columnIndex) {
        return columnIndex == 0 ? Double.class : String.class;
    }
};
table.setModel(model);

TableRowSorter检查列时Class,它现在将找到Comparable值并将使用表模型中的实际值而不是将其转换为String第一个。

现在,当您尝试对第一列进行排序时,您应该会看到更像...

class testtablesort.TestTableSort$NullClassFiller) - class java.lang.Double
class java.lang.Double) - class testtablesort.TestTableSort$NullClassFiller
class java.lang.Double) - class java.lang.Double
class testtablesort.TestTableSort$NullClassFiller) - class java.lang.Double
class java.lang.Double) - class testtablesort.TestTableSort$NullClassFiller
class java.lang.Double) - class java.lang.Double
class java.lang.Double) - class java.lang.Double
class java.lang.Double) - class testtablesort.TestTableSort$NullClassFiller
class java.lang.Double) - class java.lang.Double
class java.lang.Double) - class java.lang.Double
class java.lang.Double) - class java.lang.Double
class java.lang.Double) - class java.lang.Double
于 2013-09-08T07:07:27.073 回答
1

有几个有问题的方面,包括问题和一些答案:

  • 真正的要求是在表的末尾对空值进行排序,而不考虑 sortOrder
  • 该要求的干净解决方案需要对 DefaultRowSorter 及其子类进行近乎完全的重写,因为空值在比较算法中“早期”处理,并且深埋在其私有内部。根本不可能自定义比较器可以加入。
  • 一个肮脏的技巧是不添加空值,而是添加专用的空值替换,然后让自定义比较器完成其工作。部分原因是比较器必须知道 sortOrder,即最终需要调用 RowSorter 的句柄。
  • 黑客是......邪恶的:即使我们去攻击它们(不要,不要,不要......)它们是脆弱的,我们必须非常小心,至少在非常受控的环境中让它们正确!

这里的黑客在几个方面实施不正确,比较器

  • 不完整,不处理两个 nullFiller 的比较
  • 甚至没有破解的实质(也就是说,如果 nullFiller 是要比较的值之一,则根据 sortOrder 切换返回值)
  • getComparator(int)通过覆盖与调用与 DefaultRowSorter 的其他实现细节发生冲突setComparator(int, Comparator)

因此,如果有人决定应用他/她在某处发现的 hack,至少要正确复制它;-)

于 2013-09-08T09:38:02.140 回答
0

问题在这里:

table.setModel(new DefaultTableModel(data, new String[]{"One", "Two"}));

根据http://docs.oracle.com/javase/tutorial/uiswing/components/table.html

有两个直接接受数据的 JTable 构造函数(SimpleTableDemo 使用第一个):

JTable(Object[][] rowData, Object[] columnNames) JTable(Vector rowData, Vector columnNames) The advantage of these constructors is

它们易于使用。但是,这些构造函数也有缺点:

它们会自动使每个单元格都可编辑。它们将所有数据类型视为相同(作为字符串)。

于 2013-09-08T06:20:51.937 回答