Zephyrnet-logo

Bygg en Native Desktop GIF Searcher-app ved hjelp av NodeGui

Dato:

NodeGui er et åpen kildekodebibliotek for å bygge innfødte stasjonære apper på tvers av plattformer med Node.js. NodeGui-apper kan kjøres på macOS, Windows og Linux. Appene som er bygget med NodeGui er skrevet ved hjelp av JavaScript, stylet med CSS og gjengitt som native desktop-widgets ved hjelp av Qt rammeverk.

Noen av funksjonene i NodeGui er:

  • native widgets med innebygd støtte for mørk modus
  • lavt CPU- og minnefotavtrykk
  • styling med CSS inkludert komplett støtte for Flexbox-layout
  • fullfør Node.js API-støtte og tilgang til alle Node.js-kompatible npm-moduler
  • utmerket feilsøkingsstøtte ved hjelp av Chrome DevTools
  • førsteklasses TypeScript-støtte

NodeGui er drevet av Qt-rammeverket, noe som gjør det CPU og minne effektivt sammenlignet med andre Chrom-baserte løsninger som Electron. Dette betyr at applikasjoner skrevet med NodeGui ikke åpne en nettleserinstans og gjengi brukergrensesnittet i den. I stedet blir alle widgetene gjengitt innfødte.

Denne opplæringen vil demonstrere hvordan du installerer NodeGui og bruker den til å bygge en memsøker som bor i systemstatusfeltet og kommuniserer med GIPHY API.

Hele kildekoden for denne opplæringen er tilgjengelig på GitHub.

Installasjon og grunnleggende oppsett

For denne opplæringen antas det at du har Node.js v12 eller større installert. Du kan bekrefte at både Node og npm er tilgjengelige ved å kjøre:

# This command should print the version of Node.js
node -v # This command should print the version of npm
npm -v

Hvis du trenger hjelp med dette trinnet, kan du sjekke ut vårt veiledning om installering av Node.

NodeGui krever CMake og C ++ kompileringsverktøy for å bygge det opprinnelige C ++ laget av prosjektet. Sørg for at du installerer CMake> = 3.1 sammen med en C ++ - kompilator som støtter C ++ 11 og oppover. De detaljerte instruksjonene er litt forskjellige, avhengig av operativsystem.

macOS

Det anbefales å installere CMake ved hjelp av Homebrew. Kjør følgende kommandoer i en terminal etter at du har installert Homebrew:

brew install cmake
brew install make

Du kan bekrefte installasjonen ved å kjøre:

# This command should print the version of CMake which should be higher than 3.1
cmake --version make --version

Til slutt trenger du GCC / Clang for å kompilere C ++ - kode. Bekreft at du har GCC installert ved hjelp av denne kommandoen:

gcc --version

Hvis du ikke har GCC installert, må du sørge for at du installerer Kommandolinjeverktøy for Xcode or XCode Developer-verktøy fra Apples utviklerside.

Windows

Du kan installere CMake på Windows ved å laste ned den siste utgivelsen fra CMake nedlastingsside.

Det anbefales sterkt at du bruker Powershell som den foretrukne terminalen i Windows.

Du kan bekrefte CMake-installasjonen ved å kjøre:

# This command should print the version of CMake which should be higher than 3.1
cmake --version

Til slutt trenger du en C ++ - kompilator. En mulighet ville være å installer Visual Studio 2017 eller høyere. Det anbefales at du velger Desktoputvikling med C ++ arbeidsmengde under installasjonsprosessen.

Linux

Vi vil fokusere på Ubuntu 18.04 i forbindelse med denne opplæringen. Det anbefales å installere CMake ved hjelp av pakkebehandling. Kjør følgende kommandoer i en terminal:

sudo apt-get install pkg-config build-essential
sudo apt-get install cmake make

Du kan bekrefte installasjonen ved å kjøre:

# This command should print the version of CMake which should be higher than 3.1
cmake --version make --version

Til slutt trenger du GCC for å kompilere C ++ - kode. Bekreft at du har GCC installert ved hjelp av kommandoen:

# gcc version should be >= v7
gcc --version

Hallo verden

For å komme i gang med NodeGui-meme-appen vår, kloner vi startprosjektet.

Merk: Å kjøre dette krever Git og npm.

Åpne en terminal og kjør:

git clone https://github.com/nodegui/nodegui-starter memeapp
cd memeapp
npm install
npm start

Hvis alt går bra, bør du se en fungerende Hello World NodeGui-app på skjermen.

Hello World NodeGui eksempel

Som standard nodegui-startprosjekt er et TypeScript-prosjekt. I denne veiledningen skriver vi imidlertid søknaden vår i JavaScript. For å konvertere starteren vår til et JS-prosjekt, gjør vi følgende mindre endringer:

  1. Slett index.ts fil i src mappe.

  2. Opprett en ny fil index.js i src katalog med følgende innhold:

    src / index.js

    const { QMainWindow, QLabel } = require('@nodegui/nodegui'); const win = new QMainWindow();
    win.setWindowTitle('Meme Search'); const label = new QLabel();
    label.setText('Hello World'); win.setCentralWidget(label);
    win.show(); global.win = win;
    
    

Når det gjelder utvikling, er en NodeGui-applikasjon egentlig en Node.js-applikasjon. Alle APIer og funksjoner som finnes i NodeGui er tilgjengelige via @nodegui/nodegui modul, som kan kreves som alle andre Node.js-moduler. I tillegg har du tilgang til alle Node.js APIer og Node-moduler. NodeGui bruker innfødte komponenter i stedet for nettbaserte komponenter som byggesteiner.

I eksemplet ovenfor har vi importert QMainWindow og QLabel for å lage et eget vindu som viser teksten "Hello World".

Kjør nå appen igjen:

npm start

Hello World JavaScript-versjon

Nå som vi har vårt grunnleggende oppsett klart, la oss begynne å bygge meme searcher 🥳.

Merk: Hvis noe ikke fungerer når du følger denne opplæringen, sjekk din package.json fil for å sikre at startprosjektet har hentet den mest oppdaterte versjonen av NodeGui.

Viser en animert GIF

Siden memes generelt er animerte GIF-er, begynner vi med å lage et grunnleggende vindu som viser et GIF-bilde fra en URL.

For å gjøre dette bruker vi QMovie sammen med QLabel. QMovie er ikke en widget, men en container som kan spille enkle animasjoner. Vi bruker den i kombinasjon med QLabel.

Et eksempel på bruk av QMovie ser slik ut:

const movie = new QMovie();
movie.setFileName('/absolute/path/to/animated.gif');
movie.start(); const animatedLabel = new QLabel();
animatedLabel.setMovie(movie);

Siden vi ønsker å laste inn et bilde fra en URL, kan vi ikke bruke det QMovie's setFilnavn metoden, som kun er reservert for lokale filer. I stedet laster vi ned GIF-bildet ved hjelp av Axios som buffer og bruk QMovie-metoden loadFromData i stedet.

Så la oss starte med installasjonen av Axios:

npm i axios

La oss nå lage en funksjon som tar en URL som parameter og returnerer en konfigurert QMovie eksempel for GIF:

async function getMovie(url) { const { data } = await axios.get(url, { responseType: 'arraybuffer' }); const movie = new QMovie(); movie.loadFromData(data); movie.start(); return movie;
}

De getMovie funksjonen tar inn en URL, forteller axios å laste ned GIF som buffer, og bruker deretter bufferen til å lage en QMovie forekomst.

Du kan tenke på QMovie som en klasse som håndterer den indre logikken i å spille GIF-animasjonen ramme for ramme. QMovie er ikke en widget, så den kan ikke vises på skjermen slik den er. I stedet bruker vi en vanlig QLabel forekomst og sett QMovie til det.

Siden getMovie returnerer et løfte, må vi gjøre noen endringer i koden. Etter litt mindre refactoring, ender vi opp med følgende.

src / index.js

const { QMainWindow, QMovie, QLabel } = require('@nodegui/nodegui');
const axios = require('axios').default; async function getMovie(url) { const { data } = await axios.get(url, { responseType: 'arraybuffer' }); const movie = new QMovie(); movie.loadFromData(data); movie.start(); return movie;
} const main = async () => { const win = new QMainWindow(); win.setWindowTitle('Meme Search'); const label = new QLabel(); const gifMovie = await getMovie( 'https://upload.wikimedia.org/wikipedia/commons/e/e3/Animhorse.gif' ); label.setMovie(gifMovie); win.setCentralWidget(label); win.show(); global.win = win;
}; main().catch(console.error);

De main funksjon er vårt inngangspunkt. Her lager vi et vindu og en etikett. Vi instanserer deretter a QMovie eksempel ved hjelp av vår getMovie funksjon, og til slutt angi QMovie til en QLabel.

Kjør appen med npm start og du bør se noe sånt som dette:

Grunnleggende animasjonseksempel som viser en galopperende hest

Henter GIF-er fra GIPHY API

Giphy.com har en offentlig API som alle kan bruke til å lage flotte apper som bruker animerte GIF-er. For å bruke GIPHY API, bør du registrere deg på utviklere.giphy.com og få en API-nøkkel. Du kan finne ytterligere instruksjoner her.

Vi bruker søk sluttpunkt funksjon for å implementere vårt memsøk.

La oss starte med å skrive en searchGifs funksjon som vil ta en searchTerms parameter som input og forespørsel GIF ved hjelp av endepunktet ovenfor:

const GIPHY_API_KEY = 'Your API key here'; async function searchGifs(searchTerm) { const url = 'https://api.giphy.com/v1/gifs/search'; const res = await axios.get(url, { params: { api_key: GIPHY_API_KEY, limit: 25, q: searchTerm, lang: 'en', offset: 0, rating: 'pg-13' } }); return res.data.data;
}

Resultatet av funksjonen etter utførelse vil se omtrent slik ut:

[ { "type": "gif", "id": "dzaUX7CAG0Ihi", "url": "https://giphy.com/gifs/hello-hi-dzaUX7CAG0Ihi", "images": { "fixed_width_small": { "height": "54", "size": "53544", "url": "https://media3.giphy.com/media/dzaUX7CAG0Ihi/100w.gif?cid=725ec7e0c00032f700929ce9f09f3f5fe5356af8c874ab12&rid=100w.gif", "width": "100" }, "downsized_large": { "height": "220", "size": "807719", "url": "https://media3.giphy.com/media/dzaUX7CAG0Ihi/giphy.gif?cid=725ec7e0c00032f700929ce9f09f3f5fe5356af8c874ab12&rid=giphy.gif", "width": "410" }, ... }, "slug": "hello-hi-dzaUX7CAG0Ihi", ... "import_datetime": "2016-01-07 15:40:35", "trending_datetime": "1970-01-01 00:00:00" }, { type: "gif", ... }, ...
]

Resultatet er egentlig en rekke objekter som inneholder informasjon om hver GIF. Vi er spesielt interessert i returnValue[i].images.fixed_width_small.url for hvert bilde, som inneholder URL til GIF.

Viser en liste over GIF-er ved hjelp av API-ens svar

For å vise en liste over GIF-er, oppretter vi en getGifViews funksjon som vil:

  1. lage en QWidget container
  2. lage en QMovie widget for hver GIF
  3. lage en QLabel fra hver QMovie f.eks
  4. fest hver QLabel som barn av QWidget container
  5. returner QWidget container

Koden ser slik ut:

async function getGifViews(listOfGifs) { const container = new QWidget(); container.setLayout(new FlexLayout()); const promises = listOfGifs.map(async gif => { const { url, width } = gif.images.fixed_width_small; const movie = await getMovie(url); const gifView = new QLabel(); gifView.setMovie(movie); gifView.setInlineStyle(`width: ${width}`); container.layout.addWidget(gifView); }); await Promise.all(promises); container.setInlineStyle(` flex-direction: 'row'; flex-wrap: 'wrap'; justify-content: 'space-around'; width: 330px; height: 300px; `); return container;
}

La oss bryte dette litt ned.

Først oppretter vi containerwidgeten vår. QWidgets er egentlig tomme widgets som fungerer som containere. De ligner på <div> elementer i nettverdenen.

Deretter, for å tilordne små widgets til QWidget, må vi gi den en layout. EN layout dikterer hvordan barnets widgets skal ordnes inne i en forelder. Her velger vi FlexLayout.

Så bruker vi vår getMovie funksjon for å lage en QMovie forekomst for hver GIF-URL. Vi tildeler QMovie eksempel til en QLabel (oppkalt gifView) og gi den noen grunnleggende styling ved hjelp av setInlineStyle metode. Til slutt legger vi til QLabel widget til containerens layout ved hjelp av layout.addWidget metoden.

Siden alt dette skjer asynkront, venter vi på at alt skal løse Promise.all, før du angir noen containerstiler og returnerer containerwidgeten.

La oss nå endre vår main funksjon for å se listen over widgets vi utarbeidet.

src / index.js

const { FlexLayout, QLabel, QMainWindow, QMovie, QWidget } = require('@nodegui/nodegui');
const axios = require('axios').default;
const GIPHY_API_KEY = 'Your API key here'; async function getMovie(url) { ... }
async function searchGifs(searchTerm) { ... }
async function getGifViews(listOfGifs) { ... } const main = async () => { const win = new QMainWindow(); win.setWindowTitle('Meme Search'); const center = new QWidget(); center.setLayout(new FlexLayout()); // We get the list of gifs here const listOfGifs = await searchGifs('hello'); // We create the container with GIF view widgets const container = await getGifViews(listOfGifs); // We finally attach the container to the widget center.layout.addWidget(container); win.setCentralWidget(center); win.show(); global.win = win;
}; main().catch(console.error);

Hvis du kjører prosjektet etter å ha gjort disse endringene, bør du se:

Liste over "hei" GIF-er hentet fra GIPHY API

Flott! La oss nå legge til et søkeinntastingsfelt sammen med en knapp, slik at brukerne kan søke etter noe annet enn "hei" GIF-er.

Legge til en søkeinngang og -knapp

La oss starte med å lage en createSearchContainer funksjon, som vil godta en tilbakeringingsfunksjon som parameter. Dette kalles når du trykker på søkeknappen.

Her er hva funksjonen skal gjøre:

  1. lage en QWidget container, som vi legger til et søkeinntastingsfelt og -knapp som barn
  2. lage et oppsett og fest det til containeren
  3. opprette en søkeinngang og -knapp, og fest dem deretter til FlexLayout
  4. fest en hendelseslytter til knappen som når du klikker på den vil ringe onSearch tilbakeringingsfunksjon som sender den uansett hvilken tekst som er tilstede i tekstinntastingsfeltet
  5. returner QWidget container

Koden ser slik ut:

function createSearchContainer(onSearch) { const searchContainer = new QWidget(); searchContainer.setObjectName('searchContainer'); searchContainer.setLayout(new FlexLayout()); const searchInput = new QLineEdit(); searchInput.setObjectName('searchInput'); const searchButton = new QPushButton(); searchButton.setObjectName('searchButton'); searchButton.setText(' 🔎 '); searchButton.addEventListener('clicked', () => { onSearch(searchInput.text()); }); searchContainer.layout.addWidget(searchInput); searchContainer.layout.addWidget(searchButton); searchContainer.setStyleSheet(` #searchContainer { flex-direction: 'row'; padding: 10px; align-items: 'center'; } #searchInput { flex: 1; height: 40px; } #searchButton { margin-left: 5px; width: 50px; height: 35px; } `); return searchContainer;
}

Forhåpentligvis har du en god ide om hva som skjer her, men en ny ting å legge merke til er setStyleSheet-metoden. Du kan tenke på dette som en måte å bruke CSS på blokknivå på en gang. Det ligner veldig på globale stilark på nettet, men med den forskjellen at i StyleGui / Qt kan et stilark festes til en hvilken som helst blokk og ikke bare globalt.

For å utforme en widget ved hjelp av et stilark, må vi legge til en objectName til en widget, som vi vil bruke til å referere til den i stilarket. Dette er ganske identisk med et id i nettverdenen. For å sette en objectName, vi bruker setObjectName metoden.

La oss nå legge til dette searchContainer til hovedvinduet.

src / index.js

const { FlexLayout, QLabel, QLineEdit, QMainWindow, QMovie, QPushButton, QWidget,
} = require('@nodegui/nodegui'); const axios = require('axios').default;
const GIPHY_API_KEY = 'Your API key here'; async function getMovie(url) { ... }
async function searchGifs(searchTerm) { ... }
async function getGifViews(listOfGifs) { ... }
function createSearchContainer(onSearch) { ... } const main = async () => { const win = new QMainWindow(); win.setWindowTitle('Meme Search'); const center = new QWidget(); center.setLayout(new FlexLayout()); // Here we create the search container const searchContainer = createSearchContainer(searchText => { console.log('searchText: ', searchText); }); // Here we add it to the center widget before we add the list of GIFs. center.layout.addWidget(searchContainer); const listOfGifs = await searchGifs('hello'); const container = await getGifViews(listOfGifs); center.layout.addWidget(container); win.setCentralWidget(center); win.show(); global.win = win;
}; main().catch(console.error);

Nå, når du starter appen og skriver inn noe i søkefeltet, bør du se hva du søkte etter logget på terminalen din.

Liste over GIF-er med søkeinngang

Koble søket til GIF-visningen

For å laste inn nye GIF-er som svar på brukerens søk, må vi gjøre følgende:

  1. Inne i tilbakeringingen som utløses når du trykker på søkeknappen, ta tak i søketeksten og bruk den searchGifs funksjon for å få en ny liste over GIF-er.
  2. Opprett en ny container for disse GIF-ene ved hjelp av getGifViews funksjon.
  3. Fjern den eksisterende beholderen fra vinduet.
  4. Legg til den nye beholderen i vinduet.

Hvis vi blander ting litt rundt, får vi:

const main = async () => { const win = new QMainWindow(); win.setWindowTitle('Meme Search'); const center = new QWidget(); center.setLayout(new FlexLayout()); let container = new QWidget(); const searchContainer = createSearchContainer(async searchText => { try { // Create a new GIF container with new GIFs const listOfGifs = await searchGifs(searchText); const newGifContainer = await getGifViews(listOfGifs); // Remove existing container from the window center.layout.removeWidget(container); container.close(); // Add the new GIF container to the window center.layout.addWidget(newGifContainer); container = newGifContainer; } catch (err) { console.error('Something happened!', err); } }); center.layout.addWidget(searchContainer); win.setCentralWidget(center); win.show(); global.win = win;
};

La oss kjøre det igjen og se magien 🧙‍♂️.

Koblet GIF-søkemodul

Som du kan se, når du skriver inn noe i søkeboksen og trykker på søkeknappen, vil widgeten vår hente en liste over GIF-er som samsvarer med søkeordet fra GIPHY API.

Selv om alt dette beveger seg i riktig retning, har du sannsynligvis lagt merke til at listen over GIF-er er avskåret nederst, og det er ingen måte å bla dem på. Dette er fordi vi bruker en QWidget beholderen for å vise dem. For å gjøre containeren rullbar, må vi bytte QWidget for en QScrollArea. Dette gir en rullende visning til en annen widget.

Vi begynner med å fjerne height eiendom i getGifViews funksjon:

async function getGifViews(listOfGifs) { ... container.setInlineStyle(` flex-direction: 'row'; flex-wrap: 'wrap'; justify-content: 'space-around'; width: 330px;
- height: 300px; `); return container;
}

Da må vi endre oss src/index.js å se slik ut:

const { FlexLayout, QLabel, QLineEdit, QMainWindow, QMovie, QPushButton, QScrollArea, QWidget,
} = require('@nodegui/nodegui'); const axios = require('axios').default;
const GIPHY_API_KEY = 'Your API key here'; async function getMovie(url) { ... }
async function searchGifs(searchTerm) { ... }
async function getGifViews(listOfGifs) { ... }
function createSearchContainer(onSearch) { ... } const main = async () => { const win = new QMainWindow(); win.setWindowTitle('Meme Search'); const center = new QWidget(); center.setLayout(new FlexLayout()); const scrollArea = new QScrollArea(); scrollArea.setWidgetResizable(false); scrollArea.setInlineStyle('flex: 1; width: 350px; height: 400px;'); const searchContainer = createSearchContainer(async searchText => { try { const listOfGifs = await searchGifs(searchText); const newGifContainer = await getGifViews(listOfGifs); // Remove existing container from the scrollArea const oldContainer = scrollArea.takeWidget(); if (oldContainer) oldContainer.close(); // Add the new GIF container to the scrollArea scrollArea.setWidget(newGifContainer); } catch (err) { console.error('Something happened!', err); } }); center.layout.addWidget(searchContainer); center.layout.addWidget(scrollArea); win.setCentralWidget(center); win.show(); global.win = win;
}; main().catch(console.error);

Det skjer ingenting for spennende her. Vi lager et nytt QScrollArea, som vi legger til oppsettet under søkefeltet. Vi bruker også QScrollArea's takeWidget-metoden for å fjerne eksisterende containere fra rulleområdet før du legger til de nye søkeresultatene.

Hvis du starter meme-søkeren, bør du nå ha rullbare GIF-er:

Rullbart søk

Legg til klikklyttere for å kopiere GIF-nettadresser for deling

Nå som vi kan se alle GIF-ene, vil vi kunne dele dem. En rask måte å gjøre dette på er å kopiere URL-en til det globale utklippstavlen når en bruker klikker på GIF-en etter eget valg.

Da kan brukeren bare navigere til stedet de vil bruke GIF og sette den inn Ctrl/Cmd + V.

For å gjøre det må vi:

  1. legg til en musen ned hendelseslytter til hver GIF
  2. inne i tilbakeringing av hendelseslytter, bruk QClipboard-klasse for å kopiere URL-en til det globale utklippstavlen
  3. vis en modal til brukeren som sier at URL-en er kopiert

Arrangementlytteren kan festes inne i getGifViews funksjon:

async function getGifViews(listOfGifs) { ... const promises = listOfGifs.map(async gif => { ... gifView.addEventListener(WidgetEventTypes.MouseButtonRelease, () => { const clipboard = QApplication.clipboard(); clipboard.setText(url, QClipboardMode.Clipboard); showModal( 'Copied to clipboard!', `You can press Cmd/Ctrl + V to paste the GIF url: ${url}` ); }); container.layout.addWidget(gifView); }); ... return container;
}

Her QApplication.clipboard returnerer et objekt for interaksjon med utklippstavlen. Vi kan bruke dette objektets setText metode for å endre innholdet på utklippstavlen.

Vi bruker også en showModal funksjon. La oss definere det neste:

function showModal(title, details) { const modal = new QMessageBox(); modal.setText(title); modal.setDetailedText(details); const okButton = new QPushButton(); okButton.setText('OK'); modal.addButton(okButton, ButtonRole.AcceptRole); modal.exec();
}

De QMessageBox-widget ligner på en varslingsboks i en nettleser. Den kan brukes til å stoppe brukerinteraksjon og vise en melding.

Til slutt må vi importere alle disse nye widgetene på toppen av src/index.js:

const { ButtonRole, FlexLayout, QApplication, QClipboardMode, QLabel, QLineEdit, QMainWindow, QMessageBox, QMovie, QPushButton, QScrollArea, QWidget, WidgetEventTypes,
} = require('@nodegui/nodegui');
const axios = require('axios').default;
const GIPHY_API_KEY = 'Your API key here'; async function searchGifs(searchTerm) { ... };
async function getGifViews(listOfGifs) { ... };
async function getMovie(url) { ... };
function createSearchContainer(onSearch) { ... };
function showModal(title, details) { ... }; const main = async () => { ... }; main().catch(console.error);

Hvis du starter meme-søkeren, bør du nå ha muligheten til å kopiere / lime inn GIF-URL-er:

Kopier GIF URL til utklippstavlen GIF

Legge til et ikon for systemskuffen

Vi vil at appen vår skal skjules i systemstatusfeltet når den ikke er i bruk. For dette oppretter vi et systemstatusfeltikon som vil ha et menyelement som, ved klikk, vil bytte synligheten til den kjørende widgeten.

Fremgangsmåten er:

  1. Lag en QSystemTrayIcon med et ikon.
  2. Opprett en meny for systemstatusfeltikonet ved hjelp av QMeny. Sett menyforekomsten som systemstatusfeltets hurtigmeny.
  3. Opprett menyelementer ved hjelp av QAction-småprogram og sette opp lyttere for begivenheter for å lytte etter sine trigger arrangementer.
  4. På utløseren, skjul eller vis vinduet.

La oss starte med å kreve de nødvendige modulene, og deretter gjøre en liten endring i main funksjon for å fortelle det å bruke ikonet vårt:

const { ButtonRole, FlexLayout, QApplication, QClipboardMode, QIcon, QLabel, QLineEdit, QMainWindow, QMenu, QMessageBox, QMovie, QAction, QPushButton, QScrollArea, QSystemTrayIcon, QWidget, WidgetEventTypes,
} = require('@nodegui/nodegui');
const axios = require('axios').default;
const path = require('path');
const iconImg = require('../assets/systray.png').default;
const GIPHY_API_KEY = 'Your API key here'; const main = async () => { ... win.show(); systemTrayIcon(win); global.win = win;
};

Som du kan se, krever vi et ikon fra assets mappe. Hvis du følger med, kan du last ned ikonfilen herfra.

Nå kommer funksjonen for å lage systemstatusfeltikonet:

function systemTrayIcon(win) { const icon = new QIcon(path.resolve(__dirname, iconImg)); const tray = new QSystemTrayIcon(); tray.setIcon(icon); tray.show(); // Menu that should pop up when clicking on systray icon. const menu = new QMenu(); tray.setContextMenu(menu); //Each item in the menu is called an action const visibleAction = new QAction(); menu.addAction(visibleAction); visibleAction.setText('Show/Hide'); visibleAction.addEventListener('triggered', () => { if (win.isVisible()) { win.hide(); } else { win.show(); } }); global.tray = tray;
}

Her oppretter vi ikonet ved hjelp av NodeGui QIcon-klasse. Så bruker vi QSystemTrayIcon klasse for å lage et systemstatusfeltikon for appen vår.

Til slutt må vi tilpasse innstillingene for webpack (i webpack.config.js) for å forhindre at webpack fylles ut __dirname:

const path = require('path'); module.exports = { ... node: {
- __dirname: true,
- __filename: true
+ __dirname: false,
+ __filename: false }, ...
}

Det endelige resultatet:

Den endelige søkemodulen

Noen Final Tweaks

Feilhåndtering

Før vi går videre til emballasje, la oss gjøre bruk av vår showModal funksjon og legg til en feilhåndteringsdialog:

const main = async () => { ... const searchContainer = createSearchContainer(async searchText => { try { ... } catch (err) { ... showModal('Something went wrong!', JSON.stringify(err)); } }); ...
};

Dette vil varsle brukeren hvis for eksempel noe går galt med Ajax-forespørselen om å hente GIF-er fra GIPHY. Du kan prøve dette ved å endre API-nøkkelen til noe ugyldig, deretter starte appen og prøve å søke etter en GIF.

Tillat brukeren å legge inn en API-nøkkel

Mens vi har temaet API-nøkler, la oss legge til en dialog som lar brukeren legge inn API-nøkkelen. Dette betyr at det ikke trenger å være hardkodet i programmet:

const { ... QDialog, ...
} = require('@nodegui/nodegui');
...
let GIPHY_API_KEY = ''; async function searchGifs(searchTerm) { ... }
async function getGifViews(listOfGifs) { ... }
async function getMovie(url) { ... }
function createSearchContainer(onSearch) { ... }
function showModal(title, details) { ... }
function systemTrayIcon(win) { ... } function showAPIKeyDialog() { const dialog = new QDialog(); dialog.setLayout(new FlexLayout()); const label = new QLabel(); label.setText('Enter your Giphy API Key'); const input = new QLineEdit(); const okButton = new QPushButton(); okButton.setText('OK'); okButton.addEventListener('clicked', () => { GIPHY_API_KEY = input.text(); dialog.close(); }); dialog.layout.addWidget(label); dialog.layout.addWidget(input); dialog.layout.addWidget(okButton); dialog.setInlineStyle(` padding: 10; height: 150px; flex-direction: 'column'; align-items:'center'; justify-content: 'space-around'; `); dialog.exec();
} const main = async () => { ... showAPIKeyDialog(); global.win = win;
}; main().catch(console.error);

Som du ser, bruker vi en QDialog widget for å be brukeren om innspill, og deretter lagre det de gir i GIPHY_API_KEY variabel. Hvis du ønsker å forbedre NodeGui-ferdighetene dine etter å ha lest denne opplæringen, kan du se på å forbedre dette - for eksempel ved å vedvare nøkkelen til filsystemet, eller validere den og gi tilbakemelding til brukeren.

Merk: Ikke glem, den komplette kildekoden er tilgjengelig her: https://github.com/sitepoint-editors/memesearchapp-nodegui-tutorial.

Pakking av appen for distribusjon på tvers av plattformer

Etter at vi har bygget appen, må vi lage distribuerbare produkter for macOS, Windows og Linux som sluttbrukerne kan laste ned og bruke.

Prosessen med å lage distribuerbare produkter er vanligvis forskjellig for hvert operativsystem, så for å lette smerten bruker vi NodeGuis emballeringsverktøy kalt @nodegui/packer.

bruk

Først installerer du pakker som avhengighetsavhengighet:

npm install --save-dev @nodegui/packer

Deretter bruker du pakker for å opprette en distribusjonsmal:

npx nodegui-packer --init MemeApp

Malen er egentlig et OS-spesifikt prosjekt som inneholder koden for å kunne pakke hele NodeGui-appens kode, eiendeler og avhengigheter. Merk at du må kjøre dette i Windows, macOS og Linux hver for seg for å lage tre forskjellige maler. Denne malen lar deg finjustere de endelige distribusjonsinnstillingene som er spesifikke for hvert operativsystem. Du kan justere ting som firmainformasjon, ikoner og andre metadata for å dekke dine behov.

For Linux ser malen slik ut:

.
└── deploy ├── config.json └── linux └── MemeApp ├── default.desktop ├── default.png └── qode.json

Merk at du bare trenger å kjøre init-kommandoen gang. Deretter gjør du endringer i malen og forplikter den i prosjektreposen.

Det neste trinnet er å faktisk bygge og pakke prosjektet til et distribuerbart.

Slett build katalog hvis den eksisterer:

rm -rf ./deploy/build

Bygg deretter appen ved hjelp av webpack:

npm run build

Til slutt kjører du pakke-kommandoen til pakken, og sender den dist mappe som argument:

npx nodegui-packer --pack ./dist

Dette vil resultere i følgende:

  • På macOS vil pakker sende ut a dmg filen.
  • På Linux vil packer sende ut en AppImage, som er noe som ligner på et .app filen i macOS.
  • På Windows sender pakker en mappe som inneholder den kjørbare filen og alle dll-ene.

Når kommandoen er vellykket, skal den skrive ut utdatakatalogen, som vanligvis er inne i deploy/<os>/build katalog. Vær sikker på at du ikke begå denne katalogen:

.
└── deploy ├── config.json └── linux ├── build │ └── MemeApp │ ├── Application-aed23d8-x86_64.AppImage │ ├── AppRun -> qode │ ├── default.desktop │ ├── default.png │ ├── dist │ │ ├── f59514675cec2e70ce8598286c94dc22.png │ │ ├── index.js │ │ └── nodegui_core-7b3e73f5fef149ae765d5ea5d13d5bb0.node │ ├── doc │ │ └── ... │ ├── lib │ │ └── ... │ ├── plugins │ │ └── ... │ ├── qode │ ├── qode.json │ └── qt.conf └── MemeApp ├── default.desktop ├── default.png └── qode.json

Distribuerbar Linux er deploy/linux/build/MemeApp/Application-aed23d8-x86_64.AppImage 🚀📦.

konklusjonen

I denne opplæringen bygde vi en meme-søkeapp fra den virkelige verden ved hjelp av NodeGui i omtrent 200 kodelinjer. Vi lærte noen av bibliotekets grunnleggende konsepter og evner. Vi var også i stand til å pakke den ferdige appen til en distribuerbar som kan deles med sluttbrukere.

Jeg tror NodeGui åpner døren for å lage mange virkelig effektive innfødte apper med Node.js.

NodeGui støtter også biblioteker og rammer som Reager (offisiell), Vinkel (fellesskap) og så videre Vue.js (fellesskap). Vennligst sjekk disse og gi dem en stjerne på GitHub hvis de er den slags ting du er interessert i.

NodeGui er et open source-bibliotek som vil drar stor nytte av kodebidrag. Den har en relativt enkel kodebase å forstå og et veldig imøtekommende samfunn. Jeg oppfordrer alle til å hjelpe til.

Til slutt, takket være deres mange innebygde widgets og styling gjennom CSS, tror jeg NodeGui-apper er like enkle å utvikle som nett- eller Electron-apper. Jeg oppfordrer deg til å lage noe kult av deg selv og dele det med oss.

Denne opplæringen er et utdrag fra SitePoint Premium-bibliotek, hvor du kan bygge et jobbklart Node.js-ferdighetssett.

Kilde: https://www.sitepoint.com/build-native-desktop-gif-searcher-app-using-nodegui/?utm_source=rss

spot_img

Siste etterretning

spot_img