I have a NSMenuItem in my project:
var statusBar = NSStatusBar.systemStatusBar()
var statusItem : NSStatusItem = NSStatusItem()
var menuItem : NSMenuItem = NSMenuItem()
var mainMenu = NSMenu()
override func viewDidLoad() {
super.viewDidLoad()
menuItem.title = "Holidays"
menuItem.action = Selector("setWindowVisible:")
menuItem.target = nil
menuItem.keyEquivalent = "M"
menuItem.enabled = true
mainMenu.addItem(menuItem)
statusItem = statusBar.statusItemWithLength(-1)
statusItem.menu = mainMenu
statusItem.title = statusItem.menu?.itemAtIndex(0)?.title
}
It adds the item to menu, but it isn't enabled:
http://i68.fastpic.ru/big/2015/0116/39/8e444aa8fb6f113bcdad2753e915b439.jpeg
And the selector is valid too, the function setWindowVisible exists in the same class:
func setWindowVisible(sender : AnyObject?) {
self.window!.orderFront(self)
}
The target needs to be self instead of nil.
menuItem.target = self
Related
I'm trying to find out how can i put an info bubble inside the annotation view when i click a pin on a map.
In the view did load I load this code that shows me the map
let latDelta:CLLocationDegrees = 0.01
let longDelta:CLLocationDegrees = 0.01
let evntLat : NSString = venueLat
let evntLng : NSString = venueLng
let latitute1:CLLocationDegrees = evntLat.doubleValue
let longitute2:CLLocationDegrees = evntLng.doubleValue
let theSpan:MKCoordinateSpan = MKCoordinateSpanMake(latDelta, longDelta)
let pointLocation:CLLocationCoordinate2D = CLLocationCoordinate2DMake(latitute1, longitute2)
let region:MKCoordinateRegion = MKCoordinateRegionMake(pointLocation, theSpan)
mappy.setRegion(region, animated: true)
let pinLocation : CLLocationCoordinate2D = CLLocationCoordinate2DMake(latitute1, longitute2)
let objectAnnotation = MKPointAnnotation()
objectAnnotation.coordinate = pinLocation
objectAnnotation.title = "\(self.venumeNam)"
self.mappy.addAnnotation(objectAnnotation)
Is there any way to put inside this annotation view a button?
I've tried this
let annotationView = MKAnnotationView()
let detailButton: UIButton = UIButton(type:UIButtonType.DetailDisclosure) as UIButton
annotationView.rightCalloutAccessoryView = detailButton
But i cant figure out how to implement it on my code so it can show it.
Any idea of how can i put this bubble and configure a function when someone clicks it?
FYI it's only one pin that i'm displaying here!
Updated from this answer
class detailsViewController: UIViewController, MKMapViewDelegate {
#IBOutlet weak var mappy: MKMapView!
// Here we add disclosure button inside annotation window
func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if control == view.rightCalloutAccessoryView{
print(view.annotation!.title) // annotation's title
print(view.annotation!.subtitle) // annotation's subttitle
//Perform a segue here to navigate to another viewcontroller
// On tapping the disclosure button you will get here
}
}
// Here we add disclosure button inside annotation window
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
print("viewForannotation")
if annotation is MKUserLocation {
//return nil
return nil
}
let reuseId = "pin"
var pinView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) as? MKPinAnnotationView
if pinView == nil {
//println("Pinview was nil")
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView!.canShowCallout = true
pinView!.animatesDrop = true
}
let button = UIButton(type: .DetailDisclosure) as UIButton // button with info sign in it
pinView?.rightCalloutAccessoryView = button
return pinView
}
func displayMarkers() -> Void
{
let latDelta:CLLocationDegrees = 0.01
let longDelta:CLLocationDegrees = 0.01
let evntLat : NSString = venueLat
let evntLng : NSString = venueLng
let latitute1:CLLocationDegrees = evntLat.doubleValue
let longitute2:CLLocationDegrees = evntLng.doubleValue
let theSpan:MKCoordinateSpan = MKCoordinateSpanMake(latDelta, longDelta)
let pointLocation:CLLocationCoordinate2D = CLLocationCoordinate2DMake(latitute1, longitute2)
let annotationView = MKAnnotationView()
let region:MKCoordinateRegion = MKCoordinateRegionMake(pointLocation, theSpan)
mappy.setRegion(region, animated: true)
let pinLocation : CLLocationCoordinate2D = CLLocationCoordinate2DMake(latitute1, longitute2)
let objectAnnotation = MKPointAnnotation()
objectAnnotation.coordinate = pinLocation
objectAnnotation.title = "\(self.venumeNam)"
self.mappy.addAnnotation(objectAnnotation)
}
}
I have a TextView with some text, which font is Bold. And i´ve a button. When this button is tapped, the Bold Font should change to "UnBold"
There´s a ViewController & a class called "FontManager" to manage the Fonts of the TextKit/UITextView.
My code for the FontManager:
import UIKit
class FontManager {
var textView: UITextView! = nil
init(textView: UITextView) {
self.textView = textView
self.setFont()
}
// set a Range of the TextView to Bold at start:
func setFont() {
// set font to "HelveticaNeue"
let newFont = UIFont(name:"HelveticaNeue", size: textView.font!.pointSize)
self.textView.font = newFont
let range = NSMakeRange(11, 24)
self.makeBold(range)
}
// set attributes
func getDict(key : String, value: UIFont ) -> [String: AnyObject] {
return [key : value]
}
This code to set the Font to Bold in selectedRange works without problem
func makeBold(selectedRange: NSRange) {
self.addOrRemoveFontTraitWithName("Bold", andValue: UIFontDescriptorSymbolicTraits.TraitBold.rawValue, andRange:selectedRange)
}
func addOrRemoveFontTraitWithName(traitName: String, andValue traitValue: UInt32, andRange selectedRange: NSRange) {
let currentAttributesDict : NSDictionary! = self.textView.textStorage.attributesAtIndex(selectedRange.location, effectiveRange: nil)
let currentFont : UIFont = currentAttributesDict .objectForKey(NSFontAttributeName) as! UIFont
let fontDescriptor : UIFontDescriptor! = currentFont.fontDescriptor()
let fontNameAttribute : NSString = fontDescriptor.objectForKey(UIFontDescriptorNameAttribute) as! NSString
var existingTraitsWithNewTrait : UInt32! = nil
var changedFontDescriptor : UIFontDescriptor! = nil
Here is a check, if there is already bold text. If not (== NSNotFound) the text in selectedRange becomes the Bold "trait"
if fontNameAttribute.rangeOfString(traitName).location == NSNotFound {
existingTraitsWithNewTrait = fontDescriptor.symbolicTraits.rawValue | traitValue
changedFontDescriptor = fontDescriptor.fontDescriptorWithSymbolicTraits(UIFontDescriptorSymbolicTraits.TraitBold)
(1) if the Font in selectedRange is bold (else: != NSNotFound) the Font should be set to normal (UnBold)
} else {
existingTraitsWithNewTrait = fontDescriptor.symbolicTraits.rawValue & ~traitValue
changedFontDescriptor = fontDescriptor.fontDescriptorWithSymbolicTraits(UIFontDescriptorSymbolicTraits(rawValue: existingTraitsWithNewTrait))
}
let updatedFont = UIFont(descriptor:changedFontDescriptor, size: 0.0)
let dict = self.getDict(NSFontAttributeName, value: updatedFont)
self.textView.textStorage.beginEditing()
textView.textStorage.setAttributes(dict, range: selectedRange)
self.textView.textStorage.endEditing()
}
And now the Code of the ViewController:
class ViewController: UIViewController {
#IBOutlet weak var textView: UITextView!
var fontManger: FontManager! = nil
// the #IBAction to change the Font
#IBAction func SwitchFont(sender: AnyObject) {
let range = NSMakeRange(11, 24)
fontManger.makeBold(range)
}
#IBOutlet weak var textView: UITextView!
var fontManger: FontManager! = nil
override func viewDidLoad() {
super.viewDidLoad()
// init the FontManager
fontManger = FontManager(textView: self.textView)
}
At the first Tap of the button there should be a skip to (1), the else...
But this doesn´t happen. Can see that in debug mode???
Any idea is welcome!
download project
Found it! The Bold-Font is "HelveticaNeue-Bold". The "UnBold"-Font is "HelveticaNeue-Medium" but not "HelveticaNeue" and this difference is almost unvisible!
See no other way as adding
var updatedFont = UIFont(descriptor:changedFontDescriptor, size: 0.0)
if updatedFont.fontName == "HelveticaNeue-Medium" {
updatedFont = UIFont(name:"HelveticaNeue", size: textView.font!.pointSize)!
}
Or do u see a better solution?
How can I have the top text field be equal to the path selected by the user? I'm fairly new to Xcode so any help would be appreciated.
import Cocoa
class ViewController: NSViewController {
#IBAction func browseDMF(sender: NSOpenPanel) {
var openPanel = NSOpenPanel()
openPanel.allowsMultipleSelection = false
openPanel.canChooseDirectories = true
openPanel.canCreateDirectories = false
openPanel.canChooseFiles = false
openPanel.beginWithCompletionHandler { (result) -> Void in
if result == NSFileHandlingPanelOKButton {
}
}
}
#IBOutlet weak var textFieldDMF: NSTextField!
Here is an updated code:
import Cocoa
class ViewController: NSViewController {
#IBAction func browseDMF(sender: NSOpenPanel) {
var openPanel = NSOpenPanel()
openPanel.allowsMultipleSelection = false
openPanel.canChooseDirectories = true
openPanel.canCreateDirectories = false
openPanel.canChooseFiles = false
openPanel.beginWithCompletionHandler { (result) -> Void in
if result == NSFileHandlingPanelOKButton {
NSURL *pathURL = [[openPanel URLs] objectAtIndex:0];
[textFieldDMF setStringValue:[pathURL absoluteString]];
}
}
}
#IBOutlet weak var textFieldDMF: NSTextField!
I'm trying to build an application in Swift for OS X (With Xcode 6.1 GM) that is a MenuBar agent with a single window for preferences.
Though I've been able to get most of my menubar functionality working, it all exists in the AppDelegate and looks pretty messy.
import Cocoa
import AppKit
import Foundation
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
var downloadClass = DownloadController()
#IBOutlet weak var window: NSWindow!
#IBOutlet weak var downloadButton: NSButton!
#IBOutlet weak var subredditField: NSTextField!
#IBOutlet weak var nsfwMarked: NSButton!
#IBOutlet weak var sortFilter: NSPopUpButton!
var statusBar = NSStatusBar.systemStatusBar()
var statusBarItem : NSStatusItem = NSStatusItem()
var menu: NSMenu = NSMenu()
var subSort: NSMenu = NSMenu()
override func awakeFromNib() {
//Add statusBarItem
statusBarItem = statusBar.statusItemWithLength(-1)
statusBarItem.menu = menu
let icon = NSImage(named: "arrow16black")
statusBarItem.image = icon
var downloadItem: NSMenuItem = NSMenuItem()
downloadItem.title = "Download"
downloadItem.action = Selector("downloadPressed:")
downloadItem.keyEquivalent = ""
menu.addItem(downloadItem)
var menuItem: NSMenuItem = NSMenuItem()
menuItem.title = "Preferences..."
//Open view on button click
menuItem.action = Selector("setWindowVisible:")
menuItem.keyEquivalent = ""
menu.addItem(menuItem)
//define sorting filters
let sortOptions = NSArray(array: ["Hot","New","Top","Rising","Controversial"])
sortFilter.addItemsWithTitles(sortOptions)
var sortItem: NSMenuItem = NSMenuItem()
sortItem.title = "Sort By"
menu.addItem(sortItem)
//Add sort options as submenu
for sort in sortOptions {
var item: NSMenuItem = NSMenuItem()
item.title = sort as String
item.keyEquivalent = ""
item.action = Selector("setActiveSort:")
subSort.addItem(item)
}
menu.setSubmenu(subSort, forItem: sortItem)
//Test receiving menu
let userDefaults = NSUserDefaults.standardUserDefaults()
if let filterDefault : AnyObject = userDefaults.objectForKey("filter") {
var active : NSString = filterDefault as NSString
sortFilter.selectItemWithTitle(active)
println(active)
subSort.itemWithTitle(active)?.state = 1
}
}
func setActiveSort(sender: NSMenuItem) {
//Turn off all other active filters
let allSorts = subSort.itemArray
var a = 0
while a < subSort.numberOfItems {
var filter = subSort.itemAtIndex(a)
filter?.state = 0
a++
}
//Make selected filter active and store value in Defaults
sender.state = 1
sortFilter.selectItemWithTitle(sender.title)
let userDefaults = NSUserDefaults.standardUserDefaults()
userDefaults.setObject(sender.title, forKey: "filter")
}
#IBAction func downloadPressed(sender: AnyObject) {
let subreddit: NSString = NSString(string: subredditField.stringValue)
let sortBy: NSString = NSString(string: sortFilter.titleOfSelectedItem!)
var sort = sortBy.lowercaseString
let nsfw: Bool = Bool(nsfwMarked.integerValue)
downloadClass.startController(subreddit, sortBy: sort, markNSFW: nsfw)
}
func setWindowVisible(sender: AnyObject) {
self.window!.orderFront(self)
}
func applicationDidFinishLaunching(aNotification: NSNotification?) {
// Insert code here to initialize your application
//Don't display application window at launch
self.window!.orderOut(self)
//On launch, get user preferences if set
let userDefaults = NSUserDefaults.standardUserDefaults()
if let nsfwMarkedPref : AnyObject = userDefaults.objectForKey("NSFW?") {
//Set nsfw state to stored value
nsfwMarked.state = (nsfwMarkedPref.integerValue == 1) ? NSOnState : NSOffState;
}
if let storedSubreddit : AnyObject = userDefaults.objectForKey("subreddit") {
//set subreddit string to stored value
subredditField.stringValue = storedSubreddit as String
}
//Get screen resolution
let ms = NSScreen.mainScreen()
let frame = ms?.frame
println(frame!.size.width)
}
func applicationWillTerminate(aNotification: NSNotification?) {
// Insert code here to tear down your application
//Set the user preferences on exit.. this should be moved to onButtonState
let userDefaults = NSUserDefaults.standardUserDefaults()
userDefaults.setObject(nsfwMarked.integerValue, forKey: "NSFW?")
let subreddit: NSString = NSString(string: subredditField.stringValue)
userDefaults.setObject(subreddit, forKey: "subreddit")
}
}
Currently, the IBAction of the downloadButton in my view will call the function within the DownloadController. But ideally I would like to be able to have the IBAction of downloadPressed right within the DownloadController.swift file, but I cannot seem to figure out how to go about this..
Thanks!
Create a XIB file or use storyboard and set it's file owner as your UI view controller. Then setup your actions and outlets there. I would recommend you watch some videos on you tube before you proceed.
I have made a statusBar application with a drop down. I would like to open a settingsWindow from that dropdown. I have made the settings window with its own ViewController.
The issue is that i can't figure out how to instantiate and show the settingsWindow that i have made. I have tried to follow every thread on the internet without any success.
My Viewcontroller:
class SettingsViewController: NSViewController {
#IBOutlet var ipAddress: NSTextField!
#IBOutlet var port: NSTextField!
#IBAction func connect(sender: AnyObject) {}
override func viewDidLoad() {
super.viewDidLoad()
}
}
My AppDelegate:
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet var statusMenu: NSMenu!
var statusItem: NSStatusItem?
var tcpService: TcpService = TcpService()
func applicationDidFinishLaunching(aNotification: NSNotification?) {
let bar = NSStatusBar.systemStatusBar()
statusItem = bar.statusItemWithLength(20)
statusItem!.menu = statusMenu
statusItem!.image = NSImage(byReferencingFile: NSBundle.mainBundle().pathForResource("16*16", ofType: "png"))
statusItem!.highlightMode = true
tcpService.initOutputStream("192.168.1.1", Port: 8888)
}
func applicationWillTerminate(aNotification: NSNotification?) {
// Insert code here to tear down your application
}
#IBAction func openSettings(sender: AnyObject) {
// open settings for ip and port optional port
}
}
in swift 3:
var myWindow: NSWindow? = nil
let storyboard = NSStoryboard(name: "Main",bundle: nil)
let controller: EditorViewController = storyboard.instantiateController(withIdentifier: "editorViewController") as! ViewController
myWindow = NSWindow(contentViewController: controller)
myWindow?.makeKeyAndOrderFront(self)
let vc = NSWindowController(window: myWindow)
vc.showWindow(self)
For 2022
in your normal Main storyboard, tap to add a new window controller.
tap precisely on the red "X", then the blue circle, and then enter "ExampleID" at the green entry.
in your app's ordinary main view controller, add this
variable:
var otherWindow: NSWindowController?
function:
private func otherWindow() {
let sb = NSStoryboard(name: "Main", bundle: nil)
otherWindow = sb.instantiateController(
withIdentifier: "ExampleID") as! NSWindowController
otherWindow?.showWindow(self)
}
That's it.
Call otherWindow when you want to.
Problem:
Inevitably you will want to set up the otherWindow in a certain way, example, transparent, whatever. Unfortunately this is a whole topic in itself, but you do it like this:
private func otherWindow() {
... as above ...
otherWindow?.window?.ExampleSetup()
}
and then
extension NSWindow {
func ExampleSetup() {
self.styleMask = .borderless
self.collectionBehavior = [.fullScreenPrimary]
self.level = .floating
self.isMovable = false
self.titleVisibility = .hidden
// etc etc etc ..
guard let screen = self.screen ?? NSScreen.main else {
print("what the???")
return
}
self.setFrame(screen.frame, display: true)
// consider also .visibleFrame
}
}
enum Storyboards: String {
case main = "Main"
func instantiateVC<T>(_ identifier: T.Type) -> T? {
let storyboard = NSStoryboard(name: rawValue, bundle: nil)
guard let viewcontroller = storyboard.instantiateController(withIdentifier: String(describing: identifier)) as? T else { return nil}
return viewcontroller
}
}
var ssoLoginController: IDSSOLoginViewController?
var myWindow: NSWindow? = nil
ssoLoginController = Storyboards.main.instantiateVC(IDSSOLoginViewController.self)
myWindow = NSWindow(contentViewController: ssoLoginController!)
myWindow?.makeKeyAndOrderFront(self)
let vc = NSWindowController(window: myWindow)
vc.showWindow(self)
I am not 100% that I fully understand your problem, but assuming that you are using a storyboard (you should if you are starting fresh), adding few lines to your applicationDidFinishLaunching method will help:
var myWindow: NSWindow? = nil
let storyboard = NSStoryboard(name: "Main",bundle: nil)
let controller: SettingsViewController = storyboard?.instantiateControllerWithIdentifier("SettingsViewController") as SettingsViewController
myWindow = controller.window
myWindow?.makeKeyAndOrderFront(self)
Do not forget to set the Storyboard ID in IB (in the example above to SettingsViewController)!