Jtable, Rowfilter and Rowfilter.Entry

JTable, RowFilter and RowFilter.Entry

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();
}
});
}
}

How does JTable RowFilter work?

Using the tips from @MadProgrammer I came up with the following solution.

Not only does the RowSorter need to be replaced, you also need to keep the sort keys so the sort() method resets the table back to its current sort state:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;

public class FilterSSCCE extends JPanel
{
private JTable table;

public FilterSSCCE()
{
setLayout( new BorderLayout() );

JComboBox<Integer> comboBox = new JComboBox<Integer>();
comboBox.addItem( new Integer(1) );
comboBox.addItem( new Integer(2) );
comboBox.addItem( new Integer(3) );
comboBox.addItem( new Integer(4) );
comboBox.addItem( new Integer(5) );
comboBox.setSelectedIndex(4);

comboBox.addActionListener( new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
Integer value = (Integer)comboBox.getSelectedItem();
newFilter( value );
}
});
add(comboBox, BorderLayout.NORTH);

table = new JTable(5, 1);

for (int i = 0; i < table.getRowCount(); i++)
table.setValueAt(String.valueOf(i+1), i, 0);

table.setAutoCreateRowSorter(true);
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane, BorderLayout.CENTER);
}

private void newFilter(int numberOfRows)
{
RowFilter<TableModel, Integer> filter = new RowFilter<TableModel, Integer>()
{
@Override
public boolean include(RowFilter.Entry<? extends TableModel, ? extends Integer> entry)
{
int modelRow = entry.getIdentifier();
int viewRow = table.convertRowIndexToView(modelRow);

return viewRow < numberOfRows;
}

};

TableRowSorter oldSorter = (TableRowSorter)table.getRowSorter();
TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(table.getModel());
table.setRowSorter( sorter );
sorter.setRowFilter( filter );
sorter.setSortKeys( oldSorter.getSortKeys() );
sorter.sort();
}

private static void createAndShowGUI()
{
JPanel panel = new JPanel();

JFrame frame = new JFrame("FilterSSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new FilterSSCCE());
frame.setLocationByPlatform( true );
frame.pack();
frame.setVisible( true );
}

public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}

JTable Row Filter based on list of table model row integers

After studying and trying to grasp how the RowFilter Class works, i got my table to sort the way i want it to, it seems. I still need to do more testing but it looks like it is working. I still do not fully grasp the RowFilter Class so i would love some feedback.

Here is my code: where ArrayList<Integer> filteredRows = new ArrayList<>(); contains the row numbers i want to show. To my understanding, the filter automatically iterates over my table model and the identifier is the row number the filter is currently processing. So at first glance if the identifier equals any of the row numbers i have stored, then show it.

RowFilter<DefaultTableModel,Integer> rf = new RowFilter<>() {

@Override
public boolean include(Entry<? extends DefaultTableModel, ? extends Integer> entry) {
int entryRow = entry.getIdentifier();
for (Integer i : filteredRows) {
if (entryRow == i) return true;
}
return false;
}

};
TableRowSorter<DefaultTableModel> sorter = new TableRowSorter<DefaultTableModel>(myTableModel);
sorter.setRowFilter(null);
sorter.setRowFilter(rf);
table.setRowSorter(sorter);

JTable custom RowFilter?

What do you mean by text comparision? Have you added your filter and overridden include method?

boolean include(RowFilter.Entry<? extends M,? extends I> entry) 

The API document here RowFilter itself explains how you can filter based on integer/number or based on any property type

Merging two row filters for a JTable

Merging two row filters for a JTable

You can combine multiple filters into one. This example uses an "and" fileter, but you can also use an "or" filter:

List<RowFilter<Object,Object>> filters = new ArrayList<RowFilter<Object,Object>>(2);
filters.add(RowFilter.regexFilter(filterText.getText(), 0));
filters.add(RowFilter.regexFilter(filterText.getText(), 1));
rf = RowFilter.andFilter(filters);

This example was based on the Sorting and Filtering demo from the Swing tutorial.

JTable row filtering based on values of two different columns that Have same data

Looks like the "notFilter" was used in the wrong place. This seems to work:

List<RowFilter<Object, Object>> rfs = new ArrayList<>(2);
rfs.add(RowFilter.numberFilter(RowFilter.ComparisonType.EQUAL, 0, 1));
rfs.add(RowFilter.numberFilter(RowFilter.ComparisonType.EQUAL, 0, 2));
RowFilter<Object, Object> af = RowFilter.andFilter(rfs);

sorter = new TableRowSorter<>(((model)));
sorter.setRowFilter( RowFilter.notFilter(af) );
table.setRowSorter(sorter);

I also played around with using a custom RowFilter:

RowFilter<Object,Object> rf = new RowFilter<Object,Object>()
{
public boolean include(Entry<? extends Object, ? extends Object> entry)
{
Integer column1 = (Integer)entry.getValue(1);
Integer column2 = (Integer)entry.getValue(2);

if (column1.intValue() == 0 && column2.intValue() == 0)
return false;
else
return true;
}
};

sorter = new TableRowSorter<>(((model)));
sorter.setRowFilter(rf);
table.setRowSorter(sorter);

Note: in both cases the filter expects Integer data so it won't work if you edit a column and change the value to 0, because the model will be updated with a String value. I would assume your real TableModel would override the getColumnClass() method to return Integer.class for the last 2 columns.

JTable RowFilter displays wrong rows

String table_event = table_job.getModel().getValueAt(table_job.                          convertRowIndexToModel(row), 0).toString());

JTable with row Filter - how to iterate over filtered rows only

The lines

         for(int row = 0;row < table.getModel().getRowCount();row++) {
System.out.println(table.getModel().getValueAt(row, 0));
}

should be replaced with:

            for(int row = 0;row < table.getRowCount();row++) {
System.out.println(table.getModel().getValueAt(table.convertRowIndexToModel(row), 0));
}


Related Topics



Leave a reply



Submit