Close

Java Swing - Filtering and Highlighting rows in JTable

[Updated: Nov 6, 2018, Created: Aug 21, 2017]

This example is an enhancement of the last example. We will show how to highlight matching text in the filtered rows of a JTable. This filter will be applied via RowFilter (as we saw in the last example). We will extend the JLabel which will override its paintComponent() method to fill 2d rectangles at the matched text locations. We will also create a custom TableCellRenderer which will use our extended JLabel.

Extending JLabel

public class LabelHighlighted extends JLabel {
    private List<Rectangle2D> rectangles = new ArrayList<>();
    private Color colorHighlight = Color.YELLOW;

    public void reset() {
        rectangles.clear();
        repaint();
    }

    public void highlightText(String textToHighlight) {
        if (textToHighlight == null) {
            return;
        }
        reset();

        final String textToMatch = textToHighlight.toLowerCase().trim();
        if (textToMatch.length() == 0) {
            return;
        }
        textToHighlight = textToHighlight.trim();

        final String labelText = getText().toLowerCase();
        if (labelText.contains(textToMatch)) {
            FontMetrics fm = getFontMetrics(getFont());
            float w = -1;
            final float h = fm.getHeight() - 1;
            int i = 0;
            while (true) {
                i = labelText.indexOf(textToMatch, i);
                if (i == -1) {
                    break;
                }
                if (w == -1) {
                    String matchingText = getText().substring(i,
                            i + textToHighlight.length());
                    w = fm.stringWidth(matchingText);
                }
                String preText = getText().substring(0, i);
                float x = fm.stringWidth(preText);
                rectangles.add(new Rectangle2D.Float(x, 1, w, h));
                i = i + textToMatch.length();
            }
            repaint();
        }
    }

    @Override
    protected void paintComponent(Graphics g) {
        g.setColor(getBackground());
        g.fillRect(0, 0, getWidth(),getHeight());
        if (rectangles.size() > 0) {
            Graphics2D g2d = (Graphics2D) g;
            Color c = g2d.getColor();
            for (Rectangle2D rectangle : rectangles) {
                g2d.setColor(colorHighlight);
                g2d.fill(rectangle);
                g2d.setColor(Color.LIGHT_GRAY);
                g2d.draw(rectangle);
            }
            g2d.setColor(c);
        }
        super.paintComponent(g);

    }
}

The TableCellRenderer

public class RendererHighlighted extends DefaultTableCellRenderer {
    private JTextField searchField;

    public RendererHighlighted(JTextField searchField) {
        this.searchField = searchField;
    }

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value,
                                                   boolean selected, boolean hasFocus,
                                                   int row, int column) {
        Component c = super.getTableCellRendererComponent(table, value,
                selected, hasFocus, row, column);
        JLabel original = (JLabel) c;
        LabelHighlighted label = new LabelHighlighted();
        label.setFont(original.getFont());
        label.setText(original.getText());
        label.setBackground(original.getBackground());
        label.setForeground(original.getForeground());
        label.setHorizontalTextPosition(original.getHorizontalTextPosition());
        label.highlightText(searchField.getText());
        return label;
    }
}

Creating the RowFilter

Same as the last example:

public class RowFilterUtil {
    public static JTextField createRowFilter(JTable table) {
        RowSorter<? extends TableModel> rs = table.getRowSorter();
        if (rs == null) {
            table.setAutoCreateRowSorter(true);
            rs = table.getRowSorter();
        }

        TableRowSorter<? extends TableModel> rowSorter =
                (rs instanceof TableRowSorter) ? (TableRowSorter<? extends TableModel>) rs : null;

        if (rowSorter == null) {
            throw new RuntimeException("Cannot find appropriate rowSorter: " + rs);
        }

        final JTextField tf = new JTextField(15);
        tf.getDocument().addDocumentListener(new DocumentListener() {
            @Override
            public void insertUpdate(DocumentEvent e) {
                update(e);
            }

            @Override
            public void removeUpdate(DocumentEvent e) {
                update(e);
            }

            @Override
            public void changedUpdate(DocumentEvent e) {
                update(e);
            }

            private void update(DocumentEvent e) {
                String text = tf.getText();
                if (text.trim().length() == 0) {
                    rowSorter.setRowFilter(null);
                } else {
                    rowSorter.setRowFilter(RowFilter.regexFilter("(?i)" + text));
                }
            }
        });
        return tf;
    }
}

The main class

public class ExampleMain {
  public static void main(String[] args) {
      JFrame frame = createFrame();
      TableModel tableModel = createTableModel();
      JTable table = new JTable(tableModel);
      JTextField filterField = RowFilterUtil.createRowFilter(table);
      RendererHighlighted renderer = new RendererHighlighted(filterField);
      table.setDefaultRenderer(Object.class, renderer);
      JPanel jp = new JPanel();
      jp.add(filterField);
      frame.add(jp, BorderLayout.NORTH);

      JScrollPane pane = new JScrollPane(table);
      pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
      frame.add(pane, BorderLayout.CENTER);
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
  }

  private static TableModel createTableModel() {
      Vector<String> columns = new Vector<>(Arrays.asList("Name", "Address", "Age"));
      Vector<Vector<Object>> rows = new Vector<>();
      DataFactory dataFactory = new DataFactory();
      for (int i = 1; i <= 30; i++) {
          Vector<Object> v = new Vector<>();
          v.add(dataFactory.getName());
          v.add(dataFactory.getAddress() + ", " + dataFactory.getCity());
          v.add(dataFactory.getNumberBetween(18, 80));
          rows.add(v);
      }
      DefaultTableModel dtm = new DefaultTableModel(rows, columns);
      return dtm;
  }

  public static JFrame createFrame() {
      JFrame frame = new JFrame("JTable Row filter example");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setSize(new Dimension(600, 450));
      return frame;
  }
}

Output

Example Project

Dependencies and Technologies Used:

  • datafactory 0.8: Library to generate data for testing.
  • JDK 1.8
  • Maven 3.3.9

Swing Jtable Row Filter Highlighting Example Select All Download
  • table-row-filter-highlighting
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • LabelHighlighted.java

    See Also