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