Electron : les dialogues

Dans ce cinquième article sur Electron on va voir comment créer des dialogues pour par exemple naviguer dans les dossiers pour ouvrir ou enregistrer un fichier ou afficher une information pour l’utilisateur.

Je rappelle qu’on part de la base de cette application d’exemple. Je parle dans cet article de la manière de l’installer.

Ouvrir la fenêtre d’ouverture des dossiers et fichiers

Pour la plupart des applications il est nécessaire d’accéder aux fichiers locaux et tous les systèmes le permettent. Node est équipé du module fs (File System) pour tout ce qui concerne les accès aux fichiers. On a deux façons de procéder : de façon synchrone ou asynchrone.

Je ne détaille pas dans cet article la gestion des fichiers avec Node parce que c’est un sujet un peu à part d’Electron. Hormis la documentation officielle assez détaillée vous pouvez trouver de nombreux tutoriels sur le sujet, par exemple cette introduction, ou ce tuto de base.

Au niveau des API d’Electron on va utiliser le module dialog. On trouve dans ce module plusieurs méthodes dont showOpenDialog qu’on va utiliser à présent.

Processus principal (main process)

On va donc déclarer dans main.js le module dialog mais également le module ipcMain qu’on a déjà utilisé dans le précédent article qui permet de faire communiquer les deux processus :

const app = electron.app
const ipc = electron.ipcMain
const dialog = electron.dialog

Ensuite on met en place l’écoute de l’événement :

ipc.on('open-file-dialog', function (event) {
  dialog.showOpenDialog({
    properties: ['openFile']
  }, function (files) {
    if (files) event.sender.send('selectedElement', files)
  })
})

On attend donc de recevoir open-file-dialog du processus de rendu, on ouvre alors la boîte de dialogue avec showOpenDialog. Au niveau des propriétés on a le choix en particulier entre (vous avez les liste complète dans la documentation) :

  • openFile : on peut sélectionner un fichier
  • openDirectory : on peut sélectionner un dossier
  • multiSelections : on peut sélectionner plusieurs éléments

Si on a une sélection alors on répond au processus de rendu en lui indiquant ce qui a été effectivement sélectionné.

Processus de rendu

On va ajouter dans la page index.html un bouton pour déclencher l’ouverture de la boîte de dialogue et une balise pour récupérer le fichier sélectionné :

<button id="select">Choisir un fichier</button>
<p id="selected"></p>

Dans renderer.js on commence par déclarer le module ipcRenderer :

const ipc = require('electron').ipcRenderer

Ensuite on renseigne une constante en pointant le bouton grâce à son identifiant :

const selectBtn = document.getElementById('select')

Et si on clique sur le bouton on envoie l’information au processus principal (main process) :

selectBtn.addEventListener('click', function (event) {
  ipc.send('open-file-dialog')
})

Enfin on met en place l’écoute de la réponse du processus principal pour afficher le fichier sélectionné :

ipc.on('selectedElement', function (event, path) {
  document.getElementById('selected').innerHTML = 'Vous avez sélectionné : ' + path
})

Quand on démarre l’application on a donc cet affichage :

Ce n’est pas très sexy mais on s’intéressera plus tard à l’aspect esthétique qui est en fait seulement du traitement classique CSS.

Quand on clique sur le bouton on a l’ouverture de la boîte de dialogue et on peut naviguer et sélectionner un fichier :

Et quand on valide on a bien le retour avec le chemin du fichier sélectionné :

Les options

On dispose de plusieurs options dont 3 qui me semblent bien pratiques :

  • title : pour préciser le titre de la boîte
  • defaultPath: pour le chemin par défaut
  • buttonLabel: le texte du bouton de confirmation

Par exemple :

ipc.on('open-file-dialog', function (event) {
  dialog.showOpenDialog({
    title: 'Selectionnez le fichier du processus principal',
    properties: ['openFile'],
    defaultPath: 'E:\\laragon\\www\\electron',
    buttonLabel: "Valider"
  }, function (files) {
    if (files) event.sender.send('selectedElement', files)
  })
})

Ouvrir la fenêtre d’enregistrement des fichiers

Après l’ouverture voyons l’enregistrement qui en est la réciproque. On va retrouver le même principe de codage.

Cette fois on va utiliser la méthode showSaveDialog.

Processus principal (main process)

On va donc déclarer dans main.js les modules dialog et ipcMain :

const app = electron.app
const ipc = electron.ipcMain
const dialog = electron.dialog

Ensuite on met en place l’écoute de l’événement :

ipc.on('save-dialog', function (event) {
  const options = {
    title: 'Enregistrer une image',
    filters: [
      { name: 'Images', extensions: ['jpg', 'png', 'gif'] }
    ]
  }
  dialog.showSaveDialog(options, function (filename) {
    event.sender.send('saved-file', filename)
  })
})

On prévoit des filtres (filters) pour les extensions autorisées.

On attend donc de recevoir save-dialog du processus de rendu, on ouvre alors la boîte de dialogue avec showSaveDialog.

Processus de rendu

On va ajouter dans la page index.html un bouton pour déclencher l’ouverture de la boîte de dialogue et une balise pour récupérer le chemin sélectionné :

<button id="save">Enregistrer...</button>
<p id="selected"></p>

Dans renderer.js on commence par déclarer le module ipcRenderer :

const ipc = require('electron').ipcRenderer

Ensuite on renseigne une constante en pointant le bouton grâce à son identifiant :

const saveBtn = document.getElementById('save')

Et si on clique sur le bouton on envoie l’information au processus principal (main process) :

saveBtn.addEventListener('click', function (event) {
  ipc.send('save-dialog')
})

Enfin on met en place l’écoute de la réponse du processus principal pour afficher le chemin complet :

ipc.on('saved-file', function (event, path) {
  if (!path) path = 'Pas de chemin'
  document.getElementById('selected').innerHTML = 'Chemin : ' + path
})

Quand on démarre l’application on a donc cet affichage :

Quand on clique sur le bouton on a l’ouverture de la boîte de dialogue et on peut naviguer, sélectionner un dossier et entrer un nom de fichier :

Et quand on valide on a bien le retour avec le chemin du fichier sélectionné :

Un message d’information

On peut aussi afficher un simple message d’information.

Cette fois on va utiliser la méthode showMessageBox.

Processus principal (main process)

On va encore déclarer dans main.js les module dialog et ipcMain :

const app = electron.app
const ipc = electron.ipcMain
const dialog = electron.dialog

Ensuite on met en place l’écoute de l’événement :

ipc.on('open-information-dialog', function (event) {
  const options = {
    type: 'info',
    title: 'Information',
    message: "Un petit message pour ne rien dire...",
    buttons: ['Oui', 'Non']
  }
  dialog.showMessageBox(options, function (index) {
    event.sender.send('information-dialog-selection', index)
  })
})

On dispose de ces 5 types :

  • none
  • info
  • error
  • question
  • warning

On attend donc de recevoir open-information-dialog du processus de rendu, on ouvre alors la boîte de dialogue avec showMessageBox.

Processus de rendu

On va ajouter dans la page index.html un bouton pour déclencher l’ouverture de la boîte de dialogue et une balise pour récupérer la réponse au message :

<button id="open">Afficher le message</button>
<p id="info-selection"></p>

Dans renderer.js on commence par déclarer le module ipcRenderer :

const ipc = require('electron').ipcRenderer

Ensuite on renseigne une constante en pointant le bouton grâce à son identifiant :

const informationBtn = document.getElementById('open')

Et si on clique sur le bouton on envoie l’information au processus principal (main process) :

informationBtn.addEventListener('click', function (event) {
  ipc.send('open-information-dialog')
})

Enfin on met en place l’écoute de la réponse du processus principal pour afficher le message :

ipc.on('information-dialog-selection', function (event, index) {
  let message = 'You selected '
  if (index === 0) message += 'yes.'
  else message += 'no.'
  document.getElementById('info-selection').innerHTML = message
})

L’index qu’on reçoit au retour est celui du bouton sélectionné.

Quand on démarre l’application on a donc cet affichage :

Quand on clique sur le bouton on a l’ouverture de la boîte de message :

Et quand on clique on a bien le retour avec le bouton choisi :

Vous avez le choix de l’apparence, par exemple :

ipc.on('open-information-dialog', function (event) {
  const options = {
    type: 'error',
    title: 'Création',
    message: "Réellement créer cette sauvegarde ?",
    buttons: ['Oui créer', 'Non surtout pas !']
  }
  dialog.showMessageBox(options, function (index) {
    event.sender.send('information-dialog-selection', index)
  })
})

Une icône personnalisée

Si les icônes standard ne vous conviennent pas vous pouvez très bien imposer les vôtres. Par exemple créez un dossier avec une icône :

Dans main.js commencez par déclarer le module nativeImage :

const nativeImage = electron.nativeImage

Ensuite créez l’image avec createFromPath :

let dangerIcon = nativeImage.createFromPath('images/danger.png')

Enfin déclarez cette image dans les options :

ipc.on('open-information-dialog', function (event) {
  const options = {
    ...
    icon: dangerIcon
  }
  dialog.showMessageBox(options, function (index) {
    event.sender.send('information-dialog-selection', index)
  })
})

Les messages d’erreur

Il nous reste plus à voir le plus simple : les messages d’erreur. Cette fois ça sera avec la méthode showErrorBox qui dispose de très peu d’option.

Processus principal (main process)

On va encore déclarer dans main.js les modules dialog et ipcMain :

const app = electron.app
const ipc = electron.ipcMain
const dialog = electron.dialog

Ensuite on met en place l’écoute de l’événement :

ipc.on('open-error-dialog', function (event) {
  dialog.showErrorBox('Un message d\'erreur', 'Vous avez fait une erreur monumentale !')
})

On attend donc de recevoir open-error-dialog du processus de rendu, on ouvre alors la boîte de dialogue avec showErrorBox.

Processus de rendu

On va ajouter dans la page index.html un bouton pour déclencher l’ouverture de la boîte de dialogue :

<button id="error">Afficher le message</button>

Dans renderer.js on commence par déclarer le module ipcRenderer :

const ipc = require('electron').ipcRenderer

Ensuite on renseigne une constante en pointant le bouton grâce à son identifiant :

const errorBtn = document.getElementById('error')

Et si on clique sur le bouton on envoie l’information au processus principal (main process) :

errorBtn.addEventListener('click', function (event) {
  ipc.send('open-error-dialog')
})

Quand on démarre l’application on a donc cet affichage :

Quand on clique sur le bouton on a l’ouverture de la boîte de message :

On ne peut pas changer grand chose à l’aspect de la boîte…

 

Laisser un commentaire