Eine Textkomponente, die Zeilennummern darstellen kann leitet man nicht von JTextArea, sondern sinnvollerweise von JScrollPane ab. Sie besitzt die Methode
setRowHeaderView(), der als Parameter eine Komponente zur Darstellung der Zeilennummern übergeben wird und die am linken Bildrand einen Anzeigebereich
generiert, der hinsichtlich seiner Erscheinung konventionell formatiert werden kann.
Zu Beginn definiert das Beispiel zwei Instanzvariablen:
- areaLineBreak dient der Steuerung des Zeilenumbruchs der JTextArea
- numberLineBreak dient zur Steuerung der Darstellung der Zeilennummerierung abhängig vom Zeilenumbruch des geladenen Textes. Ist dieser Wert auf
true gesetzt, so werden bei der Zeilennummerierung nur die Zeilenanfänge des geladenen Textes nummeriert. Durch die JTextArea umgebrochene Zeilen
bleiben unnummeriert.
Die Beispielklasse erweitert JScrollPane. Im Konstruktor werden zwei JTextArea initialisiert, von denen
textArea zur Darstellung des geladenen Textes
und
numberArea zur Darstellung der Zeilennummern dient. Die erste bleibt im Gegensatz zur zweiten natürlich editierbar. Ihr Zeilenumbruch wird durch
die Methoden
setLineWrap() und
setWrapStyleWord() über die o.a. Instanzvariable gesteuert. Um später die Zeilennummern aktualisieren zu
können, wird der Textbereich bei einem
ComponentListener und einem
KeyListener angemeldet.
Über die Methode
ladeDatei(), die im Beispiel eine Testdatei mittels eines
FileReader liest, wird der anzuzeigende Text in den Textbereich
geladen. Die
JTextArea wird dem
JScrollPane hinzugefügt und die Scrolleigenschaften so eingestellt, dass bei Bedarf horizontal und vertikal
gescrollt werden kann.
Die
JTextArea zur Anzeige der Zeilennummern wird ein wenig formatiert und schließlich mit Hilfe der Methode
setRowHeaderView()
dem
JScrollPane hinzugefügt.
Die Zeilenanzeige wird durch die Methode
gibNummern() gesteuert. In ihr wird abhängig von den Einstellungen der Zeilenumbrüche mittels eines
StringBuilder ein Text erzeugt, der die einzelnen Zeilennummern untereinander darstellt. Hierzu werden die Zeichenzahl und die Anzahl der Zeilen
des geladenen Textes in zwei lokalen Variablen gespeichert. Es ist wichtig zu wissen, dass hier nicht die Anzahl der in der JTextArea gezeigten Zeilen,
sondern diejenige des Originaltextes gespeichert wird. Ein z.B. 10-zeiliger Text mit langen Zeilen kann bei aktiviertem Zeilenumbruch innerhalb der
JTextArea auf 20 oder mehr Zeilen umgebrochen werden.
Zum Auslesen der verschiedenen Offsets in Bezug auf den Originaltext stellt
JTextArea die folgenden Methoden bereit:
- getLineEndOffset(int line) Offset (Zeichenzahl) des Zeilenendes der gegebenen Zeile
- getLineStartOffset(int line) Offset des Zeilenbeginns (Zeichenzahl bis zum Zeilenbeginn) der gegebenen Zeile
- getLineOfOffset(int offset) Zeilennummer der Cursorposition
Zum Bestimmen des Zeilenend-, bzw. -start-Offsets eines in einer Komponente geladenen Textes können Methoden der Klasse
Utilities
herangezogen werden.
Im Folgenden findet eine dreifache Fallunterscheidung über einfache if-else-Verzweigungen statt:
- Der Zeilenumbruch der JTextArea ist deaktiviert.
In diesem Fall sind die Zeilenzahl im Anzeigebereich und diejenige des Originaltextes identisch und es reicht aus, die Anzahl der Zeilen der
JTextArea auszulesen und die Nummern von 1 an untereinander auszugeben.
- Der Zeilenumbruch der JTextArea ist aktiviert, es sollen nur die Zeilenanfänge des Originaltextes nummeriert werden.
Hier besteht, wie bereits oben kurz angesprochen, das Problem, dass ein Auslesen der Zeilenumbrüche des geladenen Originaltextes von demjenigen
der JTextArea getrennt werden muss, da entschieden werden muss, ob er vom Originaltext oder dem Umbruch der JTextArea stammt.
Dies geschieht über das zeichenweise Durchsuchen des Textes nach dem systemweiten Zeilenumbruchszeichen
mittels eines regulären Ausdrucks. Hierzu wird so vorgegangen, dass Zeichen für Zeichen die Position des Zeichens am Ende der Zeile
innerhalb der JTextArea ermittelt wird, in der sich das untersuchte Zeichen befindet.
In dem Moment, in dem sich diese End-Position ändert, bedeutet dies, dass eine neue Zeile begonnen hat. Entspricht das an dieser Stelle gefundene Zeichen demjenigen
für einen Zeilenumbruch, so beginnt daraufhin eine neue Zeile des Originaltextes und dem Text der Zeilenanzeige wird eine neue Zahl hinzugefügt.
Im anderen Fall wird im Textbereich der Zeilennummern ein einfacher Zeilenumbruch ohne neue Ziffer erzeugt und die nächste Zeile untersucht.
- Der Zeilenumbruch der JTextArea ist aktiviert, es sollen alle in der JTextArea gezeigten Zeilen nummeriert werden.
In diesem Fall wird ebenfalls die JTextArea nach einem Zeilenumbruch durchsucht, nur dass nun in jeder dort gezeigten Zeile eine Nummer hizugefügt
und gezeigt wird