I created a NSStatusBarItem and popUp a (programmatically generated) NSMenu on right click:
let statusBarItem = NSStatusBar.system().statusItem(withLength: -1)
statusBarItem.action = #selector(AppDelegate.statusBarItemAction(sender:))
let menu = NSMenu()
var menuItem = NSMenuItem()
menuItem.action = #selector(AppDelegate.customItemAction)
menu.addItem(menuItem)
func statusBarItemAction(sender: NSStatusItem) {
let mouseEvent = NSEvent.pressedMouseButtons()
if mouseEvent == 2 {
// right click
lxStatusBarItem.popUpMenu(menu)
}
}
func customItemAction() {
// do something
}
Everything works fine, except that the statusBarItem remains highlighted after customItemAction is called:
How can I solve this?
I found that setting statusItem.button?.isHighlighted = false helped with removing the highlight. In your case, this would look like this:
func customItemAction() {
// do something
statusBarItem.button?.isHighlighted = false
...
}
Related
I'm using the code below to show the status bar menu on the right click and show the application on the left click.
To achieve that, we need to detach the menu (statusBarItem.menu = nil) once it is closed. Otherwise, we would stop receiving statusBarButtonDidClick event and left-click would not work.
However, when I attach an external screen after right-click menu is getting closed immediately. The problem is in the line: statusBarItem.button?.performClick(nil), but without that menu would not appear instantly.
My guess is that performClick is trying to click on another screen which closes the menu on the active screen.
Is there any way to fix it or achieve the same functionality without performClick?
func createStatusBarItem() {
statusBarItem = NSStatusBar.system.statusItem(withLength: CGFloat(NSStatusItem.squareLength))
if let button = statusBarItem.button {
button.image = Asset.Icons.statusbar.image
button.image?.size = CGSize(width: 16, height: 16)
button.target = self
button.action = #selector(statusBarButtonDidClick)
}
statusBarItem.button?.sendAction(on: [.leftMouseUp, .rightMouseUp])
}
func menuDidClose(_ menu: NSMenu) {
statusBarItem.menu = nil
}
#objc private func statusBarButtonDidClick(sender: NSStatusBarButton) {
let event = NSApp.currentEvent!
if event.type == NSEvent.EventType.rightMouseUp {
let statusBarMenu = StatusBarMenu()
statusBarMenu.delegate = self
statusBarItem.menu = statusBarMenu
statusBarItem.button?.performClick(nil)
} else {
application.showApplication()
}
}
I am having a no-show menuController and I have checked all of the suggestions in previous questions. It turns out the imageView I have implemented a UILongPressGestureRecognizer on, to show the menu, is returning False on calling .becomeFirstResponder just before setting up the menu controller.
I am coding in swift 4 and can't figure out how to make the imageView return True to calling .becomeFirstResponder. Help!
/*********************************************************/
override func viewDidLoad() {
super.viewDidLoad()
// long tap to show menu that enables deletion of the image.
imageView_1.isUserInteractionEnabled = true
let longPressRecogniser = UILongPressGestureRecognizer(target: self, action: #selector(longPressOnImage(_:)))
//longPressRecogniser.numberOfTapsRequired = 1
//longPressRecogniser.numberOfTouchesRequired = 1
longPressRecogniser.minimumPressDuration = 0.5
imageView_1.addGestureRecognizer(longPressRecogniser)
imageView_1.image = placeHolderImage_1
imageView_2.image = placeHolderImage_2
}
/*********************************************************/
#IBAction func longPressOnImage(_ gestureRecognizer: UILongPressGestureRecognizer) {
print(#function)
if gestureRecognizer.state == .began {
//print("gestureRecognizer.state == .began")
self.tappedView = gestureRecognizer.view!
if tappedView.canResignFirstResponder {
print("can resign first responder")
}
if tappedView.becomeFirstResponder() {
print("returned TRUE to becomeFirstResponder")
} else {
print("returned FALSE to becomeFirstResponder")
}
// Configure the shared menu controller
let menuController = UIMenuController.shared
// Configure the menu item to display
// Create a "delete" menu item
let deleteImage = UIMenuItem(title: "Delete", action: #selector(deleteImage_1))
menuController.menuItems = [deleteImage]
// Set the location of the menu in the view.
let location = gestureRecognizer.location(in: tappedView)
print("location = ", location)
let menuLocation = CGRect(x: location.x, y: location.y, width: 2, height: 2)
menuController.setTargetRect(menuLocation, in: tappedView)
//update the menu settings to force it to display my custom items
menuController.update()
// Show the menu.
menuController.setMenuVisible(true, animated: true)
print("menu should be visible now")
}
}
/*********************************************************/
#objc func deleteImage_1() {
print(#function)
}
My caveman debugging print statements output:
longPressOnImage
can resign first responder
returned FALSE to becomeFirstResponder
location = (207.0, 82.0)
menu should be visible now
Create a custom imageView class and override "canBecomeFirstResponder" property like this:
class ResponsiveImage : UIImageView{
override var canBecomeFirstResponder: Bool{
return true
}
}
Use this ResponsiveImage type and your code will work :)
Thank you to adri. Your answer is the solution to my problem.
I had read in other posts to similar questions about overriding var canBecomeFirstResponder but either overlooked it or it wasn't made explicit that a custom UIImageView class needs to be created.
Just to make it clear to newbies like me, the class of the imageView in storyBoard and its #IBOutlet in its viewController must typed as ResponsiveImage. If only one of these is changed a type casting error is reported.
Many thanks for ending my hours of frustration! :-)
I have problem to place grey popUp right on top of screen.
it has x and y = 0.0
override func viewDidLoad() {
let dialogheigth:CGFloat = self.view.frame.height;
let dialogwidth:CGFloat = self.view.frame.width;
self.preferredContentSize = CGSizeMake(dialogwidth,dialogheigth);
}
Guys i use https://github.com/daisuke310vvv/PopupController library as PopUp
my solution was send the right ViewController to PopUp
let popup = PopupController.create(YourViewController).didShowHandler { popup in
// Do something
}
.didCloseHandler { _ in
// Do something
}
I create a NSStatusItem in a class named StatusMenuController like this
class StatusMenuController: NSObject {
let statusItem = NSStatusBar.system().statusItem(withLength: NSVariableStatusItemLength)
override func awakeFromNib() {
let icon = NSImage(named: "MenuBar")
icon?.isTemplate = true // best for dark mode
if let button = statusItem.button {
button.image = icon
button.action = #selector(StatusMenuController.showPomoNow)
button.sendAction(on: [.leftMouseUp, .rightMouseUp])
button.target = self
}
statusItem.title = "25:00"
}
I can change the title easily in this class. It will change like I expected.
I reference this class in AppDelegate
let statusMenu = StatusMenuController()
Add change it in other class
statusMenu.statusItem.title = "24:31"
I expect the text 25:00 will change to "24:31",but it looks like this.screenshot
System create another NSStatusItem. How can I change the one which created in StatusMenuController.
OOPer‘s comment is right. I found a object which create another StatusMenuController from Storyboard. I delete the object,Then everything is OK.
I'm building a NSStatusBar app and want to call different functions depending on if the user clicked left- or right on the icon.
Here is what I have so far:
let statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(-1)
func applicationDidFinishLaunching(aNotification: NSNotification) {
let icon = NSImage(named: "statusIcon")
icon?.setTemplate(true)
statusItem.image = icon
statusItem.menu = statusMenu
}
With this it shows up the statusMenu by every click. How can I distinguish the mouseEvents?
This snippet
func menuSelected (sender:AnyObject) {
var clickMask: Int = 0
if let clickEvent = NSApp.currentEvent! { // see what caused calling of the menu action
// modifierFlags contains a number with bits set for various modifier keys
// ControlKeyMask is the enum for the Ctrl key
// use logical and with the raw values to find if the bit is set in modifierFlags
clickMask = Int(clickEvent.modifierFlags.rawValue) & Int(NSEventModifierFlags.ControlKeyMask.rawValue)
}
if clickMask != 0 { ... } // click with Ctrl pressed
}
from my code checks for a ctrl-click. It's place in the method that is called from a menu item like this:
let item = NSMenuItem(title: title, action: Selector("menuSelected:"), keyEquivalent: "")