JTable, RowFilter and RowFilter.Entry
Asked Answered
L

1

4
  1. please I have an issue with RowFilter (its ComparisonType) to put together

    • Regex(String), Number, Date

    together with

    • AND, OR, NOR
  2. no idea how

    • to handle with null value for AND, OR, NOR
    • if Regex(String), Number, Date has the same logics or there "small differencies"
    • especially how to compare Date value
  3. some longer and detailed descriptions are welcome

  4. in this SSCCE to see my basic issues into frame.add(new JButton(new AbstractAction("Toggle filter") {

enter image description hereenter image description here

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.util.Calendar;
import java.util.Date;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;

public class JTableFilterDemo {

    private static TableRowSorter<TableModel> sorter;
    private Object[][] data = {{"A", 5, true, new Date()},
        {"B", 2, false, new Date()}, {"C", 4, false, new Date()},
        {"D", 8, true, new Date()}, {"E", 13, false, new Date()},
        {"F", 7, true, new Date()}, {"G", 55, false, new Date()},
        {"H", 6, false, new Date()}, {"I", 1, true, new Date()}};
    private String columnNames[] = {"Item", "Value", "Boolean", "Date"};
    private TableModel model = new DefaultTableModel(data, columnNames) {
        private static final long serialVersionUID = 1L;

        @Override
        public Class<?> getColumnClass(int column) {
            switch (column) {
                case 1:
                    return Integer.class;
                case 2:
                    return Boolean.class;
                case 3:
                    return Date.class;
                default:
                    return String.class;
            }
        }
    };
    private JTable table = new JTable(model);
    private Date modifDate = new Date();

    public JTableFilterDemo() {
        modifyDateInTable();
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        RowFilter<Object, Number> filter = new RowFilter<Object, Number>() {
            @Override
            public boolean include(RowFilter.Entry entry) {
                //String str = (String) entry.getValue(0);//String
                //return str.matches(("(?i)^a|^g"));//String
                //Boolean bol = (Boolean) entry.getValue(2);//Boolean
                //return bol.booleanValue() == false;//Boolean
                //Date date = (Date) entry.getValue(3);//Date
                //return date.getTime() > (long) (new Date().getTime());//Date
                //return ((Number) entry.getValue(1)).intValue() % 2 == 0;//Integer
                //return ((Number) entry.getValue(1)).intValue() > 0;//Integer
                return ((Number) entry.getValue(1)).intValue() > 10
                        & ((Number) entry.getValue(1)).intValue() < 50;//AND with Integer
            }
        };
        sorter = new TableRowSorter<TableModel>(model);
        sorter.setRowFilter(filter);
        table.setRowSorter(sorter);
        JScrollPane scrollPane = new JScrollPane(table);
        JFrame frame = new JFrame("Filtering Table");
        frame.add(new JButton(new AbstractAction("Toggle filter") {
            private static final long serialVersionUID = 1L;
            private RowFilter<TableModel, Object> filter = new RowFilter<TableModel, Object>() {
                @Override
                public boolean include(javax.swing.RowFilter.Entry<? extends TableModel, ? extends Object> entry) {
                    //String str = (String) entry.getValue(0);//String
                    //return str.matches(("(?i)^a|^g"));//String
                    //Boolean bol = (Boolean) entry.getValue(2);//Boolean
                    //return bol.booleanValue() == false;//Boolean
                    //Date date = (Date) entry.getValue(3);//Date
                    //return date.getTime() > (long) (new Date().getTime());//Date
                    //return ((Number) entry.getValue(1)).intValue() % 2 == 0;//Integer
                    //return ((Number) entry.getValue(1)).intValue() > 0;//Integer
                    return ((Number) entry.getValue(1)).intValue() > 10
                            & ((Number) entry.getValue(1)).intValue() < 50;//AND with Integer

                    // --->  doesn't works
                    //return ((Number) entry.getValue(1)).intValue() > 10 |
                    //((Number) entry.getValue(1)).intValue() < 50;//OR with Integer

                    // ---> works, but initialized on 2nd. event
                    //return ((Number) entry.getValue(1)).intValue() > 10 != 
                    //((Number) entry.getValue(1)).intValue() < 50;//NOR with Integer 
                }
            };

            @Override
            public void actionPerformed(ActionEvent e) {
                if (sorter.getRowFilter() != null) {
                    sorter.setRowFilter(null);
                } else {
                    sorter.setRowFilter(filter);
                }
            }
        }), BorderLayout.SOUTH);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(scrollPane);
        frame.pack();
        frame.setVisible(true);
    }

    private void modifyDateInTable() {
        Calendar c = Calendar.getInstance();
        c.setTime(modifDate);
        c.add(Calendar.DATE, - 1);
        modifDate = c.getTime();
        table.setValueAt(modifDate, 0, 3);
        c.setTime(modifDate);
        c.add(Calendar.DATE, +5);
        modifDate = c.getTime();
        table.setValueAt(modifDate, 1, 3);
        c.setTime(modifDate);
        c.add(Calendar.DATE, +1);
        modifDate = c.getTime();
        table.setValueAt(modifDate, 2, 3);
        c.setTime(modifDate);
        c.add(Calendar.DATE, - 16);
        modifDate = c.getTime();
        table.setValueAt(modifDate, 3, 3);
        c.setTime(modifDate);
        c.add(Calendar.DATE, +30);
        modifDate = c.getTime();
        table.setValueAt(modifDate, 4, 3);
        c.setTime(modifDate);
        c.add(Calendar.DATE, +55);
        modifDate = c.getTime();
        table.setValueAt(modifDate, 5, 3);
        c.setTime(modifDate);
        c.add(Calendar.DATE, +155);
        modifDate = c.getTime();
        table.setValueAt(modifDate, 6, 3);
        c.setTime(modifDate);
        c.add(Calendar.DATE, -23);
        modifDate = c.getTime();
        table.setValueAt(modifDate, 7, 3);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JTableFilterDemo jtfd = new JTableFilterDemo();
            }
        });
    }
}
Lashawna answered 25/7, 2013 at 10:1 Comment(2)
Does this simpler related example offer any guidance?Audition
@Audition thanks, I'm think (maybe sure) that not, my question is about IN/OUT off range defined by RowFilter.ENTRYLashawna
A
7

I see no unexpected result.

  1. The first predicate is straightforward; it includes the intersection of two overlapping sets, with the row having Value 13 as the only member.

    return ((Number) entry.getValue(1)).intValue() > 10
        & ((Number) entry.getValue(1)).intValue() < 50;
    
  2. The second predicate is the union of two overlapping sets, with all rows included.

    return ((Number) entry.getValue(1)).intValue() > 10 |
        ((Number) entry.getValue(1)).intValue() < 50;
    
  3. The third predicate is the complement of the first, with the row having Value 13 alternately included and excluded.

    return ((Number) entry.getValue(1)).intValue() > 10 != 
        ((Number) entry.getValue(1)).intValue() < 50;
    

Addendum: Regarding RowFilter.Entry, I found it helpful to examine how the and, or and not factories use the extra index parameter defined in the private class RowFilter.GeneralFilter; each subclass invokes the parent's implementation of include() for each filter supplied in the constructor. In contrast, the date, number and regex factories do not; instead, each relies on predicates available to the underlying type.

Addendum: As a concrete example, select two model dates, e.g. the first and penultimate.

Date d1 = (Date) model.getValueAt(0, 3);
Date d2 = (Date) model.getValueAt(model.getRowCount() - 2, 3);

Create two filters that bracket the chosen dates.

RowFilter<TableModel, Integer> low = 
    RowFilter.dateFilter(RowFilter.ComparisonType.AFTER, d1, 3);
RowFilter<TableModel, Integer> high = 
    RowFilter.dateFilter(RowFilter.ComparisonType.BEFORE, d2, 3);

Combine them in an andFilter.

List<RowFilter<TableModel, Integer>> filters = Arrays.asList(low, high);
final RowFilter<TableModel, Integer> filter = RowFilter.andFilter(filters);

The result selects rows between, but excluding, d1 and d2.

Modified SSCCE:

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;

public class JTableFilterDemo {

    private static TableRowSorter<TableModel> sorter;
    private Object[][] data = {{"A", 5, true, new Date()},
        {"B", 2, false, new Date()}, {"C", 4, false, new Date()},
        {"D", 8, true, new Date()}, {"E", 13, false, new Date()},
        {"F", 7, true, new Date()}, {"G", 55, false, new Date()},
        {"H", 6, false, new Date()}, {"I", 1, true, new Date()}};
    private String columnNames[] = {"Item", "Value", "Boolean", "Date"};
    private TableModel model = new DefaultTableModel(data, columnNames) {
        @Override
        public Class<?> getColumnClass(int column) {
            switch (column) {
                case 1:
                    return Integer.class;
                case 2:
                    return Boolean.class;
                case 3:
                    return Date.class;
                default:
                    return String.class;
            }
        }
    };
    private JTable table = new JTable(model);

    public JTableFilterDemo() {
        modifyDateInTable();
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        sorter = new TableRowSorter<TableModel>(model);
        table.setRowSorter(sorter);
        Date d1 = (Date) model.getValueAt(0, 3);
        Date d2 = (Date) model.getValueAt(model.getRowCount() - 2, 3);
        RowFilter<TableModel, Integer> low = RowFilter.dateFilter(RowFilter.ComparisonType.AFTER, d1, 3);
        RowFilter<TableModel, Integer> high = RowFilter.dateFilter(RowFilter.ComparisonType.BEFORE, d2, 3);
        List<RowFilter<TableModel, Integer>> filters = Arrays.asList(low, high);
        final RowFilter<TableModel, Integer> filter = RowFilter.andFilter(filters);
        JScrollPane scrollPane = new JScrollPane(table);
        JFrame frame = new JFrame("Filtering Table");
        frame.add(new JButton(new AbstractAction("Toggle filter") {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (sorter.getRowFilter() != null) {
                    sorter.setRowFilter(null);
                } else {
                    sorter.setRowFilter(filter);
                }
            }
        }), BorderLayout.SOUTH);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(scrollPane);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    private void modifyDateInTable() {
        Date modifDate = new Date();
        Calendar c = Calendar.getInstance();
        c.setTime(modifDate);
        c.add(Calendar.DATE, - 1);
        modifDate = c.getTime();
        table.setValueAt(modifDate, 0, 3);
        c.setTime(modifDate);
        c.add(Calendar.DATE, +5);
        modifDate = c.getTime();
        table.setValueAt(modifDate, 1, 3);
        c.setTime(modifDate);
        c.add(Calendar.DATE, +1);
        modifDate = c.getTime();
        table.setValueAt(modifDate, 2, 3);
        c.setTime(modifDate);
        c.add(Calendar.DATE, - 16);
        modifDate = c.getTime();
        table.setValueAt(modifDate, 3, 3);
        c.setTime(modifDate);
        c.add(Calendar.DATE, +30);
        modifDate = c.getTime();
        table.setValueAt(modifDate, 4, 3);
        c.setTime(modifDate);
        c.add(Calendar.DATE, +55);
        modifDate = c.getTime();
        table.setValueAt(modifDate, 5, 3);
        c.setTime(modifDate);
        c.add(Calendar.DATE, +155);
        modifDate = c.getTime();
        table.setValueAt(modifDate, 6, 3);
        c.setTime(modifDate);
        c.add(Calendar.DATE, -23);
        modifDate = c.getTime();
        table.setValueAt(modifDate, 7, 3);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JTableFilterDemo jtfd = new JTableFilterDemo();
            }
        });
    }
}
Audition answered 25/7, 2013 at 10:58 Comment(4)
thanks for answering my lacks, description about, fully answering my point 4th.Lashawna
I'm not sure I understand, but I've elaborated above.Audition
1. thanks quite understand (your edit) 2. I'm searching about combination(s) of Date with AND (OR, NOR) RowFilter, put together two methods (like SQL clause WHERE with a few AND/OR in statement), 3. my code posted here is only the bad, very wrong simulations of, 4. AFAIK aterai or Walter Laan commented these posts, and as you know very well that this is very specific API without answers, answerers, (few comments on OTN by kleopatra, but without any code), Extra-Terrestrial, a few UFOs in compare with CardLayout....Lashawna
Ah, I think I understand; I've added an example.Audition

© 2022 - 2024 — McMap. All rights reserved.