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
-
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 Answers
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...

- 343,457
- 22
- 230
- 366
-
-
-
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
-
-
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