简体   繁体   English

使用不带分组字符的数字过滤JTable(千位分隔符)

[英]Filter JTable with Numbers without the grouping character (thousands-separator)

I'm trying to filter Rows in a JTable which contains Columns with numbers. 我正在尝试过滤包含带数字的列的JTable中的行。

The filtering is working so far, but it filters over the numbers including the thousands-separators. 到目前为止,过滤工作正在进行,但它会对包括千位分隔符在内的数字进行过滤。 For example, if there is a row with the number 25689 in one row and I try to filter for this row, i have to use "25.689". 例如,如果一行中有一个数字为25689的行,并且我尝试过滤此行,则必须使用“25.689”。 So it seems there is a formatting that is performed before the filtering. 因此,似乎在过滤之前执行了格式化。

I've tried to set an own default renderer and the numbers are shown without the separators but the filtering is the same. 我试图设置一个自己的默认渲染器,数字显示没有分隔符,但过滤是相同的。

Edit 编辑

I've added a full example re-creating my problem: 我添加了一个重新创建问题的完整示例:

public class GroupingTest {

    JFrame frame= null;
    Container pane= null;
    JTextField tf=null;
    JXTable table=null;

    public void searchTable() {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {                       
                    final String searchEx = "(?i)"
                                          + Pattern.quote(tf.getText());

                    final RowFilter<TableModel, Object> filter;
                    filter = RowFilter.regexFilter(searchEx);    
                    table.setRowFilter(filter);
                    //packAll in edt
                    Utility.packTableView(table);                       
                } catch (final Exception e) {
                    return;
                }
            }
        });
    }

    public void createTable() {
        frame = new JFrame();
        pane=frame.getContentPane();

        tf = new JTextField();
        tf.setPreferredSize(new Dimension(200,25));

        tf.getDocument().addDocumentListener(new DocumentListener() {

            @Override
            public void removeUpdate(final DocumentEvent e) {
                searchTable();
            }

            @Override
            public void insertUpdate(final DocumentEvent e) {
                searchTable();
            }

            @Override
            public void changedUpdate(final DocumentEvent e) {
                searchTable();
            }
        });

        String[] columnHeaders = {"long","strings"};

        DefaultTableModel $model = new DefaultTableModel(columnHeaders, 0) {
            @Override
            public Class<?> getColumnClass(final int $col) {
                if($col == 0) {
                    return Long.class;
                } else if($col == 1){
                    return String.class;
                } else {
                    return Object.class;
                }
            }
        };

        table = new JXTable($model);

        table.setDefaultRenderer(Long.class, new DefaultTableCellRenderer() {

            @Override
            public java.awt.Component getTableCellRendererComponent(final JTable $table,
                    final Object $value, final boolean $isSelected, final boolean $hasFocus, final int $row,
                    final int $column) {
                super.getTableCellRendererComponent($table, $value, $isSelected, $hasFocus, $row, $column);

                if ($value instanceof Long) {
                    this.setHorizontalAlignment(SwingConstants.RIGHT);
                }

                return this;
            }
        });

        Object[] line1 = {new Long(23345),"asdf"};
        $model.addRow(line1);
        Object[] line2 = {new Long(3),"dfw"};
        $model.addRow(line2);

        pane.add(tf,BorderLayout.NORTH);
        pane.add(new JScrollPane(table),BorderLayout.CENTER);

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setPreferredSize(new Dimension(300,200));
        frame.pack();
        frame.setVisible(true);             
    }

    public static void main(String[] args) {        
        GroupingTest gt = new GroupingTest();
        gt.createTable();    
    }    
}

The Filtering is working so far, but it filters over the numbers including the thousands-separators. 过滤到目前为止工作,但它过滤了包括千位分隔符在内的数字。

When the value's format interferes with the expected functioning of sorters and filters then it's time to check if getColumnClass(int columnIndex) in the table model is retrieving the appropriate class (in this case Double ). 当值的格式干扰排序器和过滤器的预期功能时,则应该检查表模型中的getColumnClass(int columnIndex)是否正在检索适当的类(在本例中为Double )。

By default AbstractTableModel implementation of such method returns Object.class which is rendered using the toString() method (that's why you see the thousands-separator) and probably filtered according to the string representation as well. 默认情况下,此类方法的AbstractTableModel实现返回使用toString()方法呈现的Object.class (这就是您看到千位分隔符的原因),并且可能根据字符串表示进行过滤。 Subclasses of AbstractTableModel (such as DefaultTableModel ) inherit this implementation and thus this method should be overriden. AbstractTableModel子类(例如DefaultTableModel )继承此实现,因此应该覆盖此方法。 For example let's say your table model is DefaultTableModel and the first column is a Double : 例如,假设您的表模型是DefaultTableModel ,第一列是Double

DefaultTableModel model = new DefaultTableModel()  {
    @Override
    public Class<?> getColumnClass(int columnIndex) {
        return columnIndex == 0 ? Double.class 
                                : super.getColumnClass(columnIndex);
    }
};

See Sorting and Filtering section of How to Use Tables tutorial for further details. 有关更多详细信息,请参阅如何使用表教程的排序和筛选部分。

Update 更新

Given your new MVCE it is clear now what are you trying to achieve. 鉴于你的新MVCE现在很清楚你想要实现什么。 I'd start saying that I've mistakenly assumed your table model holds Double instead of Long which makes no difference about overriding getColumnClass() method (it should be done anyways) but it will make a slight difference in the final solution. 我开始说我错误地假设你的表模型保持Double而不是Long ,这对于覆盖getColumnClass()方法没有区别(它应该完成)但是它会在最终解决方案中略有不同。

Now, to state the requirements clear, you need to filter that column either: 现在,要明确说明要求,您需要过滤该列:

  • Users input a number (Long) including grouping character. 用户输入包括分组字符的数字(长整数)。
  • Users input a number without grouping character. 用户输入一个没有分组字符的数字。
  • The string representation of the value contains the substring typed by the users. 值的字符串表示形式包含用户键入的子字符串。

To achieve this goal I'd use a custom RowFilter instead of using a regex filter like you do in your example. 为了实现这个目标,我使用自定义RowFilter而不是像在示例中那样使用正则表达式过滤器。 This is to have control about the string typed by the user and check the three conditions listed above. 这是为了控制用户键入的字符串并检查上面列出的三个条件。 I've managed to modify your searchTable() to satisfy the requirements. 我已经设法修改你的searchTable()以满足要求。 Note: I've included the queried String as an argument in this method to keep tf text field out of the implementation. 注意:我在此方法中包含了查询的String作为参数,以保持tf文本字段不在实现中。 Please see the code below: 请参阅以下代码:

private void searchTable(final String query) {

    RowFilter<TableModel, Integer> filter = null;

    if (query.length() > 0) {
        filter = new RowFilter<TableModel, Integer>() {
            @Override
            public boolean include(RowFilter.Entry<? extends TableModel, ? extends Integer> entry) {

               for (int i = 0; i < entry.getValueCount(); i++) {
                   String stringValue = entry.getStringValue(i);
                   Object entryValue = entry.getValue(i);
                   String numberString = entryValue instanceof Long 
                                       ? String.valueOf(entryValue)
                                       : "";

                   if (stringValue.contains(query) || numberString.contains(query)) {
                       return true;
                   }
               }

               return false;
            }

        };
    }

    table.setRowFilter(filter);
}

The flow will be more or less as follows: 流程将或多或少如下:

  1. If the query length is 0 just let the filter be null . 如果查询长度为0,则让过滤器为null This means the table won't be filtered and all rentries will be included. 这意味着不会过滤该表,并且将包括所有重试。

  2. If not (1) then prepare a new filter which iterates over the whole row asking if the String representation of the entry or the String value of the entry contains the queried String. 如果不是(1)则编写一个新的过滤器,该过滤器遍历整行,询问条目的字符串表示形式条目的字符串值是否包含查询的字符串。 While those might look the same thing they are not because Entry#getStringValue(int index) might (and actually does) retrieve a different value than String#valueOf(entry#getValue(int index)) . 虽然那些可能看起来不一样,但它们不是因为Entry#getStringValue(int index)可能(实际上)检索与String#valueOf(entry#getValue(int index))不同的值。 In this case the first one retrieves the Long including grouping separators (or formatted if you prefer) while the second one retrieves the Long with no formatting at all (it means, no grouping separators). 在这种情况下,第一个检索Long包括分组分隔符(或者如果您愿意,可以格式化 ),而第二个检索Long而根本没有格式化(这意味着没有分组分隔符)。

  3. Apply the filter to the table in either case. 在任何一种情况下都将过滤器应用于表格。

I hope the idea is clear enough. 我希望这个想法足够清楚。 If you want to filter a Double then it has to be tweaked a little bit because String.valueOf(double) includes the decimal (not grouping) separator and you might want to remove it before checking if it contains the queried String. 如果你想过滤一个Double那么它必须稍微调整一下因为String.valueOf(double)包含十进制(不是分组)分隔符,你可能想要在检查它是否包含查询的字符串之前删除它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM