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.
Related
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 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
...
}
I am trying to display an OS X application statusItem in the System Status Bar and am having success with everything except the fact that the title is being cut off. I am initializing everything like so:
let statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(-1)
func applicationDidFinishLaunching(aNotification: NSNotification) {
let icon = NSImage(named: "statusIcon")
icon?.template = true
statusItem.image = icon
statusItem.menu = statusMenu
statusItem.title = "This is a test title"
}
The problem is the statusItem.title is appearing like so:
As you can see the application next to mine (iStatMenuBar) is cutting off the title to my application (or something similar is happening)
If I comment out the icon for the statusItem, it works and shows the entire title but when I re-add the icon it cuts off again. Is there a way for the two (icon and title) to co exist? I have reviewed some Apple docs and may have missed a critical piece which explains this.
Thanks guys.
One option would be to assign a custom view to your statusBarItem and within that view's class override drawRect(dirtyRect: NSRect) e.g.
private var icon:StatusMenuView?
let bar = NSStatusBar.systemStatusBar()
item = bar.statusItemWithLength(-1)
self.icon = StatusMenuView()
item!.view = icon
and StatusMenuView might look like:
// This is an edited copy & paste from one of my personal projects so it might be missing some code
class StatusMenuView:NSView {
private(set) var image: NSImage
private let titleString:NSString = "really long title..."
init() {
icon = NSImage(named: "someImage")!
let myWideStatusBarItemFrame = CGRectMake(0, 0, 180.0, NSStatusBar.systemStatusBar().thickness)
super.init(frame.rect)
}
override func drawRect(dirtyRect: NSRect)
{
self.item.drawStatusBarBackgroundInRect(dirtyRect, withHighlight: self.isSelected)
let size = self.image.size
let rect = CGRectMake(2, 2, size.width, size.height)
self.image.drawInRect(rect)
let titleRect = CGRectMake( 2 + size.width, dirtyRect.origin.y, 180.0 - size.width, size.height)
self.titleString.drawInRect(titleRect, withAttributes: nil)
}
}
Now, the above might change your event handling, you'll need to handle mouseDown in the StatusMenuView class.
In my class ViewController: NSViewController
I have the following code:
#IBAction override func mouseDown(theEvent: NSEvent) {
self.myLabel.textColor = NSColor.redColor()
//either of these work to set the labels text value
self.myLabel.objectValue = "Hello World"
self.myLabel.stringValue = "This is a test"
switch(self) {
case self.myLabel:
//change text of myLabel
break;
case self.myLabel1:
//change text of myLabel1
break;
case self.myLabel2:
//change text of myLabel2
break;
}
}
This works to change the text and color of a Label Control called myLabel, but I have 3 Label controls on the View how do I change the color on the one that sends the mouse down event? The only way I can think to do it is with the switch statement as in the code above. But I think there is a better way by some how using the sender of the event?
I'm new to OS X and Mac development and come from the .NET C# world so thanks for helping this Mac noob! Using the latest Swift and Xcode.
I did figure out how to determine if one of my NSTextField controls was clicked on in the mouseDown event of the view:
#IBAction override func mouseDown(theEvent: NSEvent) {
var event_location: NSPoint!
event_location = theEvent.locationInWindow
self.mouseDownEvent = theEvent
var cntrl_id = NSTextField()
var cntrl_frame = NSRect()
var cntrl_name = String()
var cntrl_value = String()
var hit = Bool()
for view in self.view.subviews as [NSView] {
if let ct = view as? NSTextField {
cntrl_name = ct.identifier!
cntrl_id = ct
cntrl_frame = ct.frame
cntrl_value = ct.stringValue
hit = cntrl_frame.contains(event_location)
if hit {
controlToMove = cntrl_id
break
}
}
}
}
There are probably ways to make this more efficient possibly such as keeping a dictionary of all the NSTextField controls on the view, and then
check the dictionary for if I have a "hit" on one of the controls.
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: "")