Search code examples
javaswingjtablejtextareaswing-highlighter

Refresh/Update highlighter in JTable when changing search values


how can I refresh the highlighter in my JTable after changing the search value in the JTextField? It works fine with the JTextArea under the JTextfield, but I the JTable won't refresh the highlighter. Any Suggestions??

This is my Code:

import java.awt.*;
import java.awt.event.*;

import javax.swing.*;
import javax.swing.table.*;
import javax.swing.text.*;
import javax.swing.text.DefaultHighlighter.DefaultHighlightPainter;

public class BeispielTabelle {
JTextField field;
JTextArea textFeld = new JTextArea("Hello World!");
String input="Stefan";

//Titel der Tabelle
String[] title = {"EINS", "ZWEI", "DREI"}; 

//Tabellendaten
Object[][] playerdata = {       
{"34", "Stefan", "Mein Name ist Stefan"},
{"32", "Dirk", "Ich bin der Dirk"},
{"99", "Patrick", "Ich heisse Patrick"},
{"100", "Anna", "Ich bin die Anna"},};

//TableModel
DefaultTableModel model = new DefaultTableModel(playerdata,title);

//Tabelle erstellen
JTable textTable = new JTable(model);    

public JPanel erstelleTabelle() {               
    JPanel totalGUI = new JPanel();    
    //CellRenderer
    SearchRenderer cellRenderer = new SearchRenderer();


    //Spaltenbreiten festlegen
    textTable.setDefaultRenderer(String.class, cellRenderer);
    textTable.getColumnModel().getColumn(0).setCellRenderer(cellRenderer);
    textTable.getColumnModel().getColumn(1).setCellRenderer(cellRenderer);    
    textTable.getColumnModel().getColumn(2).setCellRenderer(cellRenderer);

    textTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); // Autoresizing abschalten, sonst sind alle Spalten gleich breit:
    textTable.getColumnModel().getColumn(0).setPreferredWidth(60);
    textTable.getColumnModel().getColumn(1).setPreferredWidth(60);
    textTable.getColumnModel().getColumn(2).setPreferredWidth(180);       

    //das Ganze scrollbar machen
    JScrollPane scrollPane = new JScrollPane(textTable);

    //TextFeld erstellen
    field = new JTextField();
    field.addActionListener(new ActionListener () {
        @Override
        public void actionPerformed(ActionEvent e) {
            input = field.getText();
            System.out.println(input);
            //updateRowHeights();
            highlightText();
        }
    });        

    totalGUI.add(scrollPane);  
    totalGUI.add(field);
    totalGUI.add(textFeld);        
    return totalGUI;
}

void highlightText() {
    DefaultHighlightPainter yellowPainter = new DefaultHighlighter.DefaultHighlightPainter(Color.YELLOW);
    Highlighter highlighter = textFeld.getHighlighter();
    highlighter.removeAllHighlights();      
    String text = textFeld.getText();
    String pattern = input;
    int index = text.indexOf(pattern);      
    while ( index >= 0 ) {
        int len = pattern.length();
        try {
            highlighter.addHighlight(index, index+len, yellowPainter);
        } catch (BadLocationException e) {
            e.printStackTrace();
        }
        index = text.indexOf(pattern, index+len);
    }
}

private static void createAndShowGUI() {

    //create main frame
    JFrame mainFrame = new JFrame("");
    BeispielTabelle test = new BeispielTabelle();

    JPanel totalGUI = new JPanel();
    totalGUI = test.erstelleTabelle();
    totalGUI.setLayout(new BoxLayout(totalGUI, BoxLayout.Y_AXIS));

    //visible mode
    mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    mainFrame.add(totalGUI); //integrate main panel to main frame
    mainFrame.pack();
    mainFrame.setVisible(true);     
}


public static void main (String[] args) {               

    createAndShowGUI();     

}//main
}//GUI_main

And this is my SearchRenderer

import javax.swing.*;
import javax.swing.table.*;
import javax.swing.text.BadLocationException;

import java.awt.*;

public class SearchRenderer extends JTextArea implements TableCellRenderer {

/**
 * 
 */
private static final long serialVersionUID = 1L;
public SearchRenderer() {}//constructor
BeispielTabelle tabelle = new BeispielTabelle();
String textForSearch=tabelle.input;

@Override
public Component getTableCellRendererComponent (JTable table,
                                                Object value,
                                                boolean isSelected,
                                                boolean hasFocus,
                                                int row,                    
                                                int column ) {  
    this.setText((String) value);
    if(value != null) {
        String string = value.toString();
        if(string.contains(textForSearch)){
            int indexOf = string.indexOf(textForSearch);
            while(indexOf >=0) {
            try {
                      this.getHighlighter().addHighlight(indexOf,indexOf+textForSearch.length(),new javax.swing.text.DefaultHighlighter.DefaultHighlightPainter(Color.GREEN));
            } catch (BadLocationException e) {
                e.printStackTrace();
            }
            indexOf = string.indexOf(textForSearch, indexOf+textForSearch.length());
        }
    }
    } else {
        this.setText("");
        this.getHighlighter().removeAllHighlights();
    }
    return this;
}
}

Solution

  • Maybe you can use JTable#repaint()

    enter image description here

    import java.awt.*;
    import java.util.Objects;
    import java.util.regex.*;
    import javax.swing.*;
    import javax.swing.event.*;
    import javax.swing.table.*;
    import javax.swing.text.*;
    
    public final class SearchRendererTest {
      private final JTextField field = new JTextField("Stefan");
      private final SearchRenderer renderer = new SearchRenderer();
    
      //Titel der Tabelle
      private final String[] title = {"EINS", "ZWEI", "DREI"};
    
      //Tabellendaten
      private final Object[][] playerdata = {
        {"34", "Stefan", "Mein Name ist Stefan"},
        {"32", "Dirk", "Ich bin der Dirk"},
        {"99", "Patrick", "Ich heisse Patrick"},
        {"100", "Anna", "Ich bin die Anna"},
      };
      private final TableModel model = new DefaultTableModel(playerdata, title);
      private final JTable table = new JTable(model);
    
      public JComponent makeUI() {
        table.setDefaultRenderer(Object.class, renderer);
        field.getDocument().addDocumentListener(new DocumentListener() {
          @Override public void insertUpdate(DocumentEvent e) {
            fireDocumentChangeEvent();
          }
          @Override public void removeUpdate(DocumentEvent e) {
            fireDocumentChangeEvent();
          }
          @Override public void changedUpdate(DocumentEvent e) {
            /* not needed */
          }
        });
        fireDocumentChangeEvent();
    
        JPanel sp = new JPanel(new BorderLayout(5, 5));
        sp.add(new JLabel("regex pattern:"), BorderLayout.WEST);
        sp.add(field);
        sp.add(Box.createVerticalStrut(2), BorderLayout.SOUTH);
        sp.setBorder(BorderFactory.createTitledBorder("Search"));
    
        JPanel p = new JPanel(new BorderLayout(5, 5));
        p.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        p.add(sp, BorderLayout.NORTH);
        p.add(new JScrollPane(table));
        return p;
      }
    
      private void fireDocumentChangeEvent() {
        String pattern = field.getText().trim();
        renderer.setPattern(pattern);
        table.repaint();
      }
    
      public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
          @Override public void run() {
            createAndShowGUI();
          }
        });
      }
    
      public static void createAndShowGUI() {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        f.getContentPane().add(new SearchRendererTest().makeUI());
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
      }
    }
    
    class SearchRenderer implements TableCellRenderer {
      private static final Color BACKGROUND_SELECTION_COLOR = new Color(220, 240, 255);
      private final transient Highlighter.HighlightPainter highlightPainter
        = new DefaultHighlighter.DefaultHighlightPainter(Color.YELLOW);
      private final JTextField field = new JTextField();
      private String pattern = "";
      private String prev;
    
      public boolean setPattern(String str) {
        if (str == null || str.equals(pattern)) {
          return false;
        } else {
          prev = pattern;
          pattern = str;
          return true;
        }
      }
      public SearchRenderer() {
        super();
        field.setOpaque(true);
        field.setBorder(BorderFactory.createEmptyBorder());
        field.setForeground(Color.BLACK);
        field.setBackground(Color.WHITE);
        field.setEditable(false);
      }
      @Override public Component getTableCellRendererComponent(
        JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        String txt = Objects.toString(value, "");
        Highlighter highlighter = field.getHighlighter();
        highlighter.removeAllHighlights();
        field.setText(txt);
        field.setBackground(isSelected ? BACKGROUND_SELECTION_COLOR : Color.WHITE);
        if (pattern != null && !pattern.isEmpty() && !pattern.equals(prev)) {
          Matcher matcher = Pattern.compile(pattern).matcher(txt);
          if (matcher.find()) {
            int start = matcher.start();
            int end   = matcher.end();
            try {
              highlighter.addHighlight(start, end, highlightPainter);
            } catch (BadLocationException e) {
              e.printStackTrace();
            }
          }
        }
        return field;
      }
    }