API des menus
Référence complète de l’API des menus
Présentation
L’API des menus fournit des méthodes permettant de créer et de gérer les menus d’application, les menus contextuels et les menus de la zone de notification.
Types de menus :
- Menus d’application — Barre de menus supérieure (Fichier, Édition, etc.)
- Menus contextuels — Menus accessibles par clic droit
- Menus de la zone de notification — Menus situés dans la zone de notification système
Création de menus
NewMenu()
Crée un menu.
func (a *App) NewMenu() *MenuExemple :
menu := app.NewMenu()Méthodes des menus
Add()
Ajoute un élément au menu.
func (m *Menu) Add(label string) *MenuItemParamètres :
label— Texte affiché pour l’élément de menu
Valeur renvoyée : l’élément de menu créé
Exemple :
item := menu.Add("Open File")
item.OnClick(func(ctx *application.Context) {
// Handle click
})AddSubmenu()
Ajoute un sous-menu au menu.
func (m *Menu) AddSubmenu(label string) *MenuParamètres :
label— Libellé du sous-menu
Valeur renvoyée : le sous-menu créé
Exemple :
fileMenu := menu.AddSubmenu("File")
fileMenu.Add("New")
fileMenu.Add("Open")
fileMenu.Add("Save")AddSeparator()
Ajoute une ligne de séparation visuelle entre les éléments de menu.
func (m *Menu) AddSeparator()Exemple :
menu.Add("Copy")
menu.Add("Paste")
menu.AddSeparator()
menu.Add("Select All")Bonne pratique : utilisez des séparateurs pour regrouper les éléments de menu associés.
AddSectionHeader()
Ajoute un en-tête de section natif non interactif sous macOS 14 et versions ultérieures. Sur les versions antérieures de macOS et toutes les autres plateformes (y compris les compilations serveur), cet appel est sans effet : aucun élément de remplacement n’est inséré.
func (m *Menu) AddSectionHeader(label string)Utilisez les en-têtes pour nommer les groupes dans les menus de la zone de notification, les menus contextuels ou les menus d’application :
menu.AddSectionHeader("mac-node1")
menu.Add("Windows VM").OnClick(openWindowsVM)
menu.Add("Linux VM").OnClick(openLinuxVM)
menu.AddSectionHeader("ai-master")
menu.Add("Build VM").OnClick(openBuildVM)Les en-têtes utilisent l’apparence standard des en-têtes de section d’AppKit. Appelez menu.Update() après avoir reconstruit un menu déjà affiché, comme pour les autres modifications de structure. Consultez l’exemple systray-menu pour un en-tête obtenu avec os.Hostname().
Les en-têtes omis ne séparent pas les groupes de boutons radio. Utilisez AddSeparator() lorsque les groupes doivent rester séparés sur toutes les plateformes.
AddCheckbox()
Ajoute un élément de menu à cocher.
func (m *Menu) AddCheckbox(label string, checked bool) *MenuItemParamètres :
label— Libellé de la case à cocherchecked— État coché initial
Exemple :
darkMode := menu.AddCheckbox("Dark Mode", false)
darkMode.OnClick(func(ctx *application.Context) {
isChecked := darkMode.Checked()
// Toggle dark mode
})AddRadio()
Ajoute un élément de menu de type bouton radio (dans un groupe à choix mutuellement exclusifs).
func (m *Menu) AddRadio(label string, checked bool) *MenuItemParamètres :
label— Libellé du bouton radiochecked— État coché initial
Exemple :
// Create radio group for view modes
viewMenu := menu.AddSubmenu("View")
listView := viewMenu.AddRadio("List View", true)
gridView := viewMenu.AddRadio("Grid View", false)
treeView := viewMenu.AddRadio("Tree View", false)
listView.OnClick(func(ctx *application.Context) {
setViewMode("list")
})
gridView.OnClick(func(ctx *application.Context) {
setViewMode("grid")
})Update()
Met à jour le menu afin de refléter les modifications apportées aux éléments de menu.
func (m *Menu) Update()Exemple :
item.SetEnabled(false)
menu.Update() // Must call to apply changesImportant : appelez toujours Update() après avoir modifié les propriétés d’un élément de menu.
Méthodes des éléments de menu
OnClick()
Enregistre un gestionnaire de clic pour l’élément de menu.
func (mi *MenuItem) OnClick(callback func(ctx *application.Context)) *MenuItemParamètres :
callback— Fonction appelée lorsque l’utilisateur clique sur l’élément
Valeur renvoyée : l’élément de menu (pour le chaînage)
Exemple :
item.OnClick(func(ctx *application.Context) {
fmt.Println("Menu item clicked")
app.Logger.Info("User clicked menu item")
})SetLabel()
Modifie le libellé de l’élément de menu.
func (mi *MenuItem) SetLabel(label string) *MenuItemExemple :
item.SetLabel("Save As...")
menu.Update()SetEnabled()
Active ou désactive l’élément de menu.
func (mi *MenuItem) SetEnabled(enabled bool) *MenuItemExemple :
// Disable save when no document is open
saveItem.SetEnabled(hasOpenDocument)
menu.Update()Modèle courant :
// Update menu state based on application state
func updateMenuState() {
saveItem.SetEnabled(hasUnsavedChanges)
undoItem.SetEnabled(canUndo)
redoItem.SetEnabled(canRedo)
menu.Update()
}SetChecked()
Définit l’état coché des éléments de menu de type case à cocher ou bouton radio.
func (mi *MenuItem) SetChecked(checked bool) *MenuItemExemple :
darkModeItem.SetChecked(isDarkModeEnabled)
menu.Update()Checked()
Renvoie l’état coché actuel.
func (mi *MenuItem) Checked() boolExemple :
if darkModeItem.Checked() {
// Dark mode is enabled
}SetAccelerator()
Définit un raccourci clavier pour l’élément de menu.
func (mi *MenuItem) SetAccelerator(accelerator string) *MenuItemParamètres :
accelerator— Raccourci clavier (par exemple, “Ctrl+S”, “Cmd+Q”)
Format du raccourci clavier :
- Touches de modification :
Ctrl,Cmd,Alt,Shift - Touches :
A-Z,0-9,F1-F12,Enter,Backspace, etc. - Plateforme : utilisez
Cmdsous macOS etCtrlsous Windows/Linux.
Exemple :
saveItem.SetAccelerator("Ctrl+S")
quitItem.SetAccelerator("Ctrl+Q")
newItem.SetAccelerator("Ctrl+N")Exemple adapté à la plateforme :
import "runtime"
var quitShortcut string
if runtime.GOOS == "darwin" {
quitShortcut = "Cmd+Q"
} else {
quitShortcut = "Ctrl+Q"
}
quitItem.SetAccelerator(quitShortcut)SetTooltip()
Définit une infobulle qui s’affiche au survol de l’élément de menu.
func (mi *MenuItem) SetTooltip(tooltip string) *MenuItemExemple :
item.SetTooltip("Opens a file from disk")SetHidden()
Affiche ou masque l’élément de menu.
func (mi *MenuItem) SetHidden(hidden bool) *MenuItemExemple :
// Hide debug menu in production
debugItem.SetHidden(!isDevelopment)
menu.Update()Menu de l’application
app.Menu.Set()
Définit la barre de menus principale de l’application.
func (mm *MenuManager) Set(menu *Menu)Exemple :
menu := app.NewMenu()
// File menu
fileMenu := menu.AddSubmenu("File")
fileMenu.Add("New").SetAccelerator("Ctrl+N").OnClick(newFile)
fileMenu.Add("Open").SetAccelerator("Ctrl+O").OnClick(openFile)
fileMenu.Add("Save").SetAccelerator("Ctrl+S").OnClick(saveFile)
fileMenu.AddSeparator()
fileMenu.Add("Exit").SetAccelerator("Ctrl+Q").OnClick(func(ctx *application.Context) {
app.Quit()
})
// Edit menu
editMenu := menu.AddSubmenu("Edit")
editMenu.Add("Undo").SetAccelerator("Ctrl+Z").OnClick(undo)
editMenu.Add("Redo").SetAccelerator("Ctrl+Y").OnClick(redo)
editMenu.AddSeparator()
editMenu.Add("Cut").SetAccelerator("Ctrl+X").OnClick(cut)
editMenu.Add("Copy").SetAccelerator("Ctrl+C").OnClick(copy)
editMenu.Add("Paste").SetAccelerator("Ctrl+V").OnClick(paste)
app.Menu.Set(menu)Remarques propres aux plateformes :
- macOS : le menu apparaît dans la barre de menus en haut de l’écran
- Windows/Linux : le menu apparaît dans la barre de titre de la fenêtre
- macOS : ajoute automatiquement un menu d’application portant le nom de l’application
Menus contextuels
app.ContextMenu.New() / app.ContextMenu.Add()
Créez un *ContextMenu via le gestionnaire, puis enregistrez-le sous un nom. ContextMenuManager.Add accepte *ContextMenu — pas *Menu — et il n’existe aucune méthode app.RegisterContextMenu.
func (cm *ContextMenuManager) New() *ContextMenu
func (cm *ContextMenuManager) Add(name string, menu *ContextMenu)
func (cm *ContextMenuManager) Get(name string) (*ContextMenu, bool)
func (cm *ContextMenuManager) Remove(name string)Vous pouvez également utiliser la fonction application.NewContextMenu(name string) *ContextMenu au niveau du paquet pour créer et enregistrer un menu contextuel en une seule étape.
Go :
// Build the context menu via the manager
contextMenu := app.ContextMenu.New()
contextMenu.Add("Cut").OnClick(cut)
contextMenu.Add("Copy").OnClick(copy)
contextMenu.Add("Paste").OnClick(paste)
contextMenu.AddSeparator()
contextMenu.Add("Select All").OnClick(selectAll)
// Register under a name; HTML opts into it via the CSS custom property below.
app.ContextMenu.Add("editor", contextMenu)HTML/CSS :
Le runtime déclenche un menu contextuel enregistré lorsque la cible du clic droit (ou l’un de ses ancêtres) possède la propriété personnalisée CSS --custom-contextmenu définie sur ce nom. La propriété facultative --custom-contextmenu-data est transmise à la fonction de rappel Go via ctx.ContextMenuData(). Pour supprimer le menu contextuel par défaut du navigateur, définissez --default-contextmenu: hide (ou auto/show).
<!-- Trigger context menu on right-click -->
<div style="--custom-contextmenu: editor; --default-contextmenu: hide">
Right-click here for context menu
</div>Il n’existe aucun attribut data-wails-context-menu="..." : il n’a jamais été raccordé au runtime.
Menus contextuels dynamiques :
// Update context menu based on selection
func updateContextMenu() {
contextMenu := app.ContextMenu.New()
if hasSelection {
contextMenu.Add("Cut").OnClick(cut)
contextMenu.Add("Copy").OnClick(copy)
}
contextMenu.Add("Paste").SetEnabled(hasClipboardContent).OnClick(paste)
app.ContextMenu.Add("editor", contextMenu)
}Menu de la zone de notification
app.SystemTray.New()
Crée une nouvelle icône dans la zone de notification.
func (sm *SystemTrayManager) New() *SystemTrayExemple :
tray := app.SystemTray.New()SetIcon()
Définit l’icône de la zone de notification.
func (st *SystemTray) SetIcon(icon []byte) *SystemTrayExemple :
iconData, _ := os.ReadFile("icon.png")
tray.SetIcon(iconData)SetMenu()
Définit le menu de la zone de notification.
func (st *SystemTray) SetMenu(menu *Menu) *SystemTrayExemple :
trayMenu := app.NewMenu()
trayMenu.Add("Show Window").OnClick(func(ctx *application.Context) {
window.Show()
window.Focus()
})
trayMenu.Add("Settings").OnClick(openSettings)
trayMenu.AddSeparator()
trayMenu.Add("Quit").OnClick(func(ctx *application.Context) {
app.Quit()
})
tray.SetMenu(trayMenu)SetTooltip()
Définit l’infobulle affichée au survol de l’icône de la zone de notification. Ne renvoie rien.
func (st *SystemTray) SetTooltip(tooltip string)Exemple :
tray.SetTooltip("My Application - Running")OnClick()
Gère le clic gauche sur l’icône de la zone de notification.
func (st *SystemTray) OnClick(callback func()) *SystemTrayExemple :
tray.OnClick(func() {
if window.IsVisible() {
window.Hide()
} else {
window.Show()
window.Focus()
}
})Exemples complets
Menu d’application standard
package main
import (
"github.com/wailsapp/wails/v3/pkg/application"
)
func createMenu(app *application.App) *application.Menu {
menu := app.NewMenu()
// File menu
fileMenu := menu.AddSubmenu("File")
fileMenu.Add("New").
SetAccelerator("Ctrl+N").
OnClick(func(ctx *application.Context) {
// Create new document
})
fileMenu.Add("Open").
SetAccelerator("Ctrl+O").
OnClick(func(ctx *application.Context) {
// Open file dialog
})
fileMenu.Add("Save").
SetAccelerator("Ctrl+S").
OnClick(func(ctx *application.Context) {
// Save document
})
fileMenu.AddSeparator()
fileMenu.Add("Exit").OnClick(func(ctx *application.Context) {
app.Quit()
})
// Edit menu
editMenu := menu.AddSubmenu("Edit")
editMenu.Add("Undo").SetAccelerator("Ctrl+Z")
editMenu.Add("Redo").SetAccelerator("Ctrl+Y")
editMenu.AddSeparator()
editMenu.Add("Cut").SetAccelerator("Ctrl+X")
editMenu.Add("Copy").SetAccelerator("Ctrl+C")
editMenu.Add("Paste").SetAccelerator("Ctrl+V")
// View menu
viewMenu := menu.AddSubmenu("View")
darkMode := viewMenu.AddCheckbox("Dark Mode", false)
darkMode.OnClick(func(ctx *application.Context) {
// Toggle dark mode
isChecked := darkMode.Checked()
app.Logger.Info("Dark mode", "enabled", isChecked)
})
viewMenu.AddSeparator()
viewMenu.AddRadio("List View", true)
viewMenu.AddRadio("Grid View", false)
viewMenu.AddRadio("Detail View", false)
// Help menu
helpMenu := menu.AddSubmenu("Help")
helpMenu.Add("Documentation").OnClick(func(ctx *application.Context) {
// Open docs
})
helpMenu.Add("About").OnClick(func(ctx *application.Context) {
// Show about dialog
})
return menu
}
func main() {
app := application.New(application.Options{
Name: "Menu Demo",
})
menu := createMenu(app)
app.Menu.Set(menu)
window := app.Window.New()
window.Show()
app.Run()
}Application avec icône dans la zone de notification
func setupSystemTray(app *application.App, window application.Window) {
// Create system tray
tray := app.SystemTray.New()
// Set icon
iconData, _ := os.ReadFile("icon.png")
tray.SetIcon(iconData)
tray.SetTooltip("My App - Running")
// Handle left-click on tray icon
tray.OnClick(func() {
if window.IsVisible() {
window.Hide()
} else {
window.Show()
window.Focus()
}
})
// Create tray menu
trayMenu := app.NewMenu()
showItem := trayMenu.Add("Show Window")
showItem.OnClick(func(ctx *application.Context) {
window.Show()
window.Focus()
})
trayMenu.AddSeparator()
trayMenu.Add("Settings").OnClick(func(ctx *application.Context) {
// Open settings window
})
trayMenu.Add("About").OnClick(func(ctx *application.Context) {
// Show about dialog
})
trayMenu.AddSeparator()
trayMenu.Add("Quit").OnClick(func(ctx *application.Context) {
app.Quit()
})
tray.SetMenu(trayMenu)
}Mises à jour dynamiques des menus
type Editor struct {
app *application.App
menu *application.Menu
undoItem *application.MenuItem
redoItem *application.MenuItem
saveItem *application.MenuItem
undoStack []string
redoStack []string
hasChanges bool
}
func (e *Editor) createMenu() {
e.menu = e.app.NewMenu()
fileMenu := e.menu.AddSubmenu("File")
e.saveItem = fileMenu.Add("Save").SetAccelerator("Ctrl+S")
e.saveItem.OnClick(func(ctx *application.Context) {
e.save()
})
editMenu := e.menu.AddSubmenu("Edit")
e.undoItem = editMenu.Add("Undo").SetAccelerator("Ctrl+Z")
e.undoItem.OnClick(func(ctx *application.Context) {
e.undo()
})
e.redoItem = editMenu.Add("Redo").SetAccelerator("Ctrl+Y")
e.redoItem.OnClick(func(ctx *application.Context) {
e.redo()
})
e.updateMenuState()
e.app.Menu.Set(e.menu)
}
func (e *Editor) updateMenuState() {
// Update menu items based on current state
e.saveItem.SetEnabled(e.hasChanges)
e.undoItem.SetEnabled(len(e.undoStack) > 0)
e.redoItem.SetEnabled(len(e.redoStack) > 0)
e.menu.Update()
}
func (e *Editor) onChange() {
e.hasChanges = true
e.updateMenuState()
}
func (e *Editor) save() {
// Save logic
e.hasChanges = false
e.updateMenuState()
}Bonnes pratiques
✅ À faire
- Utilisez les raccourcis clavier standard — respectez les conventions de la plateforme (Ctrl+C pour copier, etc.).
- Appelez Update() après les modifications — sinon, le menu ne les reflétera pas.
- Regroupez les éléments associés — utilisez des séparateurs pour organiser les éléments de menu.
- Désactivez les actions indisponibles — ne les masquez pas ; désactivez-les avec SetEnabled(false).
- Utilisez des libellés clairs — soyez concis et explicite.
- Respectez les conventions de la plateforme — les structures de menus diffèrent entre macOS et Windows/Linux.
❌ À éviter
- N’oubliez pas Update() — c’est l’erreur la plus courante.
- N’imbriquez pas trop profondément les menus — limitez-les à 2-3 niveaux.
- N’utilisez pas de libellés ambigus — « Traiter » contre « Traiter le document ».
- Ne compliquez pas inutilement les menus — gardez-les simples et ciblés.
- Ne mélangez pas les métaphores — adoptez une dénomination et une organisation cohérentes.
Remarques propres aux plateformes
macOS
- Un menu d’application portant le nom de l’application est ajouté automatiquement.
- Utilisez
Cmdplutôt queCtrlpour les raccourcis clavier. - Par défaut, « À propos », « Préférences » et « Quitter » figurent dans le menu de l’application.
Windows/Linux
- Aucun menu d’application automatique
- Utilisez
Ctrlpour les raccourcis clavier - « Quitter » se trouve généralement dans le menu Fichier