How to Keep Nsmenuitem Selected in a Nspopover with Nsmenu

How do I keep NSMenuItem selected in a NSPopover with NSMenu?

In the end, I changed how I did it.

I am using a NSButton to show the menu and NSTextField to display the results.

current implementation

If anyone is interested in the details, here they are.

Build the menu up and use .representedObject to store whatever you need to access at the other end. I used a struct with the name and code the in it.

You need to assign the NSMenu to the NSButton.menu

Then have a click, something like this.

@IBAction func changeVoiceClicked(_ sender: NSButton)
{
if let event = NSApplication.shared.currentEvent {
NSMenu.popUpContextMenu(sender.menu!, with: event, for: sender)
}
}

Your NSMenuItem should have an action on it, which using a selector points to a function.

Something like this:

@objc func voiceChanged(sender: NSMenuItem)
{
// cope will nil
var voice : VoiceDetail = VoiceDetail();

if (sender.representedObject != nil) {
voice = sender.representedObject as! VoiceDetail;
}

// Do what you need to on menu select.
// update text field.
}

Is it possible to group items in a NSPopupButton?

The following code groups menu, but not like the way you mentioned.

let items = [["First","Second"],["First","Second"],["First","Second"]]

lazy var addNewViewButton : NSPopUpButton = {
let popupButton = NSPopUpButton()

let firstMenuItem = NSMenuItem(title: "First Group", action: nil, keyEquivalent: "")
let secondMenuItem = NSMenuItem(title: "Second Group", action: nil, keyEquivalent: "")
let thirdMenuItem = NSMenuItem(title: "Third Group", action: nil, keyEquivalent: "")

let superMenu = NSMenu()
superMenu.addItem(firstMenuItem)
superMenu.addItem(secondMenuItem)
superMenu.addItem(thirdMenuItem)

for (index,item) in items.enumerated()
{
let menu = NSMenu()
for title in item
{
let menuItem = NSMenuItem(title: title, action: nil, keyEquivalent: "")
menuItem.target = self
menu.addItem(menuItem)
}
menu.addItem(NSMenuItem.separator())
superMenu.setSubmenu(menu, for: superMenu.items[index])
}
popupButton.menu = superMenu

popupButton.translatesAutoresizingMaskIntoConstraints = false

return popupButton
}()

Add the popupbutton in your code and you will get results like this

Sample Image

Each one will be having its own items inside.

refresh NSMenuItem on click/open of NSStatusItem

Keep a reference to the created NSMenuItem in your app delegate and update its state (assuming you use the item only in a single menu).

class AppDelegate: NSApplicationDelegate {

var fooMenuItem: NSMenuItem?

}

func createStatusBarItem() {
...
let enableDisableMenuItem = NSMenuItem(title: "Enabled", action: #selector(toggleAdvancedMouseHandlingObjc), keyEquivalent: "e")
self.fooMenuItem = enableDisableMenuItem
...
}

@objc func toggleAdvancedMouseHandlingObjc() {
if sHandler.isAdvancedMouseHandlingEnabled() {
sHandler.disableAdvancedMouseHandling()
} else {
sHandler.enableAdvancedMouseHandling()
}

self.fooMenuItem.state = sHandler.isAdvancedMouseHandlingEnabled() ? NSControl.StateValue.on : NSControl.StateValue.off
}

How do I change/modify the displayed title of an NSPopUpButton

Subclass NSPopUpButtonCell, override drawTitle(_:withFrame:in:) and call super with the title you want.

override func drawTitle(_ title: NSAttributedString, withFrame frame: NSRect, in controlView: NSView) -> NSRect {
var attributedTitle = title
if let popUpButton = self.controlView as? NSPopUpButton {
if let object = popUpButton.selectedItem?.representedObject as? Dictionary<String, String> {
if let shortTitle = object["shortTitle"] {
attributedTitle = NSAttributedString(string:shortTitle, attributes:title.attributes(at:0, effectiveRange:nil))
}
}
}
return super.drawTitle(attributedTitle, withFrame:frame, in:controlView)
}

In the same way you can override intrinsicContentSize in a subclass of NSPopUpButton. Replace the menu, call super and put the original menu back.

override var intrinsicContentSize: NSSize {
if let popUpButtonCell = self.cell {
if let orgMenu = popUpButtonCell.menu {
let menu = NSMenu(title: "")
for item in orgMenu.items {
if let object = item.representedObject as? Dictionary<String, String> {
if let shortTitle = object["shortTitle"] {
menu.addItem(withTitle: shortTitle, action: nil, keyEquivalent: "")
}
}
}
popUpButtonCell.menu = menu
let size = super.intrinsicContentSize
popUpButtonCell.menu = orgMenu
return size
}
}
return super.intrinsicContentSize
}


Related Topics



Leave a reply



Submit