Programavimas

„Java“ patarimas 109: atvaizduokite vaizdus naudodami „JEditorPane“

Galite naudoti srovę „JEditorPane“ komponentas HTML žymėjimui rodyti, bet sudėtingesnėms užduotims atlikti, „JEditorPane“ reikia šiek tiek patobulinti. Neseniai turėjau sukurti XML formų kūrimo programą. Vienas būtinas komponentas buvo WYSIWYG HTML redaktorius, galintis redaguoti HTML žymėjimo turinį kai kuriose XML žymose. „JEditorPane“ buvo akivaizdus „Java“ komponento pasirinkimas rodant HTML žymėjimą, nes ši funkcija jau buvo įmontuota. Deja, įterpiant į HTML žymėjimą, „JEditorPane“ negalėjo rodyti vaizdų su santykiniais keliais. Pvz., Jei šis vaizdas su santykiniu keliu buvo XML žymoje, jis nebus tinkamai rodomas:

Ir atvirkščiai, veiktų absoliutus kelias (darant prielaidą, kad nurodytas kelias ir vaizdas tikrai egzistavo):

Mano programoje vaizdai visada buvo saugomi pakatalogyje, palyginti su XML failo vieta. Taigi, aš visada norėjau naudoti santykinį kelią. Šiame straipsnyje bus paaiškinta, kodėl ši problema egzistuoja ir kaip ją išspręsti.

Kodėl taip nutinka?

Atidžiau pažvelgus į statybininkus „JEditorPane“ padės mums suprasti, kodėl jis negali rodyti vaizdų santykiniais keliais.

  1. „JEditorPane“ () sukuria naują „JEditorPane“.
  2. „JEditorPane“ (eilutės URL) sukuria a „JEditorPane“ pagrįstas eilute, kurioje yra URL specifikacija.
  3. JEditorPane (eilutės tipas, eilutės tekstas) sukuria a „JEditorPane“ kuris buvo inicializuotas pagal pateiktą tekstą.
  4. „JEditorPane“ (URL initialPage) sukuria a „JEditorPane“ pagrįstas nurodytu įvesties URL.

Antrasis ir ketvirtasis konstruktoriai inicijuoja objektą nurodydami nuotolinį arba vietinį HTML failą. An HTMLDocument yra kiekvieno viduje „JEditorPane“, o jo bazė nustatyta į URL konstruktoriaus parametro bazę. „JEditorPane“Sukurti naudojant tuos konstruktorius, gali apdoroti santykinius kelius, nes pagrindas HTMLDocument derinamas su santykiniu keliu, kad būtų sukurtas absoliutus kelias.

Jei naudojamas pirmasis konstruktorius, sukurtas objektas turi būti įterptas rodomas tekstas. Trečiasis konstruktorius priima a Stygos kaip turinys, bet pagrindas nėra inicializuotas. Kadangi norėjau gauti HTML žymėjimą iš XML žymos, o ne failo, turėjau naudoti arba pirmą, arba trečią konstruktorių.

Kaip išspręsti problemą?

Prieš tęsdamas, atskleiskime ir išspręskime dar vieną mažesnę problemą. Akivaizdžiausias būdas įterpti žymėjimą į „JEditorPane“ yra naudoti setText (eilutės tekstas). Tačiau šis metodas reikalauja, kad kiekvieną kartą atlikdami pakeitimus įvestumėte visą rodomą žymėjimą. Geriausia, jei naujoji žyma (-os) turėtų būti įterpta į esamą tekstą. Norėdami pridėti naują žymėjimą, galite naudoti šį kodą:

private void insertHTML (JEditorPane editor, String html, int location) throws IOException {// daro prielaidą, kad redaktorius jau nustatytas kaip „text / html“ tipo HTMLEditorKit kit = (HTMLEditorKit) editor.getEditorKit (); Dokumentas doc = editor.getDocument (); „StringReader“ skaitytuvas = naujas „StringReader“ (html); rinkinys.skaityti (skaitytuvas, dokumentas, vieta); } 

Dabar, pereinant prie klausimo esmės: kaip „JEditorPane“ pateikti HTML? Kiekvieno tipo „JEditorPane“ nuorodos tiek a Dokumentas ir an „EditorKit“. Kada „JEditorPane“ yra nustatytas kaip "text / html", jame yra HTMLDocument, kuriame yra žymėjimas ir „HTMLEditorKit“ tai nustato, kurios klasės pateikia kiekvieną žymoje esančią žymą. Tiksliau, „HTMLEditorKit“ klasėje yra HTMLFactory vidinė klasė, kurios sukurti (elemento elementas) metodas iš tikrųjų tiria kiekvieną atskirą žymą. Štai tos gamyklos klasės kodas, kuris tvarko vaizdų žymas:

 else if (kind == HTML.Tag.IMG) grąžinti naują „ImageView“ (elem); 

Kaip dabar matote, „ImageView“ klasė iš tikrųjų įkelia vaizdą. Norėdami nustatyti vaizdo vietą, getSourceURL () metodas vadinamas:

 privatus URL getSourceURL () {String src = (String) fElement.getAttributes (). „getAttribute“ (HTML.Attribute.SRC); if (src == null) grąžinti nulį; URL nuoroda = ((HTMLDocument) getDocument ()). getBase (); pabandykite {URL u = naujas URL (nuoroda, src); grįžti u; } gaudyti (netinkamai suformuotaURLException e) {return null; }} 

Čia, getSourceURL () metodas bando sukurti naują URL, nurodantį vaizdą naudodamas HTMLDocument bazė. Jei ši bazė yra nulinė, grąžinama "null" ir nutraukiama vaizdo įkėlimo operacija. Norite nepaisyti tokio elgesio.

Geriausia, jei subklasę priskirtumėte „ImageView“ klasę ir nepaisyti inicijuoti (elemento elementas) metodas, kur atliekamas vaizdo įkėlimas. Deja, ta klasė yra paketas apsaugotas, taigi turite sukurti visiškai naują klasę. Lengviausias būdas tai padaryti yra skolintis, tada modifikuoti kodą iš originalo „ImageView“ klasė. Pavadinkime „MyImageView“.

Pirmiausia pažiūrėkite į kodą, kuris įkėlė vaizdą. Iš inicijuoti (elemento elementas) metodas:

 URL src = getSourceURL (); if (src! = null) {Žodyno talpykla = (Žodynas) getDocument (). getProperty (IMAGE_CACHE_PROPERTY); if (cache! = null) fImage = (Image) cache.get (src); else fImage = Toolkit.getDefaultToolkit (). getImage (src); } 

Čia gausite URL; jei jis yra nulinis, praleidžiate vaizdo įkėlimą. Į „MyImageView“, šį kodą turėtumėte vykdyti tik tuo atveju, jei jūsų vaizdo nuoroda yra URL. Toliau pateiktas metodas, kurį galite pridėti norėdami išbandyti vaizdo šaltinį:

 privati ​​loginė reikšmė isURL () String src = (String) fElement.getAttributes (). getAttribute (HTML.Attribute.SRC); grąžinti src.toLowerCase (). startsWith ("failas") 

Iš esmės, jūs gaunate nuorodą į vaizdą a pavidalu Stygos ir patikrinkite, ar jis prasideda vienu iš dviejų URL tipų: failą vietiniams vaizdams ir http nuotoliniams vaizdams. Jens Alfke, originalo autorius javax.swing.text.html.ImageView klasė, naudoja klasės globalius kintamuosius, todėl parametrų perdavimas funkcijoms yra nereikalingas. Čia visuotinis kintamasis yra fElementas.

Galite parašyti kodą, kuriame sakoma jei (isURL ()) {}, bet ką jūs įtraukiate į kitą santykinio kelio teiginį? Tai gana paprasta - tiesiog įkelkite vaizdą taip, kaip paprastai darytumėte programoje:

 else {String src = (String) fElement.getAttributes (). getAttribute (HTML.Attribute.SRC); fImage = Toolkit.getDefaultToolkit (). createImage (src); } 

Tikros magijos čia nėra, bet yra vienas laimikis. createImage (src) funkcija gali grįžti, kol nebus užpildyti visi vaizdo taškai. Tokiu atveju bus rodomas sulaužytas vaizdas. Norėdami išspręsti problemą, galite tiesiog palaukti, kol vaizdo pikseliai bus visiškai užpildyti. Mano pirmasis polinkis buvo naudoti „MediaTracker“ nustatyti, kada vaizdas buvo paruoštas, bet „MediaTracker“Konstruktorius reikalauja, kad komponentas atvaizdą atvaizduotų kaip parametrą. Taigi dar kartą pasiskolinau kodą iš Jimo Grahamo java.awt.MediaTracker ir parašiau savo metodą problemai apeiti:

 private void waitForImage () meta InterruptedException {int w = fImage.getWidth (tai); int h = fImage.getHeight (tai); o (tiesa)} 

Šis metodas iš esmės atlieka tą patį darbą kaip ir „MediaTracker“'s waitForID (int id) metodas, tačiau nereikia pagrindinio komponento. Šį metodą galima iškviesti iškart sukūrus vaizdą.

Yra nedidelė problema, kurią turėčiau paminėti prieš tęsdamas. Nebuvo įmanoma subklasė „ImageView“ nuo javax.swing.text.html paketą, todėl nukopijavau visą failą, kad sukčiau savo klasę, vadinamą „MyImageView“, kurio nesudėjau į pakuotę. Originale „ImageView“ kodas, jei paveikslėlio negalima rodyti, nes jo nėra arba jis vėluoja, jis įkelia numatytąjį sugadintą vaizdą iš javax.swing.text.html.icons pakuotė. Norėdami įkelti sugadintą vaizdą, klasė naudoja getResourceAsStream (eilutės pavadinimas) metodas iš Klasė klasė. Tikrasis kodas atrodo taip:

 „InputStream“ šaltinis = HTMLEditorKit.class.getResourceAsStream (MISSING_IMAGE_SRC); 

kur MISSING_IMAGE_SRC parametras yra a Stygos su turiniu:

 MISSING_IMAGE_SRC = "piktogramos" + System.getProperty ("file.separator", "/") + "image-fail.gif"; 

Ši ištrauka iš „ImageView“ šaltinio kodas paaiškina „Sun“ argumentus, kaip naudoti getResourceAsStream (eilutės pavadinimas) sugadinto (-ų) vaizdo (-ų) įkėlimo būdas.

 / * Nukopijuokite išteklius į baitų masyvą. Tai yra * būtina, nes kelios naršyklės mano, kad * Class.getResource kelia saugos riziką, nes ją * galima naudoti papildomoms klasėms įkelti. * Class.getResourceAsStream tiesiog grąžina neapdorotus * baitus, kuriuos galime konvertuoti į vaizdą. * / 

Jei dar nepraleidote šio skyriaus (žinau, jis gana smulkus!), Leiskite man paaiškinti, kodėl aš jį paminėjau. Jei nežinote apie tokį elgesį, nesuprasite, kodėl sugadinti vaizdai rodomi netinkamai, ir negalėsite išspręsti problemos savo kode. Norėdami išspręsti problemą, turite įkelti savo atvaizdus. Aš nusprendžiau ir toliau naudoti tą patį metodą, tačiau tai tikrai nėra būtina. Pirmiau pateiktas įspėjimas skirtas naršyklėms, kuriose yra programėlių, kurios turi saugumo sumetimų, kurie riboja prieigą prie disko (žinoma, jei nepasirašyta). Bet kokiu atveju šis straipsnis buvo skirtas naudoti su programa, todėl naudojant alternatyvų vaizdo įkėlimo metodą neturėtų kilti problemų.

Kai skambina getResourceAsStream (eilutės pavadinimas) padarytas, galite įtraukti santykinį kelią į vaizdą, kaip parodyta aukščiau. Pirmiau pateiktame kode sugadintas vaizdas visada bus įkeltas iš nurodyto kelio, palyginti su „HTMLEditorKit“ klasė. Pavyzdžiui, kadangi „HTMLEditorKit“ klasė yra javax.swing.text.html, ji bandys įkelti sugadintą vaizdą vaizdas nepavyko.gif nuo javax.swing.text.html.icons. Tai taip pat taikoma paprastiems katalogams; klasės neturi būti paketuose. Galiausiai, nuo tada „HTMLEditorKit“ yra apsaugotas paketu, jūs neturite prieigos prie jo getResourceAsStream (eilutės pavadinimas) metodas. Vietoj to galite naudoti „MyImageView“ klasę ir sugadintus vaizdus įdėkite į piktogramų pakatalogį. Kodo eilutė atrodys taip:

 „InputStream“ šaltinis = „MyImageView.class.getResourceAsStream“ (MISSING_IMAGE_SRC); 

Jei nuspręsite naudoti panašų į mano įgyvendinimą, turėsite sukurti savo piktogramas. Vis tiek galite naudoti piktogramas, sujungtas su „Sun“ JDK, tačiau tam reikia pakeisti išteklių vietą, kad vietoj santykinio kelio būtų naudojamas absoliutus kelias. Absoliutus kelias yra:

javax.swing.text.html.icons.imagename.gif 

Norėdami sužinoti apie naudojimą getResourceStream (eilutės pavadinimas), žr. „Javadoc“ informaciją Klasė klasė; nuoroda pateikiama šaltiniuose.

Šis straipsnis yra beveik visas apie santykinių kelių pritaikymą, tačiau kuo jie yra susiję? Iki šiol, jei naudosite mano pateiktą kodą, galėsite naudoti tik kelius, palyginti su tuo, kur pradėjote programą. Tai puiku, jei visi vaizdai visada yra tuose keliuose, bet tai ne visada. Nesidomėsiu, kaip išspręsti šią problemą, nes ją galima lengvai išspręsti. Galite nustatyti programos visuotinį kintamąjį kur nors savo programoje arba nustatyti sistemos kintamąjį. Į „MyImageView“, prieš įkeldami vaizdą, susiejate santykinį kelią su vaizdu ir absoliutų kelią, gautą iš visuotinio kintamojo. Jei tai neturi prasmės, ieškokite processSrcPath () metodas galutiniame „MyImageView“.

Pagaliau, „MyImageView“ yra baigtas. Tačiau jūs turite suprasti, kaip tai pasakyti „JEditorPane“ naudoti „MyImageView“ vietoj javax.swing.text.html.ImageView. „JEditorPane“ gali palaikyti tris teksto formatus: paprastą, RTF ir HTML. Jei „JEditorPane“ rodo HTML, PagrindinisHTML - poklasis TextUI - naudojamas HTML atvaizdavimui. PagrindinisHTML naudoja „JEditorPane“'s „HTMLEditorKit“ sukurti Vaizdas. „HTMLEditorKit“ yra metodas vadinamas getViewFactory (), kuris pateikia vidinės klasės egzempliorių, vadinamą HTMLFactory. HTMLFactory yra metodas vadinamas sukurti (elemento elementas), kuris grąžina a Vaizdas pagal žymos tipą. Tiksliau, jei žyma yra IMG žymą, ji grąžina „ImageView“. Norėdami grąžinti „MyImageView“, galite sukurti savo „EditorKit“ paskambino „MyHTMLEditorKit“, kurie poklasiai „HTMLEditorKit“. Jūsų viduje „MyHTMLEditorKit“, sukursite naują vidinę klasę, vadinamą „MyHTMLFactory“, kurie poklasiai HTMLFactory. Toje vidinėje klasėje galite susikurti savo sukurti (elemento elementas) metodas, kuris atrodo maždaug taip:

 public View create (Element elem) {Object o = elem.getAttributes (). getAttribute (StyleConstants.NameAttribute); if (o HTML.Tag egzempliorius) {HTML.Tag kind = = (HTML.Tag) o; if (kind == HTML.Tag.IMG) grąžinti naują MyImageView (elem); } return super.create (elem); } 

Vienintelis dalykas, kurį dabar reikia padaryti, yra nustatyti „JEditorPane“ naudoti „MyHTMLEditorKit“. Kodas yra gana paprastas:

$config[zx-auto] not found$config[zx-overlay] not found