Why is windowDidMove() not being called? [duplicate] - swift

I'm trying to know when a window closes, I implemented this code:
class ViewController: NSViewController, NSWindowDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let window: NSWindow? = view.window
window?.delegate = self
}
func windowWillClose(_ aNotification: Notification) {
print("windowWillClose")
}
}
Unfortunately nothing happens, what could I made wrong?
Documents: https://developer.apple.com/documentation/appkit/nswindow/1419400-willclosenotification
PS
I already read this question without to find a solution: Handle close event of the window in Swift

The problem there is that the window property will always return nil inside viewDidLoadMethod. You need to set the delegate inside viewWillAppear method:
class ViewController: NSViewController, NSWindowDelegate {
override func viewWillAppear() {
super.viewWillAppear()
view.window?.delegate = self
}
func windowWillClose(_ aNotification: Notification) {
print("windowWillClose")
}
}

Related

How to hide the top bar (with buttons) usin Swift and MacOS?

I'm trying to remove the title and top buttons from the window and basically display only the content. I've tried various things with no success without any apparent reason why it's not working.
See setVisibility function for the options I've tried
AppDelagate.swift
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet weak var window: NSWindow!
func setVisibility(){
self.window?.titlebarAppearsTransparent = true;
self.window?.styleMask = .borderless
self.window?.titleVisibility = .hidden
self.window?.styleMask.insert(.fullSizeContentView)
/*
self.window?.standardWindowButton(.zoomButton)!.isHidden = true
self.window?.standardWindowButton(.closeButton)!.isHidden = true
*/
self.window?.level = .floating
self.window?.center()
self.window?.collectionBehavior = .canJoinAllSpaces
//self.window?.collectionBehavior = .moveToActiveSpace
}
func applicationDidFinishLaunching(_ aNotification: Notification) {
setVisibility()
NSApp.activate(ignoringOtherApps: true)
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
func applicationDidBecomeActive(_ aNotification: Notification) {
setVisibility()
NSApp.activate(ignoringOtherApps: true)
}
func applicationWillResignActive(_ aNotification: Notification) {
setVisibility()
NSApp.activate(ignoringOtherApps: true)
}
func applicationWillEnterForeground(_ aNotification: Notification) {
setVisibility()
NSApp.activate(ignoringOtherApps: true)
}
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
NSApp.terminate(self)
return true
}
}
ViewController.swift
I'm just embedding a webkit view. Nothing fancy.
import Cocoa
import WebKit
import os
class ViewController: NSViewController, WKUIDelegate, WKNavigationDelegate {
#IBOutlet weak var window: NSWindow!
let webView = WKWebView()
override func viewDidLoad() {
super.viewDidLoad()
self.webView.uiDelegate = self
self.webView.navigationDelegate = self
webView.frame = CGRect(x: 0, y: 0, width: 1200, height: 600)
view.addSubview(webView)
let url = URL(string: "http://localhost:8080/?x=y")
//let url = URL(string: "https://apple.com")
let request = URLRequest(url: url!)
webView.load(request)
}
public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Swift.Void)
{
if navigationAction.request.url?.path == "/close" || navigationAction.request.url?.path == "/close/"{
exit(0);
}
decisionHandler(.allow)
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
}
What you want is a window with a style mask of type NSWindowStyleMaskBorderless. The problem is that this has to be set when initializing the window. That's why your line self.window?.styleMask = .borderless has no effect.
Because you are creating your window using Interface Builder, you have to open the corresponding xib file (I guess MainMenu.xib), select the window and deselect Title Bar in the Attributes inspector:
I know. This is confusing. But at least Apple mentions it in the documentation:
Note that you can set a window’s or panel’s style mask to NSWindowStyleMaskBorderless in Interface Builder by deselecting Title Bar in the Appearance section of the Attributes inspector.
If you want to learn more about the different styles of a NSWindow checkout NSWindowStyles by Luka Kerr. That's a great reference.
Update: In said reference i found another way to remove the title bar that might work for you:
window?.styleMask.remove(.titled)

How do I check when a NSTextView changes if I have two text views?

In a macOS app with two NSTextView, I am trying to check when a textView changes, so far I have done this:
class ViewController: NSViewController, NSTextViewDelegate {
#IBOutlet var mainTextField: NSTextView!
#IBOutlet var findPanelFindTextView: NSTextView!
func textDidChange(_ notification: Notification) {
print("Hello!") // works only with mainTextField
}
override func viewDidLoad() {
super.viewDidLoad()
mainTextField.delegate = self // for textDidChange
findPanelFindTextField.delegate = self // for textDidChange
}
}
Only the first NSTextView (mainTextField) triggers the method textDidChange.
I already see this question Check if NSTextView has been edited and that implementation works for my first textView but not for my second textView.
Besides the fact that you wrote findPanelFindTextField but it should be findPanelFindTextView, you should check the object that posted the notification, create a textView object from it but cast it from Any to NSTextView and then create a switch to check which textview is posting the notification:
#IBOutlet var mainTextView: NSTextView!
#IBOutlet var findPanelFindTextView: NSTextView!
override func viewDidLoad() {
super.viewDidLoad()
mainTextView.delegate = self
findPanelFindTextView.delegate = self
}
func textDidChange(_ notification: Notification) {
guard let textView = notification.object as? NSTextView else { return }
switch textView {
case mainTextView:
print("mainTextView changed")
case findPanelFindTextView:
print("findPanelFindTextView changed")
default:
break
}
}

Trying to know when a window closes in a macOS Document based application

I'm trying to know when a window closes, I implemented this code:
class ViewController: NSViewController, NSWindowDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let window: NSWindow? = view.window
window?.delegate = self
}
func windowWillClose(_ aNotification: Notification) {
print("windowWillClose")
}
}
Unfortunately nothing happens, what could I made wrong?
Documents: https://developer.apple.com/documentation/appkit/nswindow/1419400-willclosenotification
PS
I already read this question without to find a solution: Handle close event of the window in Swift
The problem there is that the window property will always return nil inside viewDidLoadMethod. You need to set the delegate inside viewWillAppear method:
class ViewController: NSViewController, NSWindowDelegate {
override func viewWillAppear() {
super.viewWillAppear()
view.window?.delegate = self
}
func windowWillClose(_ aNotification: Notification) {
print("windowWillClose")
}
}

How to catch some events on a NSControl in swift

I am writing an application for OSX in Swift and I am looking for a good way to catch events on a NSControl.
Obviously, I searched but the informations I found are often unclear or old.
In my case, I would like to catch several events on a NSTextField (key up, text changed, focus lost,...).
When I push on “Enter” in the NSTextField, it sends an action. Maybe is there a way to send an action when I click or write in the NSTextField?
You can subclass NSTextField and override textDidChange for text change, textDidEndEditing for lost focus and keyUp method for key up. Try like this:
import Cocoa
class CustomTextField: NSTextField {
override func viewWillMove(toSuperview newSuperview: NSView?) {
// customize your field here
frame = newSuperview?.frame.insetBy(dx: 50, dy: 50) ?? frame
}
override func textDidChange(_ notification: Notification) {
Swift.print("textDidChange")
}
override func textDidEndEditing(_ notification: Notification) {
Swift.print("textDidEndEditing")
}
override func keyUp(with event: NSEvent) {
Swift.print("keyUp")
}
}
View Controller sample Usage:
import Cocoa
class ViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
let textField = CustomTextField()
view.addSubview(textField)
}
}
Sample

MacOS statusbar app show menu and run function on click with swift 3

I'm making a small menubar app with Swift 3, I want the app to reload some data when I click the icon, but I also want it to show the statusMenu?
Below is a sample of my code:
// AppDelegate.swift
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet weak var statusMenu: NSMenu!
#IBAction func quitClicked(_ sender: NSMenuItem) {
NSApplication.shared().terminate(self)
}
let statusItem = NSStatusBar.system().statusItem(withLength: NSVariableStatusItemLength)
func applicationDidFinishLaunching(_ aNotification: Notification) {
if let button = statusItem.button {
button.title = "App"
button.action = #selector(AppDelegate.doSomething(sender:))
statusItem.menu = statusMenu
}
}
func applicationWillTerminate(_ aNotification: Notification) {
}
func doSomething(sender: AnyObject?) {
NSLog("do something")
}
}
if I comment out
// statusItem.menu = statusMenu
The doSomething() function will run, but I can't figure out how to both show the menu and run the doSomething function, how can I do that?
Set the delegate of the menu to the application delegate (or another object) and implement optional func menuWillOpen(_ menu: NSMenu) of the NSMenuDelegate protocol.