Electron : les menus

Dans ce quatrième article sur Electron nous allons voir comment créer des menus avec des sous-menus, des actions de base ou personnalisées, des menus contextuels.

Un premier exemple

En général une fenêtre comporte un menu. On en a déjà un par défaut dans notre application. Voyons à présent comment en créer un personnalisé. La documentation correspondante est ici.

Le plus simple est de prendre un exemple. On commence par prévoir le module Menu en plus de app :

const app = electron.app
const Menu = electron.Menu

Ensuite il faut définir la structure du menu qu’on veut avec un template :

const template = [
  {
    label: 'Item 1',
    submenu: [
      {
        label: 'Item1.1'
      }, {
        label: 'Item1.2'
      }
    ]
  },{
    label: 'Item 2',
    submenu: [
      {
        label: 'Item2.1'
      }, {
        label: 'Item2.2'
      }
    ]
  }
]

Et enfin on crée le menu à partir de ce template :

mainWindow.once('ready-to-show', () => {
  const menu = Menu.buildFromTemplate(template)
  Menu.setApplicationMenu(menu)
  mainWindow.show()
})

Sur macOS il y a des subtilités que vous trouverez dans la documentation

On obtient bien le menu désiré mais pour le coup on a perdu tous les menus par défaut !

D’autre part je n’ai prévu que des étiquettes et aucune action. Il est évident qu’il faudra pour chaque étiquette une action :

submenu: [
  {
    label: 'Item1.1',
    click () { mon action ici }
  }, {

Pour le moment on ne sait pas quoi mettre comme action, on verra plus tard…

Les menus standards

On a vu ci-dessus qu’on a perdu les menus standards, comment les retrouver ? Il faut utiliser les rôles. Par exemple pour le menu d’édition :

const template = [
  {
    label: 'Edit',
    submenu: [
      {role: 'undo'},
      {role: 'redo'},
      {type: 'separator'},
      {role: 'cut'},
      {role: 'copy'},
      {role: 'paste'},
      {role: 'pasteandmatchstyle'},
      {role: 'delete'},
      {role: 'selectall'}
    ]
  }
]

Vous trouvez la liste complète des rôles dans la documentation.

Remarquez au passage la syntaxe pour ajouter un séparateur :

type: 'separator'

Des sous-menus

On peut aussi créer des sous-menus en conservant le même principe :

const template = [
  {
    label: 'Item 1',
    submenu: [
      { 
        label: 'Item1.1' 
      }, { 
        label: 'Item1.2',
        submenu: [
          { 
            label: 'Item1.2.1' 
          }, { 
            label: 'Item1.2.2' 
          }
        ]
      }
    ]
  }
]

 

Il est possible d’ajouter une coche sur un item du menu :

const template = [
  {
    label: 'Item 1',
    submenu: [
      { 
        label: 'Item1.1'
      }, {
        label: 'Item1.2',
        submenu: [
          { 
            label: 'Item1.2.1',
            type: 'checkbox',
            checked: true 
          }, { 
            label: 'Item1.2.2' 
          }
        ]
      }
    ]
  }
]

Ça peut être aussi un bouton « radio » :

type: 'radio'

Pas banal dans un menu…

Vous pouvez trouver aussi dans la documentation la manière de générer dynamiquement un menu à partir du processus de rendu.

Un menu contextuel

On a vu jusque là le cas du menu fixe supérieur de la fenêtre mais dans une application on peut aussi avoir besoin d’un menu contextuel. Voyons à présent comment en faire un.

Les modules Menu et MenuItem sont accessibles à partir du processus principal (main process) mais le menu contextuel appartient au processus de rendu qui n’a pas accès à ces modules. Alors comment faire ?

On peut faire communiquer les deux processus avec le module ipcRenderer. On peut ainsi envoyer des messages depuis le processus de rendu vers le processus principal (main).

Dans le fichier main.js on va d’abord prévoir tous les modules nécessaires :

const app = electron.app
const Menu = electron.Menu
const MenuItem = electron.MenuItem
const ipc = electron.ipcMain

Ensuite on crée le menu :

const menu = new Menu()
menu.append(new MenuItem({ label: 'Accueil' }))
menu.append(new MenuItem({ type: 'separator' }))
menu.append(new MenuItem({ label: 'Actif', type: 'checkbox', checked: true }))

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

ipc.on('show-context-menu', function (event) {
  const win = BrowserWindow.fromWebContents(event.sender)
  menu.popup(win)
})

Dans le fichier renderer.js on déclare le module :

const ipc = require('electron').ipcRenderer

Et on prévoit l’événement :

document.addEventListener('contextmenu', (e) => {
    e.preventDefault()
    ipc.send('show-context-menu')
})

Maintenant un clic droit sur la fenêtre fait apparaître le menu :

On reviendra plus en détail sur le module ipc.

Complément

Dans l’application de démonstration d’Electron vous trouvez deux exemples concernant les menus :

Dans le prochain article nous verrons les boîtes de dialogue.

Laisser un commentaire