I'm trying to filter Rows in a JTable
which contains Columns with numbers.
The filtering is working so far, but it filters over the numbers including the thousands-separators. For example, if there is a row with the number 25689 in one row and I try to filter for this row, i have to use "25.689". So it seems there is a formatting that is performed before the filtering.
I've tried to set an own default renderer and the numbers are shown without the separators but the filtering is the same.
Edit
I've added a full example re-creating my problem:
public class GroupingTest {
JFrame frame= null;
Container pane= null;
JTextField tf=null;
JXTable table=null;
public void searchTable() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
final String searchEx = "(?i)"
+ Pattern.quote(tf.getText());
final RowFilter<TableModel, Object> filter;
filter = RowFilter.regexFilter(searchEx);
table.setRowFilter(filter);
//packAll in edt
Utility.packTableView(table);
} catch (final Exception e) {
return;
}
}
});
}
public void createTable() {
frame = new JFrame();
pane=frame.getContentPane();
tf = new JTextField();
tf.setPreferredSize(new Dimension(200,25));
tf.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void removeUpdate(final DocumentEvent e) {
searchTable();
}
@Override
public void insertUpdate(final DocumentEvent e) {
searchTable();
}
@Override
public void changedUpdate(final DocumentEvent e) {
searchTable();
}
});
String[] columnHeaders = {"long","strings"};
DefaultTableModel $model = new DefaultTableModel(columnHeaders, 0) {
@Override
public Class<?> getColumnClass(final int $col) {
if($col == 0) {
return Long.class;
} else if($col == 1){
return String.class;
} else {
return Object.class;
}
}
};
table = new JXTable($model);
table.setDefaultRenderer(Long.class, new DefaultTableCellRenderer() {
@Override
public java.awt.Component getTableCellRendererComponent(final JTable $table,
final Object $value, final boolean $isSelected, final boolean $hasFocus, final int $row,
final int $column) {
super.getTableCellRendererComponent($table, $value, $isSelected, $hasFocus, $row, $column);
if ($value instanceof Long) {
this.setHorizontalAlignment(SwingConstants.RIGHT);
}
return this;
}
});
Object[] line1 = {new Long(23345),"asdf"};
$model.addRow(line1);
Object[] line2 = {new Long(3),"dfw"};
$model.addRow(line2);
pane.add(tf,BorderLayout.NORTH);
pane.add(new JScrollPane(table),BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(300,200));
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
GroupingTest gt = new GroupingTest();
gt.createTable();
}
}
When the value's format interferes with the expected functioning of sorters and filters then it's time to check if getColumnClass(int columnIndex) in the table model is retrieving the appropriate class (in this case
Double
).By default
AbstractTableModel
implementation of such method returnsObject.class
which is rendered using thetoString()
method (that's why you see the thousands-separator) and probably filtered according to the string representation as well. Subclasses ofAbstractTableModel
(such asDefaultTableModel
) inherit this implementation and thus this method should be overriden. For example let's say your table model isDefaultTableModel
and the first column is aDouble
:See Sorting and Filtering section of How to Use Tables tutorial for further details.
Update
Given your new MVCE it is clear now what are you trying to achieve. I'd start saying that I've mistakenly assumed your table model holds
Double
instead ofLong
which makes no difference about overridinggetColumnClass()
method (it should be done anyways) but it will make a slight difference in the final solution.Now, to state the requirements clear, you need to filter that column either:
To achieve this goal I'd use a custom
RowFilter
instead of using a regex filter like you do in your example. This is to have control about the string typed by the user and check the three conditions listed above. I've managed to modify yoursearchTable()
to satisfy the requirements. Note: I've included the queried String as an argument in this method to keeptf
text field out of the implementation. Please see the code below:The flow will be more or less as follows:
If the query length is 0 just let the filter be
null
. This means the table won't be filtered and all rentries will be included.If not (1) then prepare a new filter which iterates over the whole row asking if the String representation of the entry or the String value of the entry contains the queried String. While those might look the same thing they are not because Entry#getStringValue(int index) might (and actually does) retrieve a different value than String#valueOf(entry#getValue(int index)). In this case the first one retrieves the Long including grouping separators (or formatted if you prefer) while the second one retrieves the Long with no formatting at all (it means, no grouping separators).
Apply the filter to the table in either case.
I hope the idea is clear enough. If you want to filter a
Double
then it has to be tweaked a little bit becauseString.valueOf(double)
includes the decimal (not grouping) separator and you might want to remove it before checking if it contains the queried String.