Markieren von Text in Textkomponenten ('Highlighting')

Das Interface Highlighter ermöglicht zusammen mit den Methoden getHighlighter() und setHighlighter() der Klasse JTextComponent das Markieren von Textbereichen.

Zur Demonstration wird ein einfaches Fenster auf Basis eines JFrame erzeugt, das untereinander ein JTextField zur Eingabe des zu markierenden Textanteils und eine JTextArea mit dem Haupttext enthält. Das GUI wird in der Methode initGUI() erzeugt.
Der vollständige, kopierfähige Quelltext des Beispiels ist unten notiert.

private void initGUI() {
    area = new JTextArea(TEXT, 10, 20);
    area.setLineWrap(true);
    area.setWrapStyleWord(true);
    JScrollPane scrollPane = new JScrollPane(area);
    field = new JTextField();
    field.addKeyListener(new KeyAdapter() {
        public void keyReleased(KeyEvent e) {
            search();
        }
    });
    JFrame frame = new JFrame();
    frame.add(field, BorderLayout.PAGE_START);
    frame.add(scrollPane, BorderLayout.CENTER);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setTitle("Highlighter-Beispiel");
    frame.pack();
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
}

Auf die Eingabe eines Textes im Suchfeld reagiert ein KeyListener [7], der nach Eingabe jedes Zeichens die Methode search() aufruft [9]. Sie startet die Suche des im Suchfeld eingegebenen Textes in der Textarea.

private void search() {
    area.getHighlighter().removeAllHighlights();
    if (field.getText() == null) {
        return;
    }
    highlightString(Color.YELLOW, field.getText());
    scrollToHighlight();
}

in search() wird zu Beginn durch die Methode getHighlighter() der Highlighter der JTextArea ermittelt. Er besitzt wiederum eine Methode removeAllHighlights(), die dafür sorgt, dass alle eventuell vorhandenen Markierungen des Textbereiches gelöscht werden [2]. Nach einer Abfrage, die sicherstellt, dass Text im Suchfeld vorhanden ist [3], wird zuächst die Methode highlightString aufgerufen, die das eigentliche Markieren vornimmt. Der Aufruf von scrollToHighlight() sorgt dann dafür, dass die Textarea zur ersten Markierung gescrollt wird.

Highlighter ist ein Interface im Package javax.swing.text, das zwei innere statische Interfaces kapselt. Highlighter.HighlightPainter und Highlighter.Highlight. Die Schnittstelle Highlighter selbst deklariert Methoden, die für das Hinzufügen, die Entfernung und den Zugriff auf Markierungen zuständig sind. Das innere Interface Highlighter.HighlightPainter ermöglicht das Zeichnen einer Markierung. Für beides bietet Java einfache Implementierungen in Form der Klassen DefaultHighlighter und DefaultHighlighter.DefaultHighlightPainter an.

private String highlightString(Color color, String target) {
    String text = null;
    try {
        Highlighter highlighter = area.getHighlighter();
        text = area.getText();
        int pos = 0;
        Highlighter.HighlightPainter hp = new DefaultHighlighter.DefaultHighlightPainter(color);
        if (target.length() > 0) {
            while ((pos = text.indexOf(target, pos)) >= 0) {
                highlighter.addHighlight(pos, pos + target.length(), hp);
                pos += target.length();
            }
        }
    } catch (BadLocationException e) {
    }
    return text;
}

Die Methode highlightString() führt die eigentliche Markierung durch. Ihr werden zwei Argumente übergeben: die Markierungsfarbe und der zu markierende String.
Innerhalb eines try-catch-Blocks werden zunächst der Highlighter der Textarea und deren Text ermittelt. Ein HighlightPainter wird mit Übergabe der Markierungsfarbe gebildet. Innerhalb einer Schleife werden dann der Areatext durchlaufen und die Position(en) des gesuchten Strings ermittelt. Die Methode addHighlight() des Highlighter fügt die Markierung dem Text hinzu. Hierzu werden ihr die Anfangsposition des gesuchten Strings, dessen Länge und der mit der Markierungsfarbe gebildete HighlightPainter als Parameter übergeben.

private void scrollToHighlight() {
    Rectangle rect = null;
    try {
        rect = area.modelToView(area.getText().indexOf(field.getText()));
    } catch (BadLocationException e1) {
    }
    if (rect != null) {
        area.scrollRectToVisible(rect);
    }
}

public static void main(String[] args) {
    SwingUtilities.invokeLater(() -> new HighlighterBsp());
}

Die Methode scrollToHighlight() bewirkt, dass der Text der Area ggfs. zur ersten Markierung gescrollt wird. Erreicht wird dies dadurch, dass ein Rechteck ermittelt wird, das am Startpunkt des ersten Vorkommens des gesuchten Textes im Areatext lokalisiert ist. Der Methode scrollRectToVisible() wird dieses Rectangle-Objekt übergeben.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Rectangle;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.Highlighter;

public class HighlighterBsp {

    private JTextArea area;
    private JTextField field;
    private static final String TEXT = "Lorem ipsum dolor sit amet, consectetur "
            + "adipisici elit, sed eiusmod tempor incidunt ut labore et dolore "
            + "magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation "
            + "ullamco laboris nisi ut aliquid ex commodi consequat. "
            + "Quis aute iure reprehenderit in voluptate velit esse cillum " + "dolore eu fugiat nulla pariatur.";

    public HighlighterBsp() {
        initGUI();
    }

    private void initGUI() {
        area = new JTextArea(TEXT, 10, 20);
        area.setLineWrap(true);
        area.setWrapStyleWord(true);
        JScrollPane scrollPane = new JScrollPane(area);
        field = new JTextField();
        field.addKeyListener(new KeyAdapter() {
            public void keyReleased(KeyEvent e) {
                search();
            }
        });
        JFrame frame = new JFrame();
        frame.add(field, BorderLayout.PAGE_START);
        frame.add(scrollPane, BorderLayout.CENTER);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setTitle("Highlighter-Beispiel");
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private void search() {
        area.getHighlighter().removeAllHighlights();
        if (field.getText() == null) {
            return;
        }
        highlightString(Color.YELLOW, field.getText());
        scrollToHighlight();
    }

    private String highlightString(Color color, String target) {
        String text = null;
        try {
            Highlighter highlighter = area.getHighlighter();
            text = area.getText();
            int pos = 0;
            Highlighter.HighlightPainter hp = new DefaultHighlighter.DefaultHighlightPainter(color);
            if (target.length() > 0) {
                while ((pos = text.indexOf(target, pos)) >= 0) {
                    highlighter.addHighlight(pos, pos + target.length(), hp);
                    pos += target.length();
                }
            }
        } catch (BadLocationException e) {
        }
        return text;
    }
    
    private void scrollToHighlight() {
        Rectangle rect = null;
        try {
            rect = area.modelToView(area.getText().indexOf(field.getText()));
        } catch (BadLocationException e1) {
        }
        if (rect != null) {
            area.scrollRectToVisible(rect);
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new HighlighterBsp());
    }
}
Das Fenster des Highlighter-Beispiels

Wenn Ihnen javabeginners.de gefällt, freue ich mich über eine Spende an diese gemeinnützigen Organisationen.