1

I have a JTable which uses a RowFilter to filter fields but i want those results to be narrowed down to x amount like e.g. 5

mKorbel
  • 109,525
  • 20
  • 134
  • 319
Rated
  • 13
  • 3
  • The functionality you would need to determine this is maintained in `private` methods within the `DefaultRowSorter`...gotta love it – MadProgrammer Feb 18 '14 at 23:33
  • hmm .. what do you mean? 5 _rows_ (as @MadProgrammer interpreted and answered)? And if so, how do you want to determine which 5 rows? – kleopatra Feb 19 '14 at 07:56

1 Answers1

1

This is a lot of fun.

Basically, there is no way for the RowFilter to know where the RowSorter will want to check for included lines, so you can't place some kind of "counter" in the RowFilter and simply start returning false after a predetermined limit. The RowSorter also makes no guarantee that it will actually look for included lines in any order or as a whole group...it could check random lines, for example...

What you can do though, is create a RowSorter of your own and override it's sort method, which generally gets called whenever the underlying model has changed in some way or the model reference itself changes. Here you can then tell the RowFilter that it needs to reset it's count.

The Row Sorter

Basically, this is an implementation of TableRowSorter that looks for a special type of RowFilter and calls its reset method whenever it is called, this is meant to reset the number of lines that have been filtered back to 0

public class MyRowSorter extends TableRowSorter<TableModel> {

    public MyRowSorter(TableModel model) {
        super(model);
    }

    @Override
    public void sort() {
        RowFilter<? super TableModel, ? super Integer> filter = getRowFilter();
        if (filter instanceof LimitedRowFilter) {
            LimitedRowFilter lrf = (LimitedRowFilter) filter;
            lrf.reset();
        }
        super.sort(); 
    }

}

The LimitedRowFilter

This is a special, base, RowFilter which provides a lineCount and lineLimit which can be used by implementations to check if the number of filtered lines exceeds the maximum number of allowed lines.

It also provides the reset method used by the RowSorter

This could use some more additional functionality like includeAndIncrement which could return true if the line should be included or false if it would exceed the line count limit and would increment the lineCount automatically...

public abstract class LimitedRowFilter<M, I> extends RowFilter<M, I> {

    private int lineLimit;
    private int lineCount;

    public void reset() {
        lineCount = 0;
    }

    public int getLineCount() {
        return lineCount;
    }

    public void incrementLineCount() {
        lineCount++;
    }

    public int getLineLimit() {
        return lineLimit;
    }

    public void setLineLimit(int lineLimit) {
        this.lineLimit = lineLimit;
    }

    public LimitedRowFilter(int lineLimit) {
        this.lineLimit = lineLimit;
    }

    public LimitedRowFilter() {
    }

}

An example implementation of a LimitedRowFilter

This is a simple example of the LimitedRowFilter in action, it basically will return true for each line up to the maximum allowed limit...

public class MyRowFilter extends LimitedRowFilter<TableModel, Integer> {

    public MyRowFilter() {
        super();
    }

    public MyRowFilter(int limit) {
        super(limit);
    }

    @Override
    public boolean include(Entry<? extends TableModel, ? extends Integer> entry) {

        boolean included = true;
        // Do you own checking here to determine if the row should be included or
        // not
        if (included) {
            if (getLineCount() < getLineLimit()) {
                incrementLineCount();
            } else {
                included = false;
            }
        }

        return included;

    }

}

A runnable example

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.swing.DefaultRowSorter;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.RowFilter;
import javax.swing.RowSorter;
import javax.swing.SortOrder;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;

public class LimitedTableRowFilter {

    public static void main(String[] args) {
        new LimitedTableRowFilter();
    }

    public LimitedTableRowFilter() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }
                DefaultTableModel model = new DefaultTableModel(new Object[]{"A"}, 0);
                for (int index = 0; index < 100; index++) {
                    model.addRow(new Object[]{index});
                }
                JTable table = new JTable(model);
                MyRowSorter sorter = new MyRowSorter(model);
                MyRowFilter filter = new MyRowFilter(10);

                sorter.setRowFilter(filter);
                table.setRowSorter(sorter);

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new JScrollPane(table));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
}

Disclaimer

I'll be the first to admit that this is a less than perfect solution, but it beats having to copy the entire source for the DefaultRowSorter and TableRowSorter just so we can gain access to the private methods we would need to use to implement the functionality directly within the sorter itself.

I've only done limited testing so you may need to do some of your own tweaking...

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • @mKorbel To which part (of my answer) are you referring? – MadProgrammer Feb 19 '14 at 07:49
  • to enhance the LimitedRowFilter – mKorbel Feb 19 '14 at 07:51
  • having a hard time understanding the answer (actually, it's more like hard to understand the question ;-) - are you implementing some weird kind of pagination? – kleopatra Feb 19 '14 at 07:54
  • @mKorbel Ah, yes, excellent examples. I had assumed that since the OP said they already had a `RowFilter`, I didn't bother fully implementing the logic in my own :P – MadProgrammer Feb 19 '14 at 07:54
  • @kleopatra Hadn't intended to. Basically, when `sort` is called, it resets the filter, when the filter has processed `n` number of lines successfully, it simply returns `false` to every other request, it ain't pretty, not 100% sure if it works 100% of the time, but my alternative was to make a copy of the `DefaultRowSorter`...and about there I decided to try something else ... – MadProgrammer Feb 19 '14 at 07:56
  • @kleopatra As I understand it, the OP wants to display up to `n` number of matches...not all the matching rows, but what do I know :P – MadProgrammer Feb 19 '14 at 07:57
  • your solution looks fine, but it feels like a weird requirement: so the user sorts and sees _different_ content? My-oh-my ... smells like a bad user experience, @Rated – kleopatra Feb 19 '14 at 08:01
  • without actually having coded anything: I would try to reset the filter in a RowSorterListener .. hmm. – kleopatra Feb 19 '14 at 08:04
  • @kleopatra I'd have to test it further as I had very simple test data, but when I sorted it, I got the same results, so it appears to be filtered first then sorted based on the filtered results, but this would come down to the implementation of the sorter... – MadProgrammer Feb 19 '14 at 08:04
  • @kleopatra - didn't even think about the listener support :P – MadProgrammer Feb 19 '14 at 08:05
  • yeah, you are right: filtering happens on the model before sorting and happens top-to-bottom. Which is an implementation detail... – kleopatra Feb 19 '14 at 08:12