Catching Window Level Events

Hi


ViewControllers events are easy to catch just open its file and well see viewdid load and other stuff, but how to catch windows based

events such as when window get resized or minimized ? and in which file well find them ?

--

Kindest Regards

Answered by Claude31 in 395236022

I finally made it work but had to turn around something that looks like an XCode bug or OSX bug…


I changed to:


import Cocoa

class S1W2WC: NSWindowController, NSWindowDelegate {

    override func windowDidLoad() {
        super.windowDidLoad()
        // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
    }
  
    func windowDidMove (_ notification: Notification) {     // Take care of space after underscore
        let newOrigin = self.window!.frame.origin
        print("Window Did Move:", newOrigin)
    }
  
    func windowDidResize (_ notification: Notification) {
        let newSize = self.window!.frame.size
        print("Window Did Resize:", newSize)
    }
  
}


and



import Cocoa

class SecondVC: NSViewController {

    var parentWindowController: NSWindowController?     // Helps keeping a reference to the controller 

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do view setup here.
    }

    override func viewDidAppear() {
        super.viewDidAppear()
        parentWindowController = self.view.window!.windowController     // This is needed, otherwise dnotification does not go through
        self.view.window!.delegate = parentWindowController as! S1W2WC
    }

}


For reference on the notification issue:

https://stackoverflow.com/questions/55836017/window-windowcontroller-is-nil-inside-windowwillclose-but-it-isnt-inside-view/58978689#58978689

NSWindowController has a window property .


To catch window move or resize, use the NSWindowDelegate functions:

func windowDidMove(_ notification: Notification)

and

func windowDidResize(_ notification: Notification)


So, if you want to get the new position and size:


    func windowDidMove(_ notification: Notification) {
        let newOrigin = self.window!.frame.origin
        print("new origin:" newOrigin)

    }

    func windowDidResize(_ notification: Notification) {
 
        let newSize = self.window!.frame.size
        print("new size:" newSize)
    }


Note: don't forget to declare that the NSWindowController conform to NSWindowDelegate protocol.

But where to put that code in the AppDelegate.Swift ?

I put this in the NSWindowController

But there’s no such file with source code only view controller ? Or I’m missing something?

Is it a storyboard app for MacOS ?


My previous answer was for a xib based.


But now for storyboard.


I have a window, with a view inside, which class is SecondViewController.


We shall use the reference to its parent window to keep track of window move and resize.

For this, Viewcontroller will conform to NSWindowDelegate and be the delagate of its parent window (that's the trick).

To initialize this delegate we call :

self.view.window!.delegate = self     // self is the viewController

But we cannot do it in viewDidload, because window not yet initialized. So we'll do it elsewhere, in didLayout for instance.


Here is the full code for the VC


import Cocoa

class SecondViewController: NSViewController, NSWindowDelegate {               // Conform to NSWindowDelegate

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do view setup here.
        // Following was just to illustrate class methods ; no more needed here
        // FirstViewController.classTest()
        // let first = FirstViewController()
        // first.instanceTest()
    }


    override func viewDidLayout() {
        self.view.window!.delegate = self   // So that window moves and resize are handled by the view controller
    }

    func windowDidMove(_ notification: Notification) {          // NSWindowDelegate function
      let newOrigin = self.view.window!.frame.origin
      print("windowDidMove new origin:", newOrigin)

    }

    func windowDidResize(_ notification: Notification) {         // NSWindowDelegate function
      let newSize = self.view.window!.frame.size
      print("windowDidResize new size:", newSize)
    }

}


When moving window:

windowDidMove new origin: (558.0, 500.0)

windowDidMove new origin: (970.0, 573.0)

windowDidMove new origin: (1011.0, 578.0)

windowDidMove new origin: (1011.0, 579.0)


When resizing window:

windowDidResize new size: (509.0, 315.0)

windowDidResize new size: (523.0, 323.0)

windowDidResize new size: (540.0, 332.0)

windowDidResize new size: (558.0, 341.0)

windowDidResize new size: (574.0, 350.0)



Hope that's clear.

Tthanks allot but I want to ask about a better approach if possible, can we add a Cocoa file of type NSWindowController and make it the class of the Wndow Controller in the Storyboard, and implement the event catching code there ?

Yes, that is another possibility.


I applied on another NSWindowController:


- Create a Cocoa class file as subClass of NSWindowController

- I name it FirstWindowController

- make it conform to NSWindowDelegate

- use the predefined window property of the controller


import Cocoa

class FirstWindowController: NSWindowController, NSWindowDelegate {

    override func windowDidLoad() {
        super.windowDidLoad()
   
        // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
    }

    func windowDidMove(_ notification: Notification) {
        let newOrigin = self.window!.frame.origin
        print("windowDidMove new origin:", newOrigin)
       
    }
   
    func windowDidResize(_ notification: Notification) {
        let newSize = self.window!.frame.size
        print("windowDidResize new size:", newSize)
    }

}

And declare (in IB) the WindowController class as FirstWindowController

Hi


I tried both and although no errors was thrown but the code didnt work and no printing happened

please check the demo below, in Main storyboard I made the ViewController the delegate for first window

and on second window i used S1W2WC as a WindowController for second window, both didnt work.

--

Kindest Regards


h ttps://www.dropbox.com/s/oyoro5obyiww0fv/Windows%20Demo.zip?dl=0

I'll need to look on another machine how I tested with NSWindowController.

May be I just left the code in the view controller, which made me think it worked as well.


For sure, this works, and is pretty straightforward, and no need for windowController in SB:


class SecondVC: NSViewController, NSWindowDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do view setup here.
    }
   
      override func viewDidLayout() {
          self.view.window!.delegate = self   // So that window moves and resize are handled by the view controller
      }
   
      func windowDidMove(_ notification: Notification) {          // NSWindowDelegate function
        let newOrigin = self.view.window!.frame.origin
        print("windowDidMove new origin:", newOrigin)
   
      }
   
      func windowDidResize(_ notification: Notification) {         // NSWindowDelegate function
        let newSize = self.view.window!.frame.size
        print("windowDidResize new size:", newSize)
      }

}


Note that the signature of your delegate functions were wrong (but that's not the reason it did not work.

You wrote

func windowDidMove (_notification: Notification){

instead of

func windowDidMove (_ notification: Notification) {

Accepted Answer

I finally made it work but had to turn around something that looks like an XCode bug or OSX bug…


I changed to:


import Cocoa

class S1W2WC: NSWindowController, NSWindowDelegate {

    override func windowDidLoad() {
        super.windowDidLoad()
        // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
    }
  
    func windowDidMove (_ notification: Notification) {     // Take care of space after underscore
        let newOrigin = self.window!.frame.origin
        print("Window Did Move:", newOrigin)
    }
  
    func windowDidResize (_ notification: Notification) {
        let newSize = self.window!.frame.size
        print("Window Did Resize:", newSize)
    }
  
}


and



import Cocoa

class SecondVC: NSViewController {

    var parentWindowController: NSWindowController?     // Helps keeping a reference to the controller 

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do view setup here.
    }

    override func viewDidAppear() {
        super.viewDidAppear()
        parentWindowController = self.view.window!.windowController     // This is needed, otherwise dnotification does not go through
        self.view.window!.delegate = parentWindowController as! S1W2WC
    }

}


For reference on the notification issue:

https://stackoverflow.com/questions/55836017/window-windowcontroller-is-nil-inside-windowwillclose-but-it-isnt-inside-view/58978689#58978689

Hello

All is fine, thanks allot

Everything in AtOmXpLuS.CoM

Catching Window Level Events
 
 
Q