Electron (Windows) not showing the menu when tray icon is clicked - javascript

Im want to create a tray app, before all Im trying to create a simple icon showing a menu with radios inputs to test Electron tray apps exact how the doc example shows up. But when i click on the icon nothing happening.
const { app, Menu, Tray } = require('electron')
const { resolve } = require('path')
app.on('ready', () => {
createTray()
})
const createTray = () => {
const tray = new Tray(resolve(__dirname, 'assets', 'tray-icon.png'))
const contextMenu = Menu.buildFromTemplate([
{ label: 'Item1', type: 'radio' },
{ label: 'Item2', type: 'radio' },
{ label: 'Item3', type: 'radio', checked: true },
{ label: 'Item4', type: 'radio' }
])
tray.setToolTip('This is my application.')
tray.setContextMenu(contextMenu)
// using this to check if the click event is working
tray.on('click', () => {
console.log('clicked')
})
}

On Windows, the menu normally opens with a right click on the tray icon.
You can also trigger it by using tray.popUpContextMenu() in the click event handler that you have.
tray.on("click", ()=>{
tray.popUpContextMenu();
});

Related

How to hide or show menu labels in Electron app

I have Electron app and I am trying to hide or show label base on user input. The label aways show. I am trying to hide or show Tutorials
{
id: "tut",
label: "Tutorials",
submenu: [
{
id: "subTut",
label: "Tutorials",
click: async () => {
const { shell } = require("electron");
await shell.openExternal("https://example.app/tutorials");
},
},
],
},
In my main.js process I call the menu
When I call:
Menu.getApplicationMenu().getMenuItemById("tut").visible = false;
it does not hide anything, however it I call
Menu.getApplicationMenu().getMenuItemById("subTut").visible = false;
it will hide the sub menu item
Here is a solution for any that runs across this issue this can be done by using the function
Menu.setApplicationMenu()
Just pass object to the function where you call you menu to handle if item is visible or not
const MenuItems = (options) => {
// MENU
const template = [
{
label: "Window",
submenu: [
{
visible: options.option,
label: "Support",
click: async () => {
await shell.openExternal("https://example.com");
},
},
]
]
const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
};
When you run the function for you menu just pass object in function for what's to show.
In Mac OS, you cannot hide top-level menu items, just submenu items:
Nota Bene: The enabled and visibility properties are not available for top-level menu items in the tray on macOS.
Source: docs

How do i make a separate menu for a specific window in electron?

I am working on an about this app window on Windows and I want to make a custom menu bar for my about window. Since I already have a custom menu is there a way I can create another one and apply it only to that specific window?
Side note:
Here is my code for the new window that is supposed to stop it from being adjusted and going into full screen, but for some reason the minimize and enlarge button still work.
app.on('ready', createWindow);
electron.app.on('ready', () => {
//Triger update check
if (!isDev) {
autoUpdater.checkForUpdates();
}
})
function createWindow(){
//create brower window
win = new BrowserWindow({
backgroundColor: '#2e2c29',
width: 800,
height: 600,
//transparent: true,
frame: false,
titleBarStyle: 'hidden',
backgroundColor: '#0000',
webPreferences: {
nodeIntegration: true
}
});
//Quit when all windows are closed
app.on('window-all-closed', () => {
app.quit()
})
app.once('ready', function() {
const template = [
{
label: 'File',
submenu: [
{
label: 'About Hubris',
click: () =>
openAboutWindow()
},
{ type: 'separator' },
{ role: 'hide' },
{ role: 'hideothers' },
{ role: 'unhide' },
{ type: 'separator' },
{ role: 'quit' }
]
},
{
label: 'View',
submenu: [
{ role: 'minimize' },
{ role: 'zoom' },
{ type: 'separator' },
{ role: 'togglefullscreen' }
]
},
]
const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)
//here is the code for the about window
var newWindow = null
function openAboutWindow() {
if (newWindow) {
newWindow.focus()
return
}
newWindow = new BrowserWindow({
height: 439,
resizable: false,
width: 599,
title: 'About Hubris',
minimizable: false,
fullscreenable: false,
frame: false,
titleBarStyle: 'hidden',
})
newWindow.loadURL('file://' + __dirname + '/about-this-app.html')
newWindow.on('closed', function() {
newWindow = null
})
}
});
You can switch menus on the fly. I have an app with 'editor' and 'presentation' modes. I create and store a menu for each mode (they have different menu items):
let editorMenu = Menu.buildFromTemplate(menuTemplate);
and subscribe to the relevant window events (focus, blur, etc). Then when a window gets focus
Menu.setApplicationMenu(editorMenu);
To do this, you have to import menu from electron in at the top of our main.js file:
// From
const {app, BrowserWindow} = require('electron')
// To
const {app, BrowserWindow, Menu} = require('electron').
Then, near the bottom of our createWindow() function, we add:
function createWindow () {
// some code here removed for brevity
var menu = Menu.buildFromTemplate([
{
label: 'Menu',
submenu: [
{label:'Adjust Notification Value'},
{label:'CoinMarketCap'},
{label:'Exit'}
]
}
])
Menu.setApplicationMenu(menu);
}
Next, we reference Menu.buildFromTemplate([{}]), which is where our menu is actually defined and built, within a series of arrays and objects.
The "label" represents the name you want your menu to display so put what you like.
The "submenu" property is an array of objects, with each object defining the actual menu items displayed when the label is clicked.
Finally, use .setApplicationMenu to set the menu. If you save the project, and run npm start in the console, you will see the menu with it's items (array) being displayed but if your click on them nothing happens.
You can change this by going back to our main.js, add the following code to make our Exit button close the application:
var menu = Menu.buildFromTemplate([
{
label: 'Menu',
submenu: [
{label:'Adjust Notification Value'},
{label:'CoinMarketCap'},
{
label:'Exit',
click() {
app.quit()
}
}
]
}
])
So, to make a menu item clickable, we simply add a comma after the label value, and reference "click() { }"
In this case, we're calling app.quit()" when the Exit submenu item is clicked. Give it a try by running npm start in the console and click Exit.
That's it!

Is it possible by clicking on Electron's MenuItem of type checkbox not to close the current submenu?

I have in my Electron app the submenu with a couple of MenuItems of type 'checkbox':
{
label: 'Search settings',
submenu: [
{
type: 'checkbox',
checked: false,
label: 'Aerodromes',
click: (/* menuItem, currentWindow, event */) => {
console.log('')
console.log('menuItem Aerodromes is clicked')
// TODO: change userPrefs about search sources
}
},
{
type: 'checkbox',
checked: false,
label: 'Heliports and HL',
click: (/* event, focusedWindow, focusedWebContents */) => {
console.log('')
console.log('menuItem Heliports and HL is clicked')
// TODO: change userPrefs about search sources
}
},
{
type: 'checkbox',
checked: false,
label: 'LP',
click: (/* event, focusedWindow, focusedWebContents */) => {
console.log('')
console.log('menuItem LP is clicked')
// TODO: change userPrefs about search sources
}
},
...
]
},
When I click on every of these items, it's state 'checked/unchecked' updates correctly, but I can see the changes only after reopening this submenu again because immediately after clicking on any item the whole submenu gets closed (hidden). This is slightly not what I want. I would prefer to give the user the ability activate/inactivate (eg check/uncheck) all these checkbox-items inside the whole submenu until he decides he is done. How can I achieve this behaviour? Any good advice will be appreciated.
P.S.: I've played a lot with params of 'click' methods but without success ('event.preventDefault is not a function' etc)

Insert dynamic menus to electron menu bar app

I'm new to electron and I'm trying to create a Mac only menu bar app that has dynamic menu items in it. My idea is when clicking 'add...' it adds/appends/inserts a new menu item in it.
My code appends the new item into the menu array. However I can't make it render the 'updated menu'.
const { resolve } = require('path');
const { app, Tray, Menu } = require('electron');
const iconPath = resolve(__dirname, 'assets','iconTemplate.png');
let contextMenu;
let tray = null;
let menu;
app.on('ready', function() {
tray = new Tray(iconPath);
menu = [
{
label: 'Add...',
click: function() {
// add new item between 'Add...' and 'Quit'. New one always on top of the last.
menu.push({label: 'new item'});
}
},
{
label: 'Quit',
enabled: false
}
]
contextMenu = Menu.buildFromTemplate(menu);
tray.setContextMenu(contextMenu);
});
Turns out I figured out myself.
let counter = 0; // Start counter globally
// add new item between 'Add...' and 'Quit'. New one always on top of the last.
menu.splice(1, 0, {label: String(counter)});
render(); // Call render for every alteration on the menu array
counter++;
function render() {
contextMenu = Menu.buildFromTemplate(menu);
tray.setContextMenu(contextMenu);
}

Open a new window to display a html file using a menu click - Electron

I'm new to Electron and JavaScript. I'm building an Electron app. I know how to open a URL in a browser via clicking an item in native menu(by studying the documentation), but I need to open a html file in another Electron window using an Electron's native menu click. If I have my menu structure like below, how can I achieve this? Please help.
const {Menu} = require('electron');
const nativeMenus = [
{
label: 'About',
submenu: [
{
label: 'About',
click () {--- code to open about.html file in another electron window}
}
]
}
]
const menu = Menu.buildFromTemplate(nativeMenus);
Menu.setApplicationMenu(menu);
If it is all in the main.js just create a function to create a new window and then call that on menu item click.
const { Menu } = require('electron')
const ipc = require('electron').ipcRenderer
const nativeMenus = [
{
label: 'About',
submenu: [
{
label: 'About',
click() {
openAboutWindow()
}
}
]
}
]
const menu = Menu.buildFromTemplate(nativeMenus)
Menu.setApplicationMenu(menu)
var newWindow = null
function openAboutWindow() {
if (newWindow) {
newWindow.focus()
return
}
newWindow = new BrowserWindow({
height: 185,
resizable: false,
width: 270,
title: '',
minimizable: false,
fullscreenable: false
})
newWindow.loadURL('file://' + __dirname + '/views/about.html')
newWindow.on('closed', function() {
newWindow = null
})
}
Let me know if this works for you.
You stored your BrowserWindow instance in a variable, for the sake of this answer I am gonna suppose it's win. user7252292 did provide you with a good answer. But if you need another window then you will have to create another function for the same purpose. I will make a function for creating modals. They are basically windows that need a parent window and you cannot respond to the parent window until the modal is closed.
const createModal = (htmlFile, parentWindow, width, height) => {
let modal = new BrowserWindow({
width: width,
height: height,
modal: true,
parent: parentWindow,
webPreferences: {
nodeIntegration: true
}
})
modal.loadFile(htmlFile)
return modal;
}
const {Menu} = require('electron');
const nativeMenus = [
{
label: 'About',
submenu: [
{
label: 'About',
click () {
createModal("myfile.html",win,600,800); // Win is the browerwindow instance
}
}
]
}
]
const menu = Menu.buildFromTemplate(nativeMenus);
Menu.setApplicationMenu(menu);
Plus, you can store the createModal in a variable and modify the modal because it returns the modal itself.

Categories

Resources