This is a guest post by Thomas Nield, a contributor to ControlsFX. Enjoy 🙂
Last year I spent a decent amount of time contributing a TableFilter
control to the ControlsFX project. It was inspired by Eugene Ryzhikov’s SwingBits project which contained a table filtering control for Swing. After recently making some enhancements, it seemed like a good time to share the TableFilter
and what it can do. I hope it enriches your UI much like the rest of the ControlsFX project has done for me.
The TableFilter
behaves very similarly to Excel's spreadsheet filter. Right-clicking on a column header will make it visible, and a searchable checklist of distinct values for that column allows you to quickly filter for data.
Here is how it works:
Step 1: Have a TableView
with a TableFilter
applied
TableView<Person> tableView = ... //add TableColumns TableFilter filter = new TableFilter(myTableView);
Step 2: Right click the header for the column you want to filter on
Step 3: Either search for items you want to filter on or uncheck values you want to filter out
Step 4: Click APPLY to execute the filter
You can always remove the filter by right-clicking any column and clicking RESET to clear the filter for that particular column, or RESET ALL to remove all filters for all columns.
How it Works
This filter control is highly intuitive to business users. From my experience, many expect it especially if they have worked with Excel. But for something that is so intuitive to use, there are a surprising number of complicated moving parts the developer has to account for:
- A distinct set of values must be maintained for each column
- Values that are selected/unselected must be tracked
- If data is added or removed, the distinct values must be rebuilt while persisting the selected/unselected values
- Each column can have a separate filter applied, and only mutually inclusive items that qualify with all filters can be displayed
- Users may want distinct values to be grayed out if they are no longer visible due to a recent filter in another column
- There may be a need to customize search "strategies" for distinct values, such as wildcards, regular expressions, date and number comparisons, etc.
The TableFilter
control does all the above, and after a lot of work I have used it in production for about six months. My clients have been extremely satisfied with it and it has worked reliably.
The TableFilter
will swap out the ObservableList
of items
with a FilteredList
. This FilteredList
will only display items that qualify on all column's respective filters. This means you can execute filters on more than one column in combination.
For instance, we have already filtered to records where the last name is "Warren". We can add another filter where the age is 16. Note that when I right-click the "Age" column, values that are no longer visible due to the "Last Name" filter are grayed out. You can use the "NONE" button to unselect all values and pick the value(s) you are interested in.
STEP 1: Right-Click "Age" and apply a second filter
STEP 2: Hit "Apply" to execute the second filter
You can remove all filters from all columns by right-clicking any column and clicking "RESET ALL".
Custom Search Strategies
One simple but highly flexible configuration you can do with the TableFilter
is change the search behavior on the search box. By default, the search box will filter distinct values based on the inputted String
, and pass it to the contains()
method of each distinct value's toString()
. Effectively, whatever input you type in the search box will match distinct values that contain it.
You can change this behavior easily by passing a BiPredicate<String,String>
lambda, where the first String
parameter is the "input" from the search box, and the second String
value is the "target" representing each distinct value. Using these two String
inputs, you can do any matching logic that returns a boolean
.
For example, you can implement the search box behavior to use regular expressions for the table filters.
TableFilter<Person> tableFilter = new TableFilter<>(table); tableFilter.setSearchStrategy((input,target) -> { try { return target.matches(input); } catch (Exception e) { return false; } });
Now I can use regular expressions to search through the distinct values.
Note I had to use the try-catch
because event-driven text inputs will likely contain broken regular expressions, especially as they are being typed. When the typed input is currently not a valid regular expression, I just default the qualification to false
.
Not that all values for all columns are searched by their toString()
values. This makes sense since you are searching by typing in String
inputs, so the distinct values should be compared to the input as String
values as well. You can do other behaviors, like using startsWith()
instead of contains()
or even a wildcard pattern system.
Currently, the API is set up to use one search strategy for all column filters. I may explore column-specific search behaviors later but for now I feel it would complicate the API. But with a little effort, you can create more complex search strategies that recognize numbers, dates, and even simple math expressions. For example, you could evaluate if the two String
inputs are numbers. If the numeric input starts with a "less than" symbol, as in "<120", you would then only qualify distinct values that are less than 120. This sounds involved but I have found it is not much work, and it just requires a few nested case
statements. I have even developed implementations that can work with date strings of various formats.
Updating Data in the TableView
Because the TableFilter
commandeers the TableView
's backing ObservableList
and replaces it with a FilteredList
, you will get errors when trying to modify the backing ObservableList
of items returned from getItems()
.
To modify the "backing list" of items for a TableView
, call the getBackingList()
method on the TableFilter
and modify that instead to update the TableView
.
TableFilter<Person> tableFilter = new TableFilter<>(table); ObservableList<Person> items = tableFilter.getBackingList();
Conclusions
I hope you find the TableFilter
useful. It is currently available in the ControlsFX project but an improved version (which includes the custom search strategy and fixes for nullability issues) is available in the coming release. Please let us know what you think and do not hesitate to get involved if you have ideas or improvements.
Great job. The first thing that I see is that there isn’t the usual filter icon on the column that has a filter set.
I think this is very very important for the user experience.
In this case the stuff should be managed manually?
Thanks
Yes, the icon has occurred to me and I agree that would increase usability. Just haven’t gotten around to it yet. I wont complain if someone else wants to beat me to implementing it though.
I think the comment system is broken :/ Vowels are missing.
I noticed that yesterday….I’m not sure why! 🙂
Fixed I think….
I added filter icons and improved some of the visuals (including ridding the blue highight). The TableColumn will even bump a few pixels wider to make room for the filter icon.
I’ll put in a PR.
http://i.imgur.com/TghHFeU.png
Brilliant control! Thank you for contributing to the community!
Glad you like it 🙂
I was looking for this type of functionality – so great job. Any idea on when the next version of ControlsFX will be available? We can’t use the ControlsFX Project in our development, as we need to use the released tooling.
Forgot to ask this above – from your code sample – this should be fully compatible with SceneBuilder since there is no layout portion of this – is this a correct assumption? Also – will this still support sorting the table based on the headers?
It will apply the sorters for you. Regarding SceneBuilder I don’t know since I am not a heavy user of it. Jonathan Giles might be able to provide answers to that as well as the release once it is planned.
Hi,
the filter is great but if I load small Data in my TableView (66 entries) the filter works fine.
When I load more Data (~66000] the app crash when aktivating filter.
Hi Reinhard,
I have made some substantial improvements in a pull request this week and overhauled the backing engine to support a high volume of records. I even added listeners for cell value changes.
Feel free to watch (or even use) this PR and it should be in the next release.
https://bitbucket.org/controlsfx/controlsfx/pull-requests/581/tablefilter-performance-optimizations/diff#comment-None
Getting a few NPE stack traces from the logs when viewing it on my table. Some columns have empty entries.
java.lang.NullPointerException: null
at impl.org.controlsfx.table.FilterPanel$FilterValueComparator.compare(FilterPanel.java:149) ~[controlsfx-8.40.10.jar:8.40.10]
at impl.org.controlsfx.table.FilterPanel$FilterValueComparator.compare(FilterPanel.java:143) ~[controlsfx-8.40.10.jar:8.40.10]
at javafx.collections.transformation.SortedList$ElementComparator.compare(SortedList.java:278) ~[jfxrt.jar:na]
at javafx.collections.transformation.SortedList$ElementComparator.compare(SortedList.java:267) ~[jfxrt.jar:na]
at java.util.Arrays.binarySearch0(Arrays.java:2545) ~[na:1.8.0_71]
at java.util.Arrays.binarySearch(Arrays.java:2530) ~[na:1.8.0_71]
at javafx.collections.transformation.SortedList.findPosition(SortedList.java:305) ~[jfxrt.jar:na]
at javafx.collections.transformation.SortedList.insertToMapping(SortedList.java:335) ~[jfxrt.jar:na]
at javafx.collections.transformation.SortedList.addRemove(SortedList.java:397) ~[jfxrt.jar:na]
at javafx.collections.transformation.SortedList.sourceChanged(SortedList.java:105) ~[jfxrt.jar:na]
at javafx.collections.transformation.TransformationList.lambda$getListener$15(TransformationList.java:106) ~[jfxrt.jar:na]
at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88) ~[jfxrt.jar:na]
at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164) ~[jfxrt.jar:na]
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73) [jfxrt.jar:na]
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233) [jfxrt.jar:na]
at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482) [jfxrt.jar:na]
at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541) [jfxrt.jar:na]
at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205) [jfxrt.jar:na]
at impl.org.controlsfx.table.DistinctMappingList.sourceChanged(DistinctMappingList.java:36) [controlsfx-8.40.10.jar:8.40.10]
at impl.org.controlsfx.table.DistinctMappingList.lambda$new$145(DistinctMappingList.java:20) [controlsfx-8.40.10.jar:8.40.10]
at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329) ~[jfxrt.jar:na]
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73) [jfxrt.jar:na]
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233) [jfxrt.jar:na]
at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482) [jfxrt.jar:na]
at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541) [jfxrt.jar:na]
at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205) [jfxrt.jar:na]
at javafx.collections.ModifiableObservableListBase.add(ModifiableObservableListBase.java:155) ~[jfxrt.jar:na]
at java.util.AbstractList.add(AbstractList.java:108) ~[na:1.8.0_71]
Looks like the issue is
private static final class FilterValueComparator implements Comparator {
@Override
public int compare(FilterValue first, FilterValue second) {
if (first.getInScopeProperty().get() && !second.getInScopeProperty().get())
return 1;
int compare = first.getValueProperty().getValue().toString().compareTo(second.getValueProperty().getValue().toString());
if (compare > 0)
return 1;
if (compare < 0)
return -1;
return 0;
}
}
The comparable should really check the value
This was resolved awhile ago. Can you make sure you have the latest release?
Great Tool Thanks 😀
Hi Jonathan Giles,
Firstly this is a great solution for providing excel like filtering for JavaFx TableView. I am currently implementing this into one of the projects I am working on. However, the TableFilter class throws errors if there are any null values in the underlying observablelist…
TableFilter filter = new TableFilter(myTableView);
Error = NULL POINTER EXCEPTION.
Currently I have had to create a custom modification in my class files getters and setters to handle nulls and replace them with an appropriate value to fix the issue.
My question is are you going to allow the TableFilter class to handle nulls? or is there already an easy way to do this that I am not aware of?
Thanks alot for the help.
Cheers,
Josh
Hi Josh, this issue has been resolved along with many enhancements in the current build on BitBucket. The release version does not reflect any of these fixes or enhancements yet.
Go ahead and do a build, and that will resolve your issue.
Great Thomas! Thanks for the help! 🙂
Where I can download jar ?
great job
but could share the jar file or the code
thank you so much
Awesome control, thank you! But how can I specify columns I don’t want to allow to filter?
Hey Tanya,
That currently is not an option but perhaps can be added. Just curious, are you preventing a certain column from being filterable because its a performance-expensive column? Or is it simply a business reason? If it’s the former, you can use the lazy configuration. For the latter, keep in mind that may not be intuitive for users and they may think it’s broken.
Hello Thomas, thank you for your reply.
I asked for the following reasons.
In my table I have a column that contains just “Delete” button to delete the appropriate row. So it doesn’t make sense to filter it.
Or the second case: I have a datetime column where all values are unique and the difference between them is in milliseconds. And there is no business reason to filter them as well.
Ah, that makes sense and are valid cases to suppress the filters. Let me think about it as I’m considering ways to open up the API a bit more to configure specific columns. I’ve been busy with RxJavaFX stuff and I’m traveling this week, but I’ll take a look and see if I can add that option easily.
Great work!
Any updates on specifying columns without filtering option?
I am using large tables. In columns with a lot of different values it has performance impact.
Good work.
Can I make a request for enhancement? I currently use a Jidesoft library with swing applications that offers similar functionality but has one particular advantage – it allows for custom filters.
For example, if a column contains numbers, the custom filters include: is any number, equals, doesn’t equal, is in, isn’t in, is empty, is not empty, etc. etc.
The custom filters are tailored to the column data type and the initial view is just a simple listing of the available values (no checkboxs) plus (All) and (Custom) at the head of the list. Clicking a vlaue filters the table for that single value, selecting ‘Custom’ pops up a dialog that allows for multiple slections by checkbox using the ‘is in’ predicate. Overall, the interface is cleaner and has a good deal more functionality. Given that you have already gone to considerable effort to produce a workable filtering solution I wonder if you are open to enhancements?
I’ve definitely thought about this before, just never have gotten around to it. I think the best approach would be to open up the API and then have a custom menu developers can put items into.
Can you open an issue on BitBucket so we can track it?
https://bitbucket.org/controlsfx/controlsfx/issues?status=new&status=open
Taken a while to get this done – but RFE has been raised:
https://bitbucket.org/controlsfx/controlsfx/issues/689/enhanced-table-filter-controls
How can i use it in dynamic tableview or tableview without getter and setter
Check this Example:
https://bitbucket.org/controlsfx/controlsfx/src/ffbe694287a11cabd8bded01bdd3177d2b833f99/controlsfx-samples/src/main/java/org/controlsfx/samples/tablefilter/ConcurrentTableFilterTest.java?at=default&fileviewer=file-view-default
Hi Thomas,
Being newBee to javaFx world, could you please provide a link or a simple example on this excellent column filter. So as to unde. Please help with a sample code of above example or similar if any…
Thanks
Nick
OMG… it is so awesome
Thank you very much for creating and sharing it
Hi,
thank you for this great component.
I am experiencing a problem whit a table for which I have defined a custom CellFactory on a Column: when I apply a filter the cell(s) of that particular column that belong to filtered rows still appear, and display a wrong value (the one from the previous row). Is this an issue/limitation with the component?
This is a simplified version of how I set the CellFactory (in reality I also add an image into the cell):
MyColumn.setCellFactory(new Callback<TableColumn, TableCell>() {
@Override
public TableCell call(TableColumn param) {
return new TableCell() {
Label lbl;
{
lbl = new Label();
setGraphic(lbl);
}
@Override
public void updateItem(Integer item, boolean empty) {
if (item != null) {
lbl.setText(item.toString());
}
}
};
}
});
Sorry, that was my fault, I fixed it by changing the updateItem methos this way:
public void updateItem(Integer item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
} else {
lbl.setText(item.toString());
setGraphic(lbl);
}
}
If this filter supports sorting, could you give me a quick example of how sort? Thank you!
Nice work!
When I type a search query in the box, I see the matching entries below. However if I uncheck some of the matching entries and hit ‘Apply’, all of the search results are included in the table rows, including the entries which I unchecked. Is this a known issue/my misuse of the API, a new issue, or has it been solved since cfx 8.40.12?
That sounds like an issue. Can you file an issue and I’ll see if I can get to it hopefully within a few weeks?
Hello everyone. Great job!
A query. Can I use this filter to generate reports?
I see the TableFilter is now deprecated. Is that true? Is there an alternative option for the same?
The constructor is deprecated. Use the builder via TableFilter.forTable()
This is a great component! Thanks a lot!
I’m having a problem clearing the BackingList. I’m just calling filter.getBackingList().clear() and I am receiving a java.util.NoSuchElementException: No value present.
Part of the stack trace is:
at java.util.Optional.get(Optional.java:135)
at impl.org.controlsfx.table.ColumnFilter.removeBackingItem(ColumnFilter.java:187)
at impl.org.controlsfx.table.ColumnFilter.lambda$null$138(ColumnFilter.java:217)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1374)
at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
at impl.org.controlsfx.table.ColumnFilter.lambda$initializeListeners$139(ColumnFilter.java:217)
at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
at com.sun.javafx.collections.ObservableListWrapper.clear(ObservableListWrapper.java:157)
at com.gapso.frota.view.component.FrotaTableView.setTableData(MyCode.java:111) —> This is where I call the .clear();
I have tried putting it on a Platform.runLater and using retainAll and etc but nothing seems to work.
Any ideas? Thanks a lot!
This was addressed about a month ago, but has not been released officially in a build yet. You can build a snapshot of ControlsFX to resolve this issue now.
I have the same issue and tried Platform.runLater too, but no luck
This was addressed about a month ago, but has not been released officially in a build yet. You can build a snapshot of ControlsFX to resolve this issue now.
Hi Thomas, thanks for the answer. Is there any workaround that doesn’t require a manual build? I would like to keep the official release for security purposes, it has been well tested and stuff…
So, I solved it by cloning the version I was using and applying the same changes Thomas applied on his pull request (https://bitbucket.org/controlsfx/controlsfx/issues/704/nosuchelementexception-on-columnfilter).
Then I built it again and it Works.
Thanks!
This is a really useful addition to TableView but as we use Pagination with our TableViews, the fact that it replaces the TableView’s items list is a problem.
Do you think it would be a reasonable enhancement to add a “backing list” property to the Builder? The TableFilter could then (optionally) use that list instead and not replace the TableView’s items list (and provide an accessor for the SortedList so we can use it for paging)?
That seems sensible. Not hard really either. Can you submit an issue and I’ll try to get to it soon?
I don’t think it is as straightforward as you make it sound. It might be, but I would have to think it through and understand your use case better. I’ll tell you what, if you want to clone the project and see if you can modify it to get it working for you, put in a PR and I’ll see if it breaks anything.
Thanks for the quick response, I’ll certainly try to find time to do that – just wanted to see if there might be any obvious reason why not before making any formal request. I did run a hacky “test” by copying the source to a temporary test package and modifying the code there and it seemed to resolve our problem at first glance.
Our basic requirement is to use paging (we use a javafx.scene.control.Pagination control) rather than scrolling through the “whole” list, so that the TableView’s items list is actually a sublist of the sorted backing list.
Have you considered just calling `setAll()` on the backingList to change the items? That sounds like it would fulfill what you are trying to accomplish…
Will check but not sure I see how that would work… wouldn’t the Comparator then be operating only on the current page, not the entire list?
For a very simple example, imagine a paged table with a single String column, showing a list of the letters of the alphabet and a page size of 10. It would therefore have 3 pages and initially show page 1 with letters A-J, in that order. If I reverse the column’s sort order via the table column the table should stay on page 1 and show Z-Q, not J-A.
If this is too fringe a use case that’s absolutely fine, we’ll find another option (and many thanks again for your help) – this is probably not the place for a detailed requirements discussion 🙂
Nice work!
I run into two issues when trying to add it to my Tableview. Maybe you have a pointer for me how to fix them.
1) Besides the filter on the column I’m applying I have an additional filter on a hidden column (for selecting list items based on choices in other controls). That filter is set using
myTableFilter.selectValue(myFilterColumn, filterValue);
myTableFilter.executeFilter();
but doesn’t seem to work in the moment. No changes to the list when changing the filterValue…
2) I get below exception when applying selected values for a visible column
Exception in thread “JavaFX Application Thread” java.lang.RuntimeException: TableColumn.prefWidth : A bound value cannot be set.
at javafx.beans.property.DoublePropertyBase.set(DoublePropertyBase.java:143)
at javafx.scene.control.TableColumnBase.setPrefWidth(TableColumnBase.java:431)
at impl.org.controlsfx.table.FilterPanel.lambda$null$177(FilterPanel.java:150)
at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.Iterator.forEachRemaining(Iterator.java:116)
at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
at impl.org.controlsfx.table.FilterPanel.lambda$new$178(FilterPanel.java:144)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Node.fireEvent(Node.java:8413)
at javafx.scene.control.Button.fire(Button.java:185)
at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:96)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3757)
at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:381)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(GlassViewEventHandler.java:417)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:416)
at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
at com.sun.glass.ui.View.notifyMouse(View.java:937)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
at java.lang.Thread.run(Thread.java:745)
Hi,
this is a great control.
I didn’t find an API to read and preselect the filters, e.g. when you want to reload a table and preserve the filter settings.
Is there a way you can achieve this?
Cheers,
Michael
I think there is. I am swamped but explore the methods and you should see there is a way. I’ll do my best to follow up later.
To read the values I just found
tableFilter.getColumnFilter(…).get().getFilterValues()
but the class FilterValue is not visible.
Also I did not find a method to select values, only to unselect, which also doesn’t work in my setup.
So I’m stuck here and don’t see the correct way to achieve it… I would really appreciate, if you catch up later 🙂 Thanks
I implemented a PR that should allow this with a better API, and some fixes in the implementation. https://bitbucket.org/thomasnield/controlsfx/pull-requests/1/tablefilter-api-improvements/diff
This is awesome tks, saved me a lot of work. i was implementing something similar when i found it.
How would one go about changing the strings in the apply, reset, etc.. buttons? i need them in spanish. is this i18n ?
got it!
just add:
impl.org.controlsfx.i18n.Localization.setLocale(Locale.forLanguageTag(“es-ES”));
before you init the filter table
Is there not another way? I want to access the node, make the spacing of the HBox or whatever it is higher so it doesn’t look that ugly and replace the Text with an Icon/Image. Please help..
Hi, great control which saved lots of work. Thank you!
As Tanya mentioned I would like to specify columns I don’t want to allow to filter and/or be able to strip HTML content. We use WebView to show formatted text in TableCells and would like to show the plain text instead of HTML at the filter control.
Regards,
Kris
Wow, what a breeze to apply. Thanks for the great control.
The only issue I worry about is my users not knowing that they can filter by right-clicking the column. I was thinking maybe doing something onHover—like flashing the little sort icon when they hover over the column header.
Any good ideas?
Very useful, nice job. One small question: is it possible to have the focus in the search box when opened?
I started to use the TableFilter and I like it! The filtering through the user interface works fine. Besides that I wanted to provide also filtering through my own widgets like buttons etc.
I assumed the following should work but it does not.
tableFilter.selectValue(lastNameCol, “Smith”);
tableFilter.executeFilter();
Any ideas/proposals? I also submitted an issue because I think it is a bug (https://bitbucket.org/controlsfx/controlsfx/issues/843/programmatic-tableview-filter-does-not). Please state me wrong!
Thanks!
Fantastic component and so easy to use. Great job.
The List View in the Context Menu popup does not seem to use the cell factories from the table column to render the filter items. Is there a way to set a cell factory for the list view popup so they’re rendered the same as the table column items?
Hi Jonathan Giles, Nice to have this feature and I have implemented this filter feature in one of my current project. I have a requirement after applying filter it shows few results which needs to be captured and do some math on it and display the updated value in one of the row.
I tried List change listener that didn’t help me to fetch this values whenever I applied filter to get the remaining value from tableview.
Is there any listener available to perform an action when I click on apply to filter the data.
Any suggestions or ideas are appreciated how can i implement it!!
Hello,
Awesome work!
Is it possible to filter on ImageViews?
In mij TableView I have a column that indicates True or False.
But instead showing true or false, I show ImageViews (green check icon or red cross icon).
If I filter, the TableFilter shows me the toString of every ImageView object.
Is it possible to view only “True / False” in the tableFilter and thus filter on my ImageViews?
Thanks,
Marchala
new TableFilter(TableView) is now deprecated. Please update how to use it & more-importantly, at the top of the TableFilter javadoc. It didn’t populate unless I called it AFTER I had set the items. A good tip to tell people. Also, it didn’t work initially because I already had a context menu for COPY functionality. Not sure how to blend these.
you helped me alto thanks
i just noticed that .matches is never used for now
replace it with .equals
below is the doc that support my words
https://controlsfx.bitbucket.io/org/controlsfx/control/table/TableFilter.html
and thanks a lot for your help