Integrere en HTML Editor i Qt ved hjelp av Javascript og QWebView.

Integrere en HTML Editor i Qt ved hjelp av Javascript og QWebView.

publisert pa 25.08.2015 16:27 av Jens Weller.

Velkommen til 8. del av serien min pa skriveprogrammer i C ++ med Qt og boost. Det siste innlegget handlet om signalering og meldingstjenester i C ++. Denne gangen handler det om a integrere en HTML Editor i Qt med QWebView og Javascript! Jeg starter med tekstredigerere generelt, og deretter fortsetter integrasjonen, basert pa QWebkit og TinyMCE3. Sluttresultatet er litt hackery, men det er en arbeidslosning. Jeg trengte ikke a bruke noen skitne triks for a gjore dette arbeidet, for eksempel a skrive en server som kjorer pa localhost for a levere bilder og andre data som et tilpasningspunkt.

Videoen, hvis du heller lytter / ser sa leser du:

Sa fikk jeg denne galne ideen om a skrive mitt eget CMS i sommer. Jeg har v rt pa jakt etter omtrent et ar pa ulike losninger og tiln rminger til a bygge nettsteder. Jeg sjekket selv alternativene for a skrive nettsteder med C ++. CppCMS eller TreeFrog er rammer som gjor det mulig for deg a gjore det. Men det passer ikke til brukssaken min, og jeg vil ogsa senere kunne integrere mitt eget verktoy for konferansen og andre behov. En av dem er at selvfolgelig vil jeg beholde arbeidsflyten som jeg for oyeblikket har, en del av dette skriver HTML som ting i en WYSIWYG-editor for blogginnlegg osv. Jeg vil unnga a skrive ra HTML eller kopiere pasta fra Open Office etc. Sa jeg trenger en dyktig HTML-editor i min Qt-applikasjon.

KDE Framework 5 har et tekstredigeringsramme, som vil v re interessant a bruke, selv om jeg ikke er sikker pa om den har HTML-funksjonalitet. Ogsa det ville bringe en masse avhengigheter i prosjektet mitt. Nar jeg onsker a beholde arbeidsflyten min, hvorfor ikke bruk hva som driver a skrive dette og alle andre blogginnlegg godt i mange ar? Sa det viser seg a integrere tinymce i min Qt-applikasjon ville v re den optimale losningen for meg. Sluttresultatet:

Integrering av TinyMCE i Qt.

Da jeg startet, kjorte dette nesten meg gal. Dette er ogsa min forste virkelige bruk av javascript, jeg har aldri brukt js sa langt for noe bortsett fra grunnleggende ting i webdev. Jeg eksperimenterte ogsa med CKEditor og startet med TinyMCE4. Jeg kunne ikke fa TinyMCE4 til a kjore i QWebKit-basert QWebView, og ettersom TinyMCE3 har fungert bra i mange ar, anser jeg det sannsynligvis det beste alternativet for meg. Jeg har avledet en HTMLTextEditor-klasse fra QWebView, da dette ville tillate meg a ogsa enkelt overskrive noen behavoir form QWebView, men sa langt det ikke var nodvendig. Ogsa, nar jeg sokte pa nettet for dette, fant jeg et prosjekt som gjorde noe lignende, det hjalp meg med a lose noen problemer i starten, men det var noe jeg onsket a unnga a legge til TinyMCE i Qt-ressurssystemet. Ogsa losningen er fra 2011, og utleder ikke en klasse fra QWebView, som jeg foretrekker i dette tilfellet. Ogsa med 0 nedlastinger, ville jeg ikke basere en slik kritisk komponent pa apenbart un (der) brukt losning.

Et av problemene som gjor denne integrasjonen vanskelig, er at redaktorene ikke er ment a bli brukt i et slikt miljo. De har utviklet seg som nodvendig verktoy i et webdrevet miljo, og bruker ofte tilpasningspunkter som ikke er enkle a etterligne fra C ++ land. Ogsa, da redaktoren bor i QWebView, gjor alle dialoger det ogsa. Disse dialogene er ofte lost i storrelse, og dette er et lite problem nar nettvisningen ikke er stor nok, rullefeltene er stygge. Ogsa a prove a flytte en slik dialog er ikke den beste brukeropplevelsen, siden den er fanget i den lille nettvisningen, som brukeren er fokusert pa applikasjonen.

Mens de fleste funksjonene til tekstredigeringsprogrammet fungerer rett ut av boksen, behoves det to tilpasningspunkter: valg av bilder og koblinger fra den aktuelle modellen. TinyMCE3 har et tilpasningspunkt for dette: external_image_list_url. Dette forventer en filsystem url, jeg skrev en liten server basert pa QTcpServer for a teste om jeg kunne overfore bildelisten pa denne maten. Dette virket ikke, external_image_list_url: 127.0.0.1 ga en hit, men det var ikke en suksess a sende tilbake et grunnleggende HTTP-svar. Ogsa, jeg onsker egentlig ikke a integrere en server for dette i soknaden min. Det ma v re en bedre mate, ogsa ved a ga ned pa dette nettstedet til kaninhullet ville det v re a bruke dialogene til TinyMCE3 for bilder og koblinger, som jeg vil erstatte med Qt-baserte dialoger i soknaden min.

Et annet problem er basen uri som redaktoren aksepterer som hjemme, sa langt hadde jeg ikke lykke til a sette det manuelt. Siden jeg ikke kan laste redigeringsvisningen setHtml inn i QWebView, ma den for oyeblikket v re en html-fil pa filsystemet. Plasseringen av denne filen er automatisk dens grunnleggende uri. Min losning pa dette problemet er a bare kopiere editor.html fra en mal til riktig posisjon for hvert prosjekt nar det ble opprettet. Dette fungerer.

Koble til C ++, Qt og TinyMCE.

Det er noen mater a samhandle med Javascript fra C ++. Googles V8-motor har sitt eget bibliotek, og det finnes andre biblioteker pa toppen av dette. Qt har ogsa muligheten til a koble til Javascript, og tilbyr med QML selv sitt eget JS-kompatible brukergrensesnitt, som er unikt for Qt. Dette er drevet av kode, som har sin rot i skriptegenskapene for Qt og QWebKit. QWebkit har en Javascript / C ++-bro som tillater a eksponere QObject-baserte klasser til js, dette gjor det ogsa mulig a sende ut signaler fra Javascript, og ringe metoder pa et slikt QObject, hvis de er merket med Q_INVOKABLE. Jeg gikk begge veier, og synes na at Q_INVOKABLE er litt bedre. Det er ogsa ganske enkelt a utfore Javascript-kode fra C + +, slik at full tur er mulig js – & gt; C ++ – & gt; js. Dette er viktig for a velge bilder i C ++ og deretter sette dem inn i redigereren via Javascript API for TinyMCE.

En forste titt pa HTMLTextEditor-klassen:

Som du ser, bruker et signal skaper litt mer stoy i koden, og bare legger Q_INVOKABLE til en metode. Oppsettet er delt inn i konstruktoren og settBasePath:

Via QWebView :: side () far du tilgang til det interne QWebPage-objektet, som ikke er som QWebView en QWidget. Hvis du angir lenkedelegeringspolitikken, forhindrer QWebView a apne eksterne koblinger i redigeringsprogrammet. Ellers vil et klikk pa en ekstern lenke (for eksempel http://meetingcpp.com) apne den nettsiden i redigeringsprogrammet. Og da objektet nettopp er opprettet, la oss fa javascript-delen av QWebView a vite om objektet med addToJavaScriptWindowObject. Na kan du sende ut signaler og ringe Q_INVOKABLE metoder fra Javascript ved hjelp av window.hostObject. For a kunne gjore dette pa riktig tidspunkt, trengte jeg a implementere til tinymce plugins: en for linking og en for bilder. Alt de gjor er a ringe / sende ut insertLink / selectImage. For oyeblikket er det ikke mulig a redigere innsatte bilder eller koblinger, men det ville v re mulig a gjore dette, fordi parametere er tillatt for signaler og metoder som interagerer med Javascript. Disse parametrene er begrenset til Qt-standardtyper som er kjent for QWebkit C ++ / js-broen. I dette tilfellet vil QString v re nok.

Dette er koden som velger bildet:

Jeg bruker C ++ 11-funksjonen i raske strenger, da det gjor det mye lettere a legge inn denne js-koden i C ++-koden. Alle bilder lagres under / img /, nar brukeren velger et bilde blir det satt inn via tsymcens js api. execJS er en metode som kjorer alle Javascript i denne klassen, slik at jeg kunne legge til lett logging etc. til en metode, i stedet for mange. For oyeblikket kan man bare sette inn bilder med src og alt, ImageDialog er fortsatt en prototype:

Koden som gjor C ++-delen for a sette inn koblinger, er veldig lik:

Denne gangen er js-koden litt mer kompleks, men faktisk gjor 2-trinns js-kode arbeidet. Resten er bare for bedre integrering og kansellering av valget. A fa / sette inn innholdet i redaktoren er ganske enkelt a:

GetContent-metoden hint, at execJS returnerer en verdi som kommer fra Javascript. Men setContent-metoden fortjener litt oppmerksomhet. Det ser sa lett ut at jeg ved forste testing ikke skjonte at de andre metodene ble utfort i en annen sammenheng. Disse metodene blir utfort nar de blir hentet fra redigeringsprogrammet, som allerede er fulllastet. Ringer setContent i en annen kontekst, f.eks. fra konstruktoren eller etter setUrl i setBasePath vil det ganske enkelt ikke fungere og vise ingenting i redaktoren. Som setUrl er asynkron, og ogsa QWebViews loadFinished hjelper ikke her, som det er bare for HTML, ikke Javascript kjorer na inne i QWebView. Sa, for oyeblikket har jeg i skjemaet som inneholder denne klassen en knapp «last innhold» som kaller setContent nar den klikkes. Dette er selvsagt bare et bevis pa konsept, jeg vil nok erstatte dette med en timer. SetContent tar ogsa QString per verdi, da erstatning ikke er const.

Metoden execJS kaller bare metoden for a utfore js i webvisningen, og returnerer en QVariant, som holder resultatet, hvis js-funksjonen returnerer en:

Og dette er hele koden som trengs for a integrere TinyMCE3 i min Qt-applikasjon. Vel, den innebygde klassen ma gjore noe arbeid med a koble til :: signal2 signaler for a motta oppdateringer for lenker og bilder. Men dette er en annen historie.

Copyright Meetingcpp GmbH 2018 Impressum Piwik Opt ut.