Erstellen Sie clientseitige Benutzeroberflächen in HTML, Teil 1

Diesen Monat werde ich für eine Weile wieder programmieren. Ich brauche eine Pause von der Verrücktheit in der Talkback-Diskussion in der Kolumne des letzten Monats. Ich beabsichtige jedoch, in Zukunft mehr über theoretische Fragen zu schreiben, jedoch nicht für die nächsten paar Monate.

Ich muss eine Klarstellung aus der Kolumne des letzten Monats machen. Viele Leute interpretierten meine Kommentare zu Benutzeroberflächen als Befürworter schwerer Objekte mit Milliarden von Rendering-Methoden. Das hatte ich nicht im Sinn. Es gibt zahlreiche praktikable Möglichkeiten, Benutzeroberflächen (UIs) zu erstellen, ohne Implementierungsdetails offenzulegen. Die Muster der vierköpfigen Erbauer und Besucher fallen mir sofort ein. Eine einfache drawYourself()Methode kann offensichtlich nur mit den einfachsten Objekten arbeiten, und 50 drawYourselfInThisFormat()und drawYourselfInThatFormat()Methoden sind ein unsinniges Rezept für nicht verwaltbaren Code. Viele Leute denken jedoch, dass ich diesen Ansatz befürworte, deshalb entschuldige ich mich, wenn ich diesen Eindruck erweckte.

Da ich viele Missverständnisse in Bezug auf das UI-Problem gesehen habe, werde ich Ihnen in zukünftigen Spalten einige Implementierungen objektorientierter (OO) UI-Building-Ansätze zeigen. Ich habe vor einigen Jahren eine solche Lösung in JavaWorld vorgestellt (siehe Ressourcen), aber in den vergangenen Jahren habe ich bessere Systeme gebaut. In dieser aktuellen Spalte wird ein Teil eines dieser UI-Systeme vorgestellt: eine Infrastrukturklasse, mit der ich clientseitige UIs auf OO-Weise erstellt habe. Es ist an und für sich keine Lösung für das UI-Problem, aber es ist ein nützlicher Baustein.

Da die Codebeispiele ziemlich groß sind, werde ich die Präsentation in zwei Teile aufteilen. Dieser Monat ist Dokumentation und Anwendungscode; nächsten Monat ist der Quellcode.

Lesen Sie die gesamte Reihe "Erstellen clientseitiger Benutzeroberflächen in HTML":

  • Teil 1: Machen Sie das JEditorPane nützlich (Oktober 2003)
  • Teil 2: Die HTMLPane-Quellen (November 2003)

Verwenden von HTML auf der Clientseite

HTML ist eine wunderbare Sache. Sie können damit mit minimalem Aufwand komplizierte Benutzeroberflächen erstellen. Es trennt die Struktur und das Layout der Benutzeroberfläche hervorragend von der Geschäftslogik. es ist leicht zu schreiben; und es ist leicht zu pflegen. Das Abstract Window Toolkit (AWT) / Swing-Layout ist dagegen ärgerlich schwierig zu verwenden. Sie müssen den Code ändern (und neu kompilieren), um das Aussehen Ihrer Bildschirme zu ändern. Der Code für ein triviales Layout ist selbst nicht trivial und erstreckt sich auf viele Seiten. Wäre es nicht schön, wenn Sie Ihre gesamte clientseitige Benutzeroberfläche in HTML angeben könnten?

(Ich weiß, dass einige von Ihnen die vorhergehende Frage mit einem mitreißenden "Nein, es wäre nicht schön!" Beantworten werden. Viele argumentieren, dass HTML und eine gute Benutzererfahrung sich gegenseitig ausschließen, da HTML Ihre Benutzeroberfläche in eine "unendliche Kaskadierung" zwingt Dialogfeld "Modus". Andererseits können viele Anwendungen HTML in zumindest einem Teil der Benutzeroberfläche effektiv nutzen - für tabellarische Berichte, wenn nichts anderes. Sie können das Baby nicht mit dem Badewasser wegwerfen.)

Swings JEditorPaneKlasse scheint zunächst eine Antwort auf das HTML-Layout-Problem zu sein. Es versteht HTML-Eingabe auf eine Art und Weise. Der folgende Code öffnet beispielsweise einen Frame, in dem einfacher HTML-Text angezeigt wird:

JFrame main_frame = neuer JFrame (); JEditorPane-Bereich = neuer JEditorPane (); pane.setContentType ("text / html"); pane.setEditable (false); pane.setText ("" + "" + "" + "" + " Hallo Welt " + "" + ""); main_frame.setContentPane (Bereich); main_frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); main_frame.pack (); main_frame.show ();

Ich sage "nach einer Mode", weil JEditorPanees nicht besonders gut ist, mit komplexem HTML umzugehen. Mit verschachtelten Tabellen macht es keine gute Arbeit, und es macht Cascading Style Sheets (CSS) nicht sehr gut. (Mir wurde gesagt, dass viele dieser Probleme in der Java 1.5-Version im nächsten Jahr behoben werden, aber vorerst müssen wir uns alle damit abfinden.) Schließlich JEditorPanemacht das Verlegen nicht besonders gut Dinge wie Optionsfelder. Sie sind nicht richtig an der Textgrundlinie ausgerichtet und zeigen immer einen grauen Hintergrund an. Daher funktionieren sie nicht gut, wenn Sie die Hintergrundfarbe der Seite ändern ( z. B. mit einem Stil auf dem Tag).

All diese Fehler sind ärgerlich, aber das Problem mit dem Show-Stopper JEditorPaneist, dass es als Textsteuerung und nicht als Layout-Funktion funktioniert. Sie können beispielsweise einen HTML-Code in der Eingabe angeben , das Formular wird jedoch an einen Webserver gesendet, wenn Sie auf die Schaltfläche Senden klicken. Um eine clientseitige Benutzeroberfläche anzugeben, möchten Sie, dass die Formulardaten zu dem Programm zurückkehren, das das Formular angezeigt hat, und nicht zu einem Remoteserver. Sie benötigen auch eine bequeme Möglichkeit, benutzerdefinierte Tags für nicht standardmäßige Eingabe- oder Anzeigezwecke hinzuzufügen oder Platzhalter für Standard-Swing bereitzustellen, die JComponentsSie für das Formular verwenden möchten. ( JEditorPaneSie können dies tun, aber der Mechanismus ist alles andere als praktisch.) Schließlich müssen Sie Dinge wie eine Schaltfläche Abbrechen handhaben, die in HTML nicht vorhanden ist.

Glücklicherweise kann das ungeheuerlichste der oben genannten Probleme mit in sich integrierten Anpassungsfunktionen gelöst werden JEditorPane. Die Behebung dieser Probleme ist jedoch mit einem gewissen Kompromiss verbunden. Sie könnten beispielsweise das Problem mit der Schaltfläche "Abbrechen" lösen, indem Sie einen JavaScript-Interpreter implementieren und das onclickAttribut unterstützen, aber das ist eine Menge Arbeit. In ähnlicher Weise ist es mit dem vorhandenen Parser sehr schwierig, eine echte Unterstützung für benutzerdefinierte Tags bereitzustellen (bei der Sie alles verarbeiten können, was zwischen einem Start- und einem End-Tag liegt). Sie könnten die ersetzenJEditorPaneEs ist ein Parser mit einem besseren, aber das ist auch eine Menge Arbeit. Ich entschied mich für einfachere Lösungen, die den Job erledigten. Ich habe meiner Klasse genügend Funktionen hinzugefügt, um damit eine Benutzeroberfläche für das Programm zu erstellen, das ich geschrieben habe, aber keine "perfekte" Lösung bereitgestellt. Das Problem, das ich löste, war: Geben Sie eine Möglichkeit an, eine Benutzeroberfläche in HTML anzugeben. Ich habe das Problem nicht gelöst: Geben Sie eine Möglichkeit an, alle möglichen HTML-Code in einer clientseitigen Anwendung anzuzeigen. Die HTMLPaneKlasse, die ich in diesem Artikel vorstelle, löst das Problem der Angabe einer Benutzeroberfläche in HTML auf gute Weise.

Verwenden des HTMLPane

Meine clientseitige HTML-Eingabeklasse HTMLPaneist eine JEditorPaneAbleitung, die die zuvor beschriebenen Probleme behebt. Listing 1 zeigt die Verwendung eines HTMLPane. Ich habe eine einfache JDialogAbleitung namens erstellt, HtmlDialogin der Sie das Dialogfeldlayout als HTML angeben können. Das HtmlDialogist ein triviales Beispiel der Fassade Entwurfsmusters. Es erledigt nur die rote Arbeit, die notwendig ist, um ein HTMLPanein ein Dialogfeld einzufügen und es anzuzeigen.

Die HtmlDialog.TestKlasse (Listing 1, Zeile 134) bietet ein einfaches Beispiel für die Verwendung von HtmlDialog. Es wird ein größtenteils leerer Hauptrahmen erstellt ( owner). Mit Code wie dem unten wiedergegebenen Snippet main()wird ein HtmlDialogObjekt erstellt, dessen Inhalt in der CLASSPATH-relativen Datei angegeben ist com/holub/ui/HTML/test/okay.html(Listing 2). Die Zeichenfolge wird "Test HtmlDialog"in der Titelleiste angezeigt. Zum Schluss wird main()der Dialog durch Aufrufen geöffnet d.popup(), der erst zurückkehrt, wenn der Benutzer den Dialog beendet:

// Zeigen Sie die Datei okay.html in einem Dialogfeld mit dem // Titel "Test HtmlDialog" an. // HtmlDialog dialog = neuer HtmlDialog (owning_frame, "com / holub / ui / HTML / test / okay.html", "Test HtmlDialog"); // Öffne den Dialog und warte, bis der Benutzer ihn geschlossen hat. // dialog.popup (); // Drucke die "Formular" -Daten, die der Benutzer eingegeben hat. // System.out.println ("hidden =" + dialog.data (). GetProperty ("hidden") + "Benutzereingabe" + dialog.data (). GetProperty ("Benutzereingabe"));

Formulardaten (der Text, den der Benutzer in ein Element oder ein gleichwertiges Element eingegeben hat ) sind über die Methode HtmlDialog' verfügbar data(), die ein java.util.PropertiesObjekt zurückgibt, das Schlüssel / Wert-Paare enthält, die die Formulardaten darstellen. Der obige Aufruf zum dialog.data().getProperty("hidden")Zurückgeben der Zeichenfolge "hidden-field data". Der dialog.data().getProperty("user-input")Aufruf gibt alles zurück, was der Benutzer in das Eingabefeld eingegeben hat.

Der größte Teil der Arbeit zum Instanziieren der Kapselung findet HTMLPaneim HtmlDialogKonstruktor statt (Listing 1, Zeile 46). Der Konstruktor richtet zunächst eine ein ActionListener, die die Schaltfläche Senden im Formular behandelt. Dieser Observer schließt das aktuelle Dialogfeld und kopiert alle Formulardaten aus der HTMLPanein die dataInstanzvariable. Der Konstruktor ruft dann die Eingabedatei vom CLASSPATH ab und lädt dann den HTML-Code in das HTMLPaneusing setText(). (Es gibt auch eine setPage(URL)Methode, aber Sie würden eine URL für den absoluten Pfad zur Datei benötigen, wenn Sie sie verwenden würden. Ich wollte, dass der HTML-Dateiname CLASSPATH-relativ ist.)

Die Abbruchverarbeitung wird in popup()(Zeile 121) behandelt, wobei davon ausgegangen wird, dass eine Abbrechen-Schaltfläche gedrückt wurde, wenn in den übermittelten Formulardaten eine Abbrechen-Taste vorhanden ist. (Mehr darüber, wie diese Daten Propertiesin einem Moment in das Objekt gelangen.)