Créer une application de recherche GIF de bureau natif à l'aide de NodeGui –
NodeGui est une bibliothèque open source pour la création d'applications de bureau natives multiplateformes avec Node.js. Les applications NodeGui peuvent s'exécuter sur macOS, Windows et Linux. Les applications construites avec NodeGui sont écrites à l'aide de JavaScript, stylisées en CSS et rendues en tant que widgets de bureau natifs en utilisant le framework Qt .
Certaines des fonctionnalités de NodeGui sont:
- widgets natifs avec intégré prise en charge du mode sombre
- style et empreinte mémoire faibles
- style CSS avec prise en charge complète de la mise en page Flexbox
- prise en charge complète de l'API Node.js et accès à tous les modules npm compatibles Node.js
- excellente prise en charge du débogage en utilisant DevTools de Chrome
- prise en charge TypeScript de première classe
NodeGui est alimenté par le cadre Qt, ce qui le rend efficace en termes de CPU et de mémoire par rapport à d'autres solutions basées sur Chromium telles qu'Electron. Cela signifie que les applications écrites à l'aide de NodeGui n'ouvrent pas une instance de navigateur et n'y rendent pas l'interface utilisateur. Au lieu de cela, tous les widgets sont rendus en mode natif.
Ce didacticiel montrera comment installer NodeGui et l'utiliser pour créer un moteur de recherche de mèmes qui réside dans la barre d'état système et communique avec l'API GIPHY .
Le code source complet de ce didacticiel est disponible sur GitHub .
Installation et configuration de base
Pour ce didacticiel, il est supposé que vous avez Node.js v12 ou une version ultérieure installée. Vous pouvez confirmer que Node et npm sont disponibles en exécutant:
# Cette commande doit imprimer la version de Node.js
noeud -v
# Cette commande devrait imprimer la version de npm
npm -v
Si vous avez besoin d'aide pour cette étape, consultez notre didacticiel sur l'installation de Node .
NodeGui nécessite des outils de compilation CMake et C ++ pour créer la couche C ++ native du projet. Assurez-vous d'installer CMake> = 3.1 avec un compilateur C ++ qui prend en charge C ++ 11 et versions ultérieures. Les instructions détaillées varient un peu selon votre système d'exploitation.
macOS
Il est recommandé d'installer CMake à l'aide de Homebrew. Exécutez les commandes suivantes dans un terminal après avoir installé Homebrew:
brew install cmake
brasser installer faire
Vous pouvez confirmer l'installation en exécutant:
# Cette commande doit imprimer la version de CMake qui doit être supérieure à 3.1
cmake --version
faire --version
Enfin, vous avez besoin de GCC / Clang pour compiler du code C ++. Vérifiez que GCC est installé à l'aide de cette commande:
gcc --version
Si vous n'avez pas installé GCC, assurez-vous d'installer Outils de ligne de commande pour Xcode ou Outils de développement XCode à partir de Page de développeur d'Apple . [196590255] ] Windows
Vous pouvez installer CMake sur Windows en téléchargeant la dernière version de la page de téléchargement de CMake .
Il est fortement recommandé d'utiliser Powershell comme terminal préféré dans Windows.
Vous pouvez confirmer l'installation de CMake en exécutant:
# Cette commande devrait imprimer la version de CMake qui devrait être supérieure à 3.1
cmake --version
Enfin, vous avez besoin d'un compilateur C ++. Une possibilité serait d'installer Visual Studio 2017 ou une version supérieure . Il est recommandé de choisir la charge de travail Développement de bureau avec C ++ pendant le processus d'installation.
Linux
Nous allons nous concentrer sur Ubuntu 18.04 pour les besoins de ce didacticiel. Il est recommandé d'installer CMake à l'aide du gestionnaire de packages. Exécutez les commandes suivantes dans un terminal:
sudo apt-get install pkg-config build-essential
sudo apt-get install cmake make
Vous pouvez confirmer l'installation en exécutant:
# Cette commande doit imprimer la version de CMake qui doit être supérieure à 3.1
cmake --version
faire --version
Enfin, vous avez besoin de GCC pour compiler du code C ++. Vérifiez que GCC est installé à l'aide de la commande:
# la version gcc doit être> = v7
gcc --version
Hello World
Afin de commencer avec notre application meme NodeGui, nous allons cloner le projet de démarrage.
Remarque: L'exécution de cette opération nécessite Git et npm.
Ouvrez un terminal et exécuter:
clone git https://github.com/nodegui/nodegui-starter memeapp
cd memeapp
installation de npm
npm start
Si tout se passe bien, vous devriez voir une application NodeGui Hello World fonctionnelle à l'écran.
Par défaut, le projet nodegui-starter est un projet TypeScript. Cependant, dans ce didacticiel, nous allons écrire notre application en JavaScript. Pour convertir notre démarreur en projet JS, nous apporterons les modifications mineures suivantes:
Supprimez le fichier
index.ts
dans le dossiersrc
.Créez un nouveau fichier
index.js
dans le répertoiresrc
avec le contenu suivant:src / index.js
const {QMainWindow, QLabel } = require ('@ nodegui / nodegui'); const win = new QMainWindow (); win.setWindowTitle ('Recherche Meme'); const label = new QLabel (); label.setText ('Bonjour tout le monde'); win.setCentralWidget (étiquette); win.show (); global.win = gagner;
En ce qui concerne le développement, une application NodeGui est essentiellement une application Node.js. Toutes les API et fonctionnalités présentes dans NodeGui sont accessibles via le module @ nodegui / nodegui
qui peut être requis comme tout autre module Node.js. De plus, vous avez accès à toutes les API Node.js et modules Node. NodeGui utilise des composants natifs au lieu de composants Web comme blocs de construction.
Dans l'exemple ci-dessus, nous avons importé QMainWindow et QLabel pour créer une fenêtre native qui affiche le texte "Bonjour tout le monde".
Réexécutez maintenant l'application:
npm start
Maintenant que notre configuration de base est prête, commençons à construire notre moteur de recherche de mèmes ?.
Remarque: Si quelque chose ne fonctionne pas en suivant ceci tutoriel, vérifiez votre fichier package.json
pour vous assurer que le projet de démarrage a extrait la version la plus récente de NodeGui.
Affichage d'un GIF animé
Les mèmes étant généralement des GIF animés , nous allons commencer par créer une fenêtre de base qui affiche une image GIF à partir d'une URL.
Pour ce faire, nous utiliserons QMovie avec QLabel. QMovie n'est pas un widget mais un conteneur qui peut jouer des animations simples. Nous l’utiliserons en combinaison avec QLabel.
Un exemple d’utilisation de QMovie ressemble à ceci:
const movie = new QMovie ();
movie.setFileName ('/ absolu / chemin / vers / animated.gif');
movie.start ();
const animatedLabel = new QLabel ();
animatedLabel.setMovie (film);
Étant donné que nous souhaitons charger une image à partir d'une URL, nous ne pouvons pas utiliser la méthode setFileName de
QMovie
qui est réservée uniquement aux fichiers locaux. Au lieu de cela, nous allons télécharger l'image GIF en utilisant axios comme tampon et utiliser à la place la méthode QMovie loadFromData .
Commençons donc par l'installation d'axios:
npm i axios
Créons maintenant une fonction qui prendra une URL comme paramètre et renverra une instance de QMovie
configurée pour le GIF:
fonction async getMovie (url) {
const {data} = attendre axios.get (url, {responseType: 'arraybuffer'});
const movie = new QMovie ();
movie.loadFromData (données);
movie.start ();
film de retour;
}
La fonction getMovie
prend une URL, indique à axios de télécharger le GIF en tant que tampon, puis utilise ce tampon pour créer une instance QMovie
.
Vous pouvez penser de QMovie
en tant que classe qui gère la logique interne de lecture de l'animation GIF image par image. QMovie
n'est pas un widget, il ne peut donc pas être affiché à l'écran tel quel. Au lieu de cela, nous utiliserons une instance régulière de QLabel
et lui définirons QMovie
.
Puisque getMovie
renvoie une promesse, nous devons apporter quelques modifications à le code. Après quelques modifications mineures, nous nous retrouvons avec ce qui suit:
src / index.js
const {QMainWindow, QMovie, QLabel} = require ('@ nodegui / nodegui');
const axios = require ('axios'). default;
fonction asynchrone getMovie (url) {
const {data} = attendre axios.get (url, {responseType: 'arraybuffer'});
const movie = new QMovie ();
movie.loadFromData (données);
movie.start ();
film de retour;
}
const main = async () => {
const win = new QMainWindow ();
win.setWindowTitle ('Recherche Meme');
const label = new QLabel ();
const gifMovie = attendre getMovie (
«https://upload.wikimedia.org/wikipedia/commons/e/e3/Animhorse.gif»
);
label.setMovie (gifMovie);
win.setCentralWidget (étiquette);
win.show ();
global.win = gagner;
};
main (). catch (console.error);
La fonction principale
est notre point d'entrée. Ici, nous créons une fenêtre et une étiquette. Nous instancions ensuite une instance de QMovie
à l'aide de notre fonction getMovie
puis définissons le QMovie
sur un QLabel
.
Exécutez l'application avec npm start
et vous devriez voir quelque chose comme ceci:
Récupération de GIF à partir de l'API GIPHY
Giphy.com a un API publique que tout le monde peut utiliser pour créer de superbes applications qui utilisent des GIF animés. Pour utiliser l'API GIPHY, vous devez vous enregistrer sur developers.giphy.com et obtenir une clé API. Vous pouvez trouver des instructions supplémentaires ici .
Nous utiliserons la fonction de point final de recherche pour implémenter notre recherche de mèmes.
Commençons par écrire un searchGifs
fonction qui prendra un paramètre searchTerms
comme entrée et demande des GIF en utilisant le point de terminaison ci-dessus:
const GIPHY_API_KEY = 'Votre clé API ici';
fonction asynchrone searchGifs (searchTerm) {
const url = 'https://api.giphy.com/v1/gifs/search';
const res = attendre axios.get (url, {
params: {
api_key: GIPHY_API_KEY,
limite: 25,
q: searchTerm,
lang: 'en',
décalage: 0,
évaluation: 'pg-13'
}
});
return res.data.data;
}
Le résultat de la fonction après exécution ressemblera à ceci:
[
{
"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",
...
},
...
]
Le résultat est essentiellement un tableau d'objets qui contiennent des informations sur chaque GIF. Nous sommes particulièrement intéressés par returnValue [i] .images.fixed_width_small.url
pour chaque image, qui contient l'URL du GIF.
Affichage d'une liste de GIF à l'aide de la réponse de l'API
Dans afin d'afficher une liste de GIF, nous allons créer une fonction getGifViews
qui:
- créera un conteneur QWidget
- créera un widget
QMovie
pour chaque GIF - créez un
QLabel
à partir de chaqueQMovie
instance - attachez chaque
QLabel
en tant qu'enfant du conteneurQWidget
- renvoie le conteneur
QWidget
Le code ressemble à ceci:
fonction asynchrone 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 = attendre getMovie (url);
const gifView = new QLabel ();
gifView.setMovie (film);
gifView.setInlineStyle (`largeur: $ {largeur}`);
container.layout.addWidget (gifView);
});
attendre Promise.all (promesses);
container.setInlineStyle (`
flex-direction: 'rangée';
flex-wrap: «wrap»;
justifier-contenu: «espace autour»;
largeur: 330 px;
hauteur: 300px;
');
conteneur de retour;
}
Décomposons cela un peu.
Tout d'abord, nous créons notre widget conteneur. Les QWidget
sont essentiellement des widgets vides qui agissent comme des conteneurs. Ils sont similaires aux éléments
Ensuite, pour attribuer des widgets enfants au QWidget
nous devons lui donner une disposition. Une disposition dicte comment les widgets enfants doivent être disposés à l'intérieur d'un parent. Ici, nous choisissons FlexLayout .
Ensuite, nous utilisons notre fonction getMovie
pour créer une instance QMovie
pour chaque URL GIF. Nous attribuons l'instance QMovie
à une QLabel
(nommée gifView
) et lui donnons un style de base à l'aide de la méthode setInlineStyle
. Enfin, nous ajoutons le widget QLabel
à la disposition du conteneur à l'aide de la méthode layout.addWidget
.
Comme tout se passe de manière asynchrone, nous attendons que tout se résout à l'aide de Promise.all
avant de définir certains styles de conteneur et de renvoyer le widget conteneur.
Modifions maintenant notre fonction principale
afin de voir la liste des widgets que nous avons préparés.
src / index.js
const {FlexLayout, QLabel, QMainWindow, QMovie, QWidget} = require ('@ nodegui / nodegui');
const axios = require ('axios'). default;
const GIPHY_API_KEY = 'Votre clé API ici';
fonction asynchrone getMovie (url) {...}
fonction asynchrone searchGifs (searchTerm) {...}
fonction asynchrone getGifViews (listOfGifs) {...}
const main = async () => {
const win = new QMainWindow ();
win.setWindowTitle ('Recherche Meme');
const center = new QWidget ();
center.setLayout (nouveau FlexLayout ());
// Nous obtenons la liste des gifs ici
const listOfGifs = attendre searchGifs ('bonjour');
// Nous créons le conteneur avec des widgets de vue GIF
const container = wait getGifViews (listOfGifs);
// On attache enfin le conteneur au widget
center.layout.addWidget (conteneur);
win.setCentralWidget (centre);
win.show ();
global.win = gagner;
};
main (). catch (console.error);
Si vous exécutez le projet après avoir apporté ces modifications, vous devriez voir:
Génial! Maintenant, ajoutons un champ de saisie de recherche avec un bouton, afin que les utilisateurs puissent rechercher autre chose que des "bonjour" GIF.
Ajout d'une entrée de recherche et d'un bouton
Commençons par créer un createSearchContainer
qui acceptera une fonction de rappel comme paramètre. Ceci sera appelé lorsque le bouton de recherche sera cliqué.
Voici ce que la fonction devrait faire:
- créer un
QWidget
conteneur, auquel nous ajouterons un champ de saisie de recherche et un bouton en tant qu'enfants [19659004] créer une disposition et l'attacher au conteneur - créer une entrée et un bouton de recherche, puis les attacher au
FlexLayout
- attacher un écouteur d'événements au bouton qui, lorsque vous cliquez dessus, appellera la fonction de rappel
onSearch
en lui passant le texte présent dans le champ de saisie de texte - renvoie le conteneur
QWidget
Le code ressemble à ceci:
fonction createSearchContainer (onSearch ) {
const searchContainer = new QWidget ();
searchContainer.setObjectName ('searchContainer');
searchContainer.setLayout (nouveau FlexLayout ());
const searchInput = new QLineEdit ();
searchInput.setObjectName ('searchInput');
const searchButton = new QPushButton ();
searchButton.setObjectName ('searchButton');
searchButton.setText ('?');
searchButton.addEventListener ('cliqué', () => {
onSearch (searchInput.text ());
});
searchContainer.layout.addWidget (searchInput);
searchContainer.layout.addWidget (searchButton);
searchContainer.setStyleSheet (`
#searchContainer {
flex-direction: 'rangée';
rembourrage: 10px;
align-items: 'center';
}
#searchInput {
flex: 1;
hauteur: 40px;
}
#searchButton {
marge gauche: 5px;
largeur: 50 px;
hauteur: 35px;
}
');
return searchContainer;
}
J'espère que vous avez une bonne idée de ce qui se passe ici, mais une nouvelle chose à noter est la méthode setStyleSheet . Vous pouvez penser à cela comme un moyen d'appliquer du CSS de niveau bloc en une seule fois. C'est très similaire aux feuilles de style globales sur le Web, mais avec la différence que dans NodeGui / Qt une feuille de style peut être attachée à n'importe quel bloc et pas seulement globalement.
Afin de styliser un widget en utilisant une feuille de style, nous devons ajouter un objectName
à un widget, que nous utiliserons pour le référencer dans la feuille de style. Ceci est à peu près identique à un id
dans le monde du Web. Pour définir un objectName
nous utiliserons la méthode setObjectName
.
Ajoutons maintenant searchContainer
à la fenêtre principale.
src / index.js
const {
FlexLayout,
QLabel,
QLineEdit,
QMainWindow,
QMovie,
QPushButton,
QWidget,
} = require ('@ nodegui / nodegui');
const axios = require ('axios'). default;
const GIPHY_API_KEY = 'Votre clé API ici';
fonction asynchrone getMovie (url) {...}
fonction asynchrone searchGifs (searchTerm) {...}
fonction asynchrone getGifViews (listOfGifs) {...}
fonction createSearchContainer (onSearch) {...}
const main = async () => {
const win = new QMainWindow ();
win.setWindowTitle ('Recherche Meme');
const center = new QWidget ();
center.setLayout (nouveau FlexLayout ());
// Ici, nous créons le conteneur de recherche
const searchContainer = createSearchContainer (searchText => {
console.log ('searchText:', searchText);
});
// Ici, nous l'ajoutons au widget central avant d'ajouter la liste des GIF.
center.layout.addWidget (searchContainer);
const listOfGifs = attendre searchGifs ('bonjour');
const container = wait getGifViews (listOfGifs);
center.layout.addWidget (conteneur);
win.setCentralWidget (centre);
win.show ();
global.win = gagner;
};
main (). catch (console.error);
Maintenant, lorsque vous lancez l'application et entrez quelque chose dans le champ de recherche, vous devriez voir tout ce que vous avez recherché connecté à votre terminal.
Connexion de la recherche à la Vue GIF
Pour charger de nouveaux GIF en réponse à la recherche d'un utilisateur, nous devons procéder comme suit:
- Dans le rappel qui est déclenché lorsque le bouton de recherche est cliqué, saisissez le texte de la recherche et utilisez
searchGifs
pour obtenir une nouvelle liste de GIF. - Créez un nouveau conteneur pour ces GIF à l'aide de la fonction
getGifViews
. - Supprimez le conteneur existant de la fenêtre.
- Ajoutez le nouveau
Si nous mélangeons un peu les choses, nous obtenons:
const main = async () => {
const win = new QMainWindow ();
win.setWindowTitle ('Recherche Meme');
const center = new QWidget ();
center.setLayout (nouveau FlexLayout ());
laissez container = new QWidget ();
const searchContainer = createSearchContainer (async searchText => {
essayez {
// Créer un nouveau conteneur GIF avec de nouveaux GIF
const listOfGifs = attendre searchGifs (searchText);
const newGifContainer = attendre getGifViews (listOfGifs);
// Supprimer le conteneur existant de la fenêtre
center.layout.removeWidget (conteneur);
container.close ();
// Ajout du nouveau conteneur GIF à la fenêtre
center.layout.addWidget (newGifContainer);
container = newGifContainer;
} catch (err) {
console.error ('Quelque chose s'est passé!', err);
}
});
center.layout.addWidget (searchContainer);
win.setCentralWidget (centre);
win.show ();
global.win = gagner;
};
Exécutons-le à nouveau et voyons la magie ?♂️.
Comme vous pouvez le voir, lorsque vous tapez quelque chose dans la zone de recherche et appuyez sur le bouton de recherche, notre widget récupérera une liste de GIF correspondant au terme de recherche à partir de l'API GIPHY.
Alors que tout va dans la bonne direction, vous avez probablement remarqué que la liste des GIF est coupée en bas et il n'y a aucun moyen de faites-les défiler. En effet, nous utilisons un conteneur QWidget
pour les afficher. Pour faire défiler le conteneur, nous devons remplacer le QWidget
par un QScrollArea . Cela donne une vue défilante sur un autre widget.
Nous allons commencer par supprimer la propriété height
dans la fonction getGifViews
:
fonction async getGifViews (listOfGifs) {
...
container.setInlineStyle (`
flex-direction: 'rangée';
flex-wrap: «wrap»;
justifier-contenu: «espace autour»;
largeur: 330 px;
- hauteur: 300px;
');
conteneur de retour;
}
Ensuite, nous devons changer src / index.js
pour qu'il ressemble à ceci:
const {
FlexLayout,
QLabel,
QLineEdit,
QMainWindow,
QMovie,
QPushButton,
QScrollArea,
QWidget,
} = require ('@ nodegui / nodegui');
const axios = require ('axios'). default;
const GIPHY_API_KEY = 'Votre clé API ici';
fonction asynchrone getMovie (url) {...}
fonction asynchrone searchGifs (searchTerm) {...}
fonction asynchrone getGifViews (listOfGifs) {...}
fonction createSearchContainer (onSearch) {...}
const main = async () => {
const win = new QMainWindow ();
win.setWindowTitle ('Recherche Meme');
const center = new QWidget ();
center.setLayout (nouveau FlexLayout ());
const scrollArea = new QScrollArea ();
scrollArea.setWidgetResizable (false);
scrollArea.setInlineStyle ('flex: 1; largeur: 350px; hauteur: 400px;');
const searchContainer = createSearchContainer (async searchText => {
essayez {
const listOfGifs = attendre searchGifs (searchText);
const newGifContainer = attendre getGifViews (listOfGifs);
// Supprimer le conteneur existant de scrollArea
const oldContainer = scrollArea.takeWidget ();
if (oldContainer) oldContainer.close ();
// Ajout du nouveau conteneur GIF à scrollArea
scrollArea.setWidget (newGifContainer);
} catch (err) {
console.error ('Quelque chose s'est passé!', err);
}
});
center.layout.addWidget (searchContainer);
center.layout.addWidget (scrollArea);
win.setCentralWidget (centre);
win.show ();
global.win = gagner;
};
main (). catch (console.error);
Il n'y a rien de trop excitant ici. Nous créons un nouveau QScrollArea
que nous ajoutons à la mise en page sous le champ de recherche. Nous utilisons également la méthode takeWidget de QScrollArea
pour supprimer tout conteneur existant de la zone de défilement, avant d'ajouter les nouveaux résultats de recherche.
Si vous lancez le moteur de recherche de mèmes, vous devriez maintenant avoir des GIF défilants:
Ajouter des écouteurs Cliquez pour copier les URL GIF pour le partage
Maintenant que nous pouvons voir tous les GIF, nous voulons pouvoir les partager. Une façon rapide de le faire est de copier l'URL dans le presse-papiers global chaque fois qu'un utilisateur clique sur le GIF de son choix.
Ensuite, l'utilisateur peut simplement naviguer jusqu'à l'endroit où il souhaite utiliser le GIF et l'insérer avec Ctrl / Cmd + V .
Pour ce faire, nous devons:
- attacher un écouteur d'événements souris vers le bas à chaque GIF
- à l'intérieur du rappel de l'écouteur d'événements, utilisez la classe QClipboard pour copier l'URL dans le presse-papiers global
- affiche un modal à l'utilisateur disant que l'URL a été copiée
L'écouteur d'événements peut être attaché à l'intérieur la fonction getGifViews
:
fonction asynchrone getGifViews (listOfGifs) {
...
const promises = listOfGifs.map (async gif => {
...
gifView.addEventListener (WidgetEventTypes.MouseButtonRelease, () => {
const clipboard = QApplication.clipboard ();
clipboard.setText (url, QClipboardMode.Clipboard);
showModal (
'Copié dans le presse-papier!',
`Vous pouvez appuyer sur Cmd / Ctrl + V pour coller l'URL GIF: $ {url}`
);
});
container.layout.addWidget (gifView);
});
...
conteneur de retour;
}
Ici, QApplication.clipboard renvoie un objet pour interagir avec le presse-papiers. Nous pouvons utiliser la méthode setText
de cet objet pour modifier le contenu réel du presse-papiers.
Nous utilisons également une fonction showModal
. Définissons cela ensuite:
fonction showModal (titre, détails) {
const modal = new QMessageBox ();
modal.setText (titre);
modal.setDetailedText (détails);
const okButton = new QPushButton ();
okButton.setText ('OK');
modal.addButton (okButton, ButtonRole.AcceptRole);
modal.exec ();
}
Le widget QMessageBox est similaire à une boîte d'alerte dans un navigateur Web. Il peut être utilisé pour arrêter l'interaction de l'utilisateur et afficher un message.
Enfin, nous devons importer tous ces nouveaux widgets en haut de 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 = 'Votre clé API ici';
fonction asynchrone searchGifs (searchTerm) {...};
fonction asynchrone getGifViews (listOfGifs) {...};
fonction asynchrone getMovie (url) {...};
function createSearchContainer (onSearch) {...};
fonction showModal (titre, détails) {...};
const main = async () => {...};
main (). catch (console.error);
Si vous lancez le moteur de recherche de meme, vous devriez maintenant avoir la possibilité de copier / coller des URL GIF:
Ajouter une icône de barre d'état système
Nous voulons notre application à cacher dans la barre d'état système lorsqu'elle n'est pas utilisée. Pour cela, nous allons créer une icône de barre d'état système qui aura un élément de menu qui, au clic, basculera la visibilité du widget en cours d'exécution.
Les étapes impliquées sont:
- Créez un QSystemTrayIcon avec une icône.
- Créez un menu pour l'icône de la barre d'état système à l'aide de QMenu . Définissez l'instance de menu comme menu contextuel de la barre d'état système.
- Créez des éléments de menu à l'aide de Widgets QAction et configurez des écouteurs d'événements pour écouter leurs événements de déclenchement
- Sur déclenchement, masquez ou afficher la fenêtre.
Commençons par exiger les modules nécessaires, puis modifions légèrement la fonction principale
pour lui dire d'utiliser notre icône:
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 = 'Votre clé API ici';
const main = async () => {
...
win.show ();
systemTrayIcon (win);
global.win = gagner;
};
Comme vous pouvez le voir, nous avons besoin d'une icône dans le dossier actifs
. Si vous suivez la suite, vous pouvez télécharger le fichier icône à partir d'ici .
Vient maintenant la fonction pour créer l'icône de la barre d'état système:
function systemTrayIcon (win) {
const icon = new QIcon (path.resolve (__ dirname, iconImg));
const tray = new QSystemTrayIcon ();
tray.setIcon (icône);
tray.show ();
// Menu qui devrait apparaître lorsque vous cliquez sur l'icône de la barre d'état système.
menu const = nouveau QMenu ();
tray.setContextMenu (menu);
// Chaque élément du menu est appelé une action
const visibleAction = new QAction ();
menu.addAction (visibleAction);
visibleAction.setText ('Afficher / Masquer');
visibleAction.addEventListener ('triggered', () => {
if (win.isVisible ()) {
win.hide ();
} autre {
win.show ();
}
});
global.tray = plateau;
}
Ici, nous créons l'icône en utilisant la classe QIcon de NodeGui . Ensuite, nous utilisons la classe QSystemTrayIcon
pour créer une icône de barre d'état système pour notre application.
Enfin, nous devons modifier nos paramètres de webpack (dans webpack.config.js
) pour empêcher le webpack de polyfilling __ dirname
:
const path = require ('path');
module.exports = {
...
nœud: {
- __dirname: true,
- __filename: true
+ __dirname: false,
+ __nom de fichier: faux
},
...
}
Le résultat final:
Quelques ajustements finaux
Gestion des erreurs
Avant de passer à l'emballage, utilisons notre showModal
et ajoutez une boîte de dialogue de gestion des erreurs:
const main = async () => {
...
const searchContainer = createSearchContainer (async searchText => {
essayez {
...
} catch (err) {
...
showModal ('Quelque chose s'est mal passé!', JSON.stringify (err));
}
});
...
};
Cela alertera l'utilisateur si, par exemple, quelque chose ne va pas avec la demande Ajax pour récupérer les GIF de GIPHY. Vous pouvez essayer cela en modifiant votre clé API en quelque chose de non valide, puis en lançant l'application et en tentant de rechercher un GIF.
Autoriser l'utilisateur à saisir une clé API
Pendant que nous parlons de clés API, ajoutons une boîte de dialogue pour permettre à un utilisateur d'entrer sa clé API. Cela signifie qu'il n'a pas besoin d'être codé en dur dans le programme:
const {
...
QDialog,
...
} = require ('@ nodegui / nodegui');
...
laissez GIPHY_API_KEY = '';
fonction asynchrone searchGifs (searchTerm) {...}
fonction asynchrone getGifViews (listOfGifs) {...}
fonction asynchrone getMovie (url) {...}
fonction createSearchContainer (onSearch) {...}
fonction showModal (titre, détails) {...}
fonction systemTrayIcon (win) {...}
fonction showAPIKeyDialog () {
const dialog = new QDialog ();
dialog.setLayout (new FlexLayout ());
const label = new QLabel ();
label.setText ('Entrez votre clé API Giphy');
const input = new QLineEdit ();
const okButton = new QPushButton ();
okButton.setText ('OK');
okButton.addEventListener ('clicked', () => {
GIPHY_API_KEY = input.text ();
dialog.close ();
});
dialog.layout.addWidget (étiquette);
dialog.layout.addWidget (entrée);
dialog.layout.addWidget (okButton);
dialog.setInlineStyle (`
rembourrage: 10;
hauteur: 150px;
flex-direction: «colonne»;
align-items: 'center';
justifier-contenu: «espace autour»;
');
dialog.exec ();
}
const main = async () => {
...
showAPIKeyDialog ();
global.win = gagner;
};
main (). catch (console.error);
Comme vous pouvez le voir, nous utilisons un widget QDialog
pour inviter l'utilisateur à entrer des données, puis stockant tout ce qu'il fournit dans la variable GIPHY_API_KEY
. Si vous cherchez à améliorer vos compétences NodeGui après avoir lu ce didacticiel, vous pouvez envisager d'améliorer cela - par exemple, en conservant la clé du système de fichiers, ou en la validant et en fournissant des commentaires à l'utilisateur.
Remarque: N'oubliez pas, le code source complet est disponible ici: https://github.com/sitepoint-editors/memesearchapp-nodegui-tutorial .
Conditionnement de l'application pour la distribution multiplateforme
Après avoir créé l'application avec succès, nous devons créer des distributables pour macOS, Windows et Linux que les utilisateurs finaux peuvent télécharger et utiliser.
Le processus de création de distributables est généralement différent pour chaque système d'exploitation, donc pour soulager la douleur, nous utiliserons l'outil de packaging de NodeGui appelé @ nodegui / packer
.
Utilisation
Premièrement, installez packer comme dépendance de dev:
npm install --save-dev @nodegui /emballeur
Ensuite, utilisez le packer pour créer un modèle de déploiement:
npx nodegui-packer --init MemeApp
The template is essentially an OS-specific project that contains the code to successfully package all of NodeGui app’s code, assets and dependencies. Note that you need to run this in Windows, macOS and Linux separately to create three different templates. This template allows you to fine tune the final deployment settings specific to each OS. You can adjust things like company info, icons and other metadata to suit your needs.
For Linux, the template looks like this:
.
└── deploy
├── config.json
└── linux
└── MemeApp
├── default.desktop
├── default.png
└── qode.json
Note that you only need to run the init command once. Then you make changes to the template and commit it in the project repo.
The next step is to actually build and package the project into a distributable.
Delete the build
directory if it exists:
rm -rf ./deploy/build
Then build the app using webpack:
npm run build
Finally, run the packer’s pack command, passing it the dist
folder as an argument:
npx nodegui-packer --pack ./dist
This will result in the following:
- On macOS, packer will output a
dmg
file. - On Linux, packer will output an
AppImage
which is something similar to an.app
file in macOS. - On Windows, packer outputs a folder containing the executable and all the dlls.
Once the command is successful, it should print the output directory, which is typically inside the deploy/
directory. Make sure you don’t commit this directory:
.
└── 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
The Linux distributable is deploy/linux/build/MemeApp/Application-aed23d8-x86_64.AppImage
??.
Conclusion
In this tutorial, we successfully built a real-world meme search app using NodeGui in roughly 200 lines of code. We learned some of the library’s basic concepts and capabilities. We also were able to package the finished app into a distributable that can be shared with end users.
I believe NodeGui opens the door to create a lot of truly efficient native apps with Node.js.
NodeGui also supports libraries and frameworks such as React (official)Angular (community) and soon Vue.js (community). Please check these out and give them a star on GitHub if they’re the sort of thing you’re interested in.
NodeGui is an open-source library that will greatly benefit from code contributions. It has a relatively easy codebase to understand and a very welcoming community. I encourage everyone to help out.
Finally, thanks to their many inbuilt widgets and styling through CSS, I believe NodeGui apps are as easy to develop as web or Electron apps. I encourage you to build something cool of your own and share it with us.
This tutorial is an excerpt from the SitePoint Premium librarywhere you can build a job-ready Node.js skillset.
Source link