Sunday, May 1, 2011

The Awesomeness of Java table filters

While working on a coding project related to my thesis, I ran into java table filters. Initially, I was quite hesitant to use those, merely for the obscureness bundled with them, but soon I was proven wrong. At first I thought, I'd be better off creating a database and constructing the queries as we go. Apart from the fact that I have historically hated databases, for slowness, dependencies and the time required to design them and lack of visibility in terms of wtf is exactly happening inside, I decided to give java filters a shot, simply because all I needed to do was deal with a visible table and have user play with it to his/her heart's content.
The first thing I look for when using something I have never used before is the working example, e.g. on roseindia.com or something instead of looking at the javadocs. In short, I cheat because I am impatient and I do not wish to learn the language, but instead get the work done! Recently, I have been avoiding roseindia.com because of poor coding style, but those guys are bang on in terms of how to use something, no bullshit! I don't exactly remember, but I guess there's not much about filters on roseindia.com so I settled for java tutorials example which i found here.
Example is pretty much self explanatory, in the sense that it gives you at least two key hints:
1. You have to add a DocumentListener to a text field and override all the update methods that come with the DocumentListener interface. But where this example or any other example anywhere on the internet including sun (now oracle) website fails is that these guys end up defining the listener at the exact same place where it was added on the field. This is what I am talking about:

filterText.getDocument().addDocumentListener(

new DocumentListener() {

public void changedUpdate(DocumentEvent e) {

newFilter();

}

public void insertUpdate(DocumentEvent e) {

newFilter();

}

public void removeUpdate(DocumentEvent e) {

newFilter();

}

});


And I seriously believe that this is a very bad way of doing it, because the objects and fields and methods of current class are simple inaccessible within these update method definitions, because this space actually belongs to the new class DocumentListener. In my opinion, a better way of doing it is

filterText.getDocument().addDocumentListener(new YourListenerImplementation(Object1, Object2...));


and


class YourListenerImplementation{


public YourListenerImplementation(Object1, Object2....){


}

@Override

public void changedUpdate(DocumentEvent event) {

// do stuff here

//create new filter each time

}


@Override

public void insertUpdate(DocumentEvent event) {

//do stuff here

// create new filter each time

}


@Override

public void removeUpdate(DocumentEvent event) {

// do stuff here

// create new filter each time


}


}

So, now you have a freedom to parameterize the filter. This way, filter can be reused as well.

2. Regular expression is the key:
Now comes the filter part. Against my expectations, this was very easy! All I needed to do was to make sure that I am receiving a valid regular expression from the caller. What example also fails to demonstrate is that you can actually search over the entire row instead of sticking to a particular column. Had I found that out earlier, it would have saved me writing an additional function, but better late than never! I ended up implementing a filter, which takes multiple comma separated values from a text field and lists the row that contain either of those values. And it all happens as you type. I was blown away by this feature. So here's how you can construct queries and apply filter:

// Read the text field, construct and return a regular expression:


private static final String COMMA = ",";

private static final String OR = "|";


private String getSearchRegularExpression(){

String filterText = filterControlsPanelHandlerObject.getFilterText();

return filterText.replace(COMMA, OR);

}

// call the filter in update methods

@Override

public void changedUpdate(DocumentEvent event) {

yourTableClassWithFilterMethod.newFilter(getSearchRegularExpression());

}

And here's how the filter method looks like:

private TableRowSorter rowSorter;

/*

* initialize rowsorter etc...

*/

protected void newFilter(String filterRegExp) {

RowFilter rowFilter = null;

//If current expression doesn't parse, don't update.

try {

rowFilter = RowFilter.regexFilter(filterRegExp);

} catch (java.util.regex.PatternSyntaxException e) {

return;

}

rowSorter.setRowFilter(rowFilter);

}



And the functionality is ready to be used!! Enjoy :)

No comments:

Post a Comment