Now and again someone will ask me how you can search records in a desktop database app. Here's a reasonably simple way to do so, using mechanisms that exist in Swing and the Beans Binding library. We will create a binding between the rowSorter property of the master table in the example in my previous entries and a text field that I've just added for the search string. For this binding we will need a binding converter so that the table knows how to respond to the search string.

To follow along, you can either continue with the project created in previous entries or begin with a new NetBeans project (Java Desktop Application project template) that connects to a database.

Let's get started. First of all, we'll add a label and a text field for the search field as shown below.


Now we will add a converter class to the project.

  1. Create a new Java class in your project. Call itRowSorterToStringConverter.
  2. Replace the generated code in the new class with the following code: 
    package clientpurchaseapp;
    import javax.swing.JTable;
    import javax.swing.RowFilter;
    import javax.swing.table.TableRowSorter;
    import org.jdesktop.beansbinding.Converter;
     * Binding converter between String and regex RowFilter (encapsulated by RowSorterToStringConverter).
     *  */
    public class RowSorterToStringConverter extends Converter {
        private JTable table;
        public JTable getTable() {
            return table;
        public void setTable(JTable table) {
            this.table = table;
        public Object convertForward(Object value) {
            return value.toString();
        public Object convertReverse(Object mask) {
            TableRowSorter sorter = new TableRowSorter(table.getModel());
            // The following statement makes the filter case-sensitive. If you want 
            //filter to work in a case-insensitive way, uncomment the line below, comment 
            //the 7 code lines below
            //sorter.setRowFilter(RowFilter.regexFilter(".*" + mask + ".*"));
            //The following 7 lines create a case-insensitive filter. If you want 
            //the filter to be case-sensitive, comment them out and uncomment the 
            //line above
            String m = mask.toString();
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < m.length(); i++) {
                char c = m.charAt(i);
            sorter.setRowFilter(RowFilter.regexFilter(".*" + sb + ".*"));
            return sorter;
  3. Adjust the package statement, if necessary.
  4. Save the file and compile it. Compiling the file enables you to treat it as a bean that you can add to the form by dragging and dropping from within the IDE's GUI builder.
  5. Drag the class from the Projects window and drop it in white area surrounding the form, as shown in the screenshot below. masterdetail5-dragconverter.png 

    A node called rowSorterToStringConverter1 should appear in the Inspector window.

  6. Select the rowSorterToStringConverter1 node and set its table property tomasterTable.

We'll use this converter when we create the binding.

To create the binding:

  1. In the main form, right-click the text field and choose Bind | text.
  2. In the Bind dialog, select masterTable as the binding source and rowSorter as the expression. masterdetail5-binding-basic.png
  3. Click the Advanced tab of the dialog box.
  4. From the Converter combo box, selectrowSorterToStringConverter1. masterdetail5-binding-advanced.png
  5. Click OK to close the dialog and generate the binding code.

Now when you run the application, you should be able to type in the Search Filter field and see that the list of rows is reduced to only rows that contain text matching what you have typed.


Note: If you have been following this whole series of posts, you will need to make a few changes to get the New Record and Edit Record buttons to work correctly. The Edit Record button doesn't work correctly because the number of the record to display is determined according to the records displayed but applied to the whole list of records in the database. In other words, if you select the first record in a filtered list, the first record of the whole database appears for editing in the dialog.


The New Record button fails with an exception because the code to select the new row is determined according to number of records in the database table, not according to the number of records currently displayed in the table.

To fix the first problem, replace the line:




To fix the second problem, replace the line:

int row = list.size() - 1;


int row = masterTable.getRowCount() - 1;