Programmering

Opret brugergrænseflader på klientsiden i HTML, del 1

Denne måned går jeg tilbage til programmering et stykke tid. Jeg har brug for en hvile fra det underlige i Talkback-diskussionen i sidste måneds kolonne. Jeg har dog til hensigt at skrive mere om teorispørgsmål i fremtiden, men ikke de næste par måneder.

Jeg har brug for at gøre en afklaring fra sidste måneds kolonne. Mange mennesker fortolkede mine kommentarer om brugergrænseflader som fortaler for tunge genstande med milliarder af gengivelsesmetoder i dem. Det var ikke det, jeg havde i tankerne. Der er adskillige levedygtige måder at oprette brugergrænseflader (UI'er) uden at udsætte implementeringsoplysninger. Gang of Four Builder og Visitor mønstre kommer straks til at tænke på. En simpel tegn dig selv() Metoden kan naturligvis ikke arbejde på andet end de mest enkle objekter og have 50 tegn dig selvInThisFormat () og drawYourselfInThatFormat () metoder er en meningsløs opskrift på uhåndterbar kode. Mange mennesker tror dog, at jeg går ind for denne tilgang, så jeg undskylder, hvis jeg gav det indtryk.

Da jeg har set en masse misforståelser med hensyn til UI-problemet, planlægger jeg at vise dig et par implementeringer af objektorienterede (OO) UI-opbygningsmetoder i fremtidige kolonner. Jeg præsenterede en sådan løsning i JavaWorld for et par år siden (se Ressourcer), men jeg har bygget bedre systemer i de mellemliggende år. Denne aktuelle kolonne præsenterer et stykke af et af disse UI-systemer: en infrastrukturklasse, jeg har brugt til at opbygge UI'er på klientsiden på en OO-måde. Det er ikke i og for sig en løsning på UI-problemet, men det er en nyttig byggesten.

Da kodeprøverne er ret store, opdeler jeg præsentationen i to stykker. Denne måned er dokumentation og applikationskode; næste måned er kildekoden.

Læs hele serien "Opret klientsides brugergrænseflader i HTML":

  • Del 1: Gør JEditorPane nyttigt (oktober 2003)
  • Del 2: HTMLPane-kilderne (november 2003)

Brug af HTML på klientsiden

HTML er en vidunderlig ting. Det giver dig mulighed for at lægge komplicerede brugergrænseflader med et minimum af besvær; det gør et godt stykke arbejde med at adskille UI-struktur og layout fra forretningslogik; det er let at skrive; og det er let at vedligeholde. Abstract Window Toolkit (AWT) / Swing-layout er derimod irriterende svært at bruge. Du skal ændre (og kompilere) kode for at ændre udseendet på dine skærme, og koden til et trivielt layout er i sig selv ikke-kort og strækker sig til mange sider. Ville det ikke være rart, hvis du kunne specificere hele din brugergrænseflade på klientsiden i HTML?

(Jeg ved, at nogle af jer vil besvare det foregående spørgsmål med et spændende "Nej, det ville ikke være rart!" dialogboks "-tilstand. På den anden side kan mange applikationer udnytte HTML effektivt i mindst en del af brugergrænsefladen - til tabelrapporter, hvis intet andet. Du kan ikke smide babyen ud med badevandet.)

Gynger JEditorPane klasse synes i starten at være et svar på HTML-layoutproblemet. Det forstår HTML-input efter en mode. For eksempel popper den følgende kode en ramme, der viser nogle enkle HTML-tekster:

JFrame main_frame = ny JFrame (); JEditorPane-rude = ny JEditorPane (); pane.setContentType ("tekst / html"); pane.setEditable (false); pane.setText ("" + "" + "" + "" + "HejVerden"+" "+" "); main_frame.setContentPane (rude); main_frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); main_frame.pack (); main_frame.show (); 

Jeg siger "efter en mode" fordi JEditorPane er ikke særlig god til at håndtere kompleks HTML. Det gør ikke et godt stykke arbejde med indlejrede tabeller, og det gør ikke Cascading Style Sheets (CSS) særlig godt. (Jeg har fået at vide, at mange af disse problemer vil blive løst i Java 1.5-udgivelsen næste år, men for tiden er vi alle nødt til at udholde dem.) Endelig, JEditorPane gør ikke et særligt godt stykke arbejde med at lægge ting ud som radioknapper. De er ikke justeret korrekt med tekstbaselinjen, og de viser altid en grå baggrund, så de fungerer ikke godt, hvis du ændrer sidens baggrundsfarve (med en stil på tag, for eksempel).

Alle disse mangler er irriterende, men show-stop-problemet med JEditorPane er, at det fungerer som en tekstkontrol, ikke som en layoutfacilitet. Du kan angive en HTML i input, for eksempel, men formularen sendes til en webserver, når du trykker på knappen Send. For at være nyttig til at specificere et brugergrænseflade på klientsiden, skal du have formulardataene til at gå tilbage til det program, der viste formularen, ikke til en eller anden ekstern server. Du har også brug for en praktisk måde at tilføje brugerdefinerede tags til ikke-standardiserede input- eller visningsformål eller at give pladsholdere til standard Swing JKomponenter du vil bruge på formularen. (JEditorPane lader dig gøre dette, men mekanismen er langt fra praktisk.) Endelig skal du håndtere ting som en Annuller-knap, som ikke findes i HTML.

Heldigvis kan de mest alvorlige af de foregående problemer løses ved hjælp af indbyggede tilpasningsfaciliteter JEditorPane sig selv. At løse disse problemer indebærer dog en vis kompromis. For eksempel kan du håndtere problemet Annuller-knappen ved at implementere en JavaScript-tolk og støtte onclick attribut, men det er forfærdeligt meget arbejde. På samme måde er det meget vanskeligt at gøre med den eksisterende parser at levere ægte tilpasset tag-support (hvor du kan behandle alt, hvad der kommer mellem et start- og slut-tag). Du kan erstatte JEditorPaneparser med en bedre, men det er også meget arbejde. Jeg valgte enklere løsninger, der gjorde jobbet. Jeg satte nok funktionalitet i min klasse til, at jeg kunne bruge den til at opbygge en brugergrænseflade til det program, jeg skrev, men gav ikke en "perfekt" løsning. Problemet jeg løste var: give en måde at specificere en brugergrænseflade i HTML. Jeg løste ikke problemet: Giv en måde at vise al mulig HTML i en applikation på klientsiden. Det HTML-rude klasse, jeg præsenterer i denne artikel, løser specifikt-a-UI-i-HTML-problemet pænt.

Brug af HTMLPane

Min klient-side-kun HTML-input klasse, HTML-rude, er en JEditorPane derivat, der løser de tidligere diskuterede problemer. Liste 1 viser, hvordan man bruger en HTML-rude. Jeg skabte en simpel JDialog derivat kaldes HtmlDialog hvor du kan angive dialogboksens layout som HTML. Det HtmlDialog er et trivielt eksempel på facademønsteret. Det gør bare det rote arbejde, der er nødvendigt for at sætte en HTML-rude i en dialogboks og vise den.

Det HtmlDialog.Test klasse (liste 1, linje 134) giver et simpelt eksempel på, hvordan man bruger HtmlDialog. Det skaber en stort set tom hovedramme (ejer). Ved hjælp af kode som uddraget gengivet nedenfor, hoved () skaber en HtmlDialog objekt, hvis indhold er specificeret i den CLASSPATH-relative fil com / holub / ui / HTML / test / okay.html (Liste 2). Strengen "Test HtmlDialog" vises i titellinjen. Langt om længe, hoved () dukker op i dialogen ved at ringe d.popup (), som ikke vender tilbage, før brugeren lukker dialogen:

// Vis okay.html-filen i en dialogboks, der har// titlen "Test HtmlDialog".// HtmlDialog dialog = ny HtmlDialog (owning_frame, "com / holub / ui / HTML / test / okay.html", "Test HtmlDialog"); // Pop op dialogen, og vent på, at brugeren afviser den.// dialog.popup (); // Udskriv de "form" -data, som brugeren skrev.// System.out.println ("skjult =" + dialog.data (). GetProperty ("skjult") + "bruger-input" + dialog.data (). GetProperty ("bruger-input")); 

Formulardata (teksten, som brugeren skrev i en element eller tilsvarende), er tilgængelig via HtmlDialog's data() metode, som returnerer en java.util.Ejendomme objekt, der indeholder nøgle / værdipar, der repræsenterer formulardataene. Ovenstående kald til dialog.data (). getProperty ("skjult") returnerer strengen "skjulte feltdata". Det dialog.data (). getProperty ("bruger-input") opkald returnerer hvad brugeren har indtastet i indtastningsfeltet.

Det meste af arbejdet involveret i at instantere det indkapslede HTML-rude sker i HtmlDialog konstruktør (liste 1, linje 46). Konstruktøren opretter først en ActionListener der håndterer knappen Send på formularen. Denne observatør lukker den aktuelle dialogboks ned og kopierer eventuelle formulardata fra HTML-rude til data instansvariabel. Konstruktøren henter derefter inputfilen fra CLASSPATH og indlæser derefter HTML'en i HTML-rude ved brug af setText (). (Der er også en setPage (URL) metode, men du har brug for en URL til den absolutte sti til filen, hvis du brugte den. Jeg ønskede, at HTML-filnavnet skulle være relativ CLASSPATH.)

Annuller behandling håndteres pop op() (linje 121), som antager, at der blev trykket på en Annuller-knap, hvis der findes en Annuller-tast i de indsendte formulardata. (Mere om hvordan disse data kommer ind i Ejendomme objekt på et øjeblik.)