8.6.16 | JEditorPane |
Mit Hilfe des JEditorPane können Java-Programmierer formatierten Text editieren. Das JEditorPane unterstützt als Formate RTF (Rich Text Format) und HTML, wobei beides gelesen und geschrieben werden kann.
Weitere Formate können mit Hilfe weiterer Implementierungen der Klasse javax.swing.text.EditorKit hinzugefügt werden (s. registerEditorKitForContentType(String type, String className)). Das JEditorPane unterstützt unformatierten Text durch das DefaultEditorKit, HTML durch das HTMLEditorKit und RTF durch das RTFEditorKit.
Der Inhalt des JEditorPane kann durch die Methoden setText(String text) oder setURL(URL url) gesetzt werden. Wenn das Format HTML ist, wird der Text asynchron geladen, das heißt, die Seite baut sich während des Betrachtens auf, die Komponente ist dabei bedienbar.
Um das JEditorPane als Editor zu benutzen, kann man die vordefinierten Action-Exemplare mittels getEditorKit().getActions() abfragen und die benötigten beispielsweise in einer JToolBar anordnen. Das StyledEditorKit, welches auch die Grundlage des HTML- und RTFEditorKit ist, bietet hier die Möglichkeit, eigene Actions mittels der Standardimplementierung javax.swing.text.StyledEditorKit.StyledTextAction anzulegen. Diese Aktionen beziehen sich im Gegensatz zu den HTML-Aktionen (s. nächstes Unterkapitel) nicht auf das Einfügen von Konstrukten (bspw. einer Tabelle), sondern auf das Zuweisen von Attributen (Styles).
Eine Superskript-Aktion kann so folgendermaßen programmiert werden:
new StyledEditorKit.StyledTextAction("font-superscript") { public void actionPerformed(ActionEvent e) { JEditorPane editor = getEditor(e); if (editor != null) { StyledEditorKit kit = getStyledEditorKit(editor); MutableAttributeSet attr = kit.getInputAttributes(); boolean superscript = (StyleConstants.isSuperscript(attr)) ? false : true; SimpleAttributeSet sas = new SimpleAttributeSet(); StyleConstants.setSuperscript(sas, superscript); setCharacterAttributes(editor, sas, false); } } };
Wie man in dem Beispiel sieht, wird lediglich das Style-Attribut superscript bei dem ausgewählten Textblock gesetzt.
Die Klasse javax.swing.text.StyleConstants dient diesem Zweck. Sie setzt bei einem übergebenen AttributeSet den entsprechenden Style (hier setSuperscript(MutableAttributeSet attributeSet, boolean flag)). Über die geerbte Methode kann die StyledTextAction dann diese Attribute dem selektierten Text übergeben (setCharacterAttributes(JEditorPane editorPane, AttributeSet attr, boolean replace)). Da wir hier bereits vorher gemachte Formatierungen nicht überschreiben wollen, wird der Wert für replace auf false gesetzt. Ansonsten würde der Text vor dem Hochstellen von sämtlichen Style-Informationen bereinigt werden.
Der Text wird in der Klasse javax.swing.text.html.HTMLDocument gespeichert. In dem HTML-Dokument ist zusätzlich ein Exemplar von javax.swing.text.html.StyleSheet assoziiert (s. Cascading Style Sheets (CSS) Level 1: http://www.w3.org/Style/CSS/). Die derzeitige CSS-Implementierung ist jedoch noch nicht vollständig. Die unterstüzten Attribute sind in der API-Dokumentation des J2SDK aufgelistet.
Das HTMLEditorKit bietet die Möglichkeit, die HTML-Implementierung zu erweitern. Möchte man beispielsweise ein eigenes Tag hinzufügen, muss man in einer Ableitung die Methode getViewFactory() überschreiben, die danach eine eigene Implementierung der HTMLEditorKit.HTMLFactory zurückliefert. Die HTMLFactory liefert zu jedem Tag eine grafische Repräsentation, die so genannte javax.swing.text.View. Um also ein eigenes Tag grafisch darzustellen, muss eine passende View geschrieben werden. Neben den Attributen, die einem Tag zugeordnet sein können, kann die View die CSS-Einstellungen aus dem Stylesheet lesen und darauf reagieren.
Wer eigene TextActions schreiben möchte, kann dazu die Klasse HTMLEditorKit.InsertHTMLTextAction benutzen. Es existieren dabei zwei Konstruktoren:
- HTMLEditorKit.InsertHTMLTextAction(String name, String html, HTML.Tag parentTag, HTML.Tag addTag)
Mit diesem Konstruktor wird neben dem Namen und dem einzufügenden HTML der Vaterknoten (für eine Tabelle beispielsweise HTML.Tag.BODY und das einzufügende Tag (für eine Tabelle HTML.Tag.TABLE) eingegeben. Das einzufügende Tag bezeichnet das erste Tag in dem HTML-String, welches eingefügt werden soll - alles was davor steht, wird beim Einsetzen ignoriert. Wird an der Einfügeposition das Parent-Tag nicht gefunden, versucht der Editor, in der Elementhierarchie weiter nach oben zu gehen, bis das Parent-Tag gefunden wurde, und setzt das HTML dort ein. Wird das Parent-Tag nicht gefunden, wird nichts eingefügt.- HTMLEditorKit.InsertHTMLTextAction(String name, String html, HTML.Tag parentTag, HTML.Tag addTag, HTML.Tag alternateParentTag, HTML.Tag alternateAddTag)
Der zweite Konstruktor besitzt die Möglichkeit, eine Alternative für das Start-Tag und das Parent-Tag zu definieren. Dies ist beispielsweise bei einem neuen Listitem (LI) der Fall. In HTML kann dieses COD>Listitem in einer Unordered List (UL) stehen. Soll also ein Listitem mitten in dem Parent-Tag HTML.Tag.BODY eingesetzt werden, so muss zusätzlich darum ein <ul></ul> eingefügt werden. Wenn hingegegen das Parent-Tag bereits eine Unordered List ist, muss nur das Listitem eingefügt werden. Der Aufruf des Konstruktors wäre damit folgender:new HTMLEditorKit.InsertHTMLTextAction("LI", "<ul><li></li></ul>", HTML.Tag.UL, HTML.Tag.LI, HTML.Tag.BODY, HTML.Tag.UL);
Eine Besonderheit bei HTML sind die Links (Anker: <a href="http://www.sun.com">Link</a>). Um den Mauszeiger beim Überfahren eines Links zu verändern und bei einem Klick im nicht editierbaren Modus die URL anzuzeigen, kann folgender Code benutzt werden:
editorPane.addHyperlinkListener ( new HyperlinkListener () { public void hyperlinkUpdate(HyperlinkEvent e) { // Das Ändern des Mauszeigers geht ab // Java 1.3 auch automatisch if (e.getEventType() == HyperlinkEvent.EventType.ENTERED) { ((JEditorPane) e.getSource()).setCursor( Cursor.getPredefinedCursor( Cursor.HAND_CURSOR)); } else if (e.getEventType() == HyperlinkEvent.EventType.EXITED) { ((JEditorPane) e.getSource()).setCursor( Cursor.getPredefinedCursor( Cursor.DEFAULT_CURSOR)); } else // Hier wird auf ein Klick reagiert if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { JEditorPane pane = (JEditorPane) e.getSource(); if (e instanceof HTMLFrameHyperlinkEvent) { HTMLFrameHyperlinkEvent evt = (HTMLFrameHyperlinkEvent)e; HTMLDocument doc = (HTMLDocument)pane.getDocument(); doc.processHTMLFrameHyperlinkEvent(evt); } else try { // Normaler Link pane.setPage(e.getURL()); } catch (Throwable t) { t.printStackTrace(); } } } });
Hierbei wird zwischen einem Klick innerhalb von HTML-Frames und einem normalen HTML-Dokument unterschieden. Bei einem Klick innerhalb eines Frames muss das Ziel (also in welchem Frame das neue Dokument geladen werden soll) bestimmt werden. Diese Aufgabe übernimmt die Methode processHTMLFrameHyperlinkEvent(HTMLFrameHyperlinkEvent e).
Material zum Beispiel
Ein interessantes Beispiel für die Verwendung von HTML innerhalb einer Applikation ist die Oberflächengestaltung. So kann man in HTML rudimentäre, aber sehr flexible Eingabemasken erstellen, die man dann in Swing abfragen kann. Der Vorteil liegt dabei in einer einfachen Wartbarkeit, dem HTML-Standard und der schnelleren Entwicklung, da keine komplexen Layout-Manager benötigt werden.
- Applet starten
- Quelltexte:
Voraussetzung für die Verwendung einer Eingabeoberfläche in HTML ist ein HTML-Formular, etwa <form method="get" action="test.jsp">, in das dann Textfelder, Auswahlfelder, Checkboxen und Radioboxen integriert werden. Drückt der Benutzer zum Abschluss einen Submit-Button (<input type="submit">) oder eine entsprechende Grafik (<input type="image" src="submit.gif">), so wird typischerweise der Inhalt des Formulars an die im Form-Tag angegebene Seite übermittelt.
Der folgende Code ermöglicht, in den Transfermechanismus der HTML-Form einzugreifen, um die eingegebenen Werte abzufangen (in diesem Beispiel werden die übermittelten Werte zur Einfachheit mittels System.out.println(String text) ausgegeben). Dazu wird das HTMLEditorKit erweitert, so dass eine eigene FormView aufgerufen wird, die im Gegensatz zum Original keine neue Seite lädt. Es ist einfach, an der Stelle mit dem System.out.println(String text) die eigene Methode einzubauen, die dann die Eingaben enthält:editorPane.setEditorKit (new HTMLEditorKit() { public ViewFactory getViewFactory() { return new HTMLEditorKit.HTMLFactory() { public View create(Element elem) { Object o = elem.getAttributes().getAttribute( StyleConstants.NameAttribute); if (o instanceof HTML.Tag) { HTML.Tag kind = (HTML.Tag) o; if (kind == HTML.Tag.INPUT) return new FormView(elem) { protected void submitData (String data) { System.out.println ("Data: "+data); } protected void imageSubmit(String data) { System.out.println ("Data: "+data); } }; } return super.create (elem); } }; } });Als Beispiel dient folgender HTML-Code zur Eingabe<form> Vorname: <input name="Vorname" type="text" value="James T."> Nachname: <input name="Nachname" type="text" value="Kirk"> Dienstrgrad: <select name="Dienstgrad"> <option>Captain</select> <input type="submit"> </form>Drückt der Benutzer dann auf den Submit-Button, wird die submitData(String data)-Methode aufgerufen.
Der Parameter data besteht dabei aus mehreren Name-Wert-Paaren, getrennt durch ein kaufmännisches Und. Die Werte sind URL-encoded und müssen mit Hilfe der Methode decode(String text) von java.net.URLDecoder zurückgewandelt werden. Im obigen Beispiel wäre der data-Parameter dementsprechend: Vorname=James+T.&Nachname=Kirk&Rang=Captain.
StringTokenizer st = new StringTokenizer(data, "&"); while (st.hasMoreTokens()) { String token = st.nextToken(); String key = URLDecoder.decode( token.substring(0, token.indexOf("="))); String value = URLDecoder.decode( token.substring(token.indexOf("=")+1, token.length())); }
Material zum Beispiel
- Applet starten
- Quelltexte:
Das JEditorPane kann als ein rudimentärer HTML-Editor genutzt werden, wenn man die Methode setEditable(true) aufruft. Für einen kommerziellen Einsatz ist er jedoch eher nicht zu gebrauchen, wie auch die HTML-Anzeigekomponenten nicht an professionelle Browser heranreichen.