Launching ViewController as sheet from windowDidLoad - swift

I'm trying to show a storyboard as a sheet right after the window has loaded.
override func windowDidLoad() {
super.windowDidLoad()
let storyboard = NSStoryboard(name: NSStoryboard.Name(rawValue: "Init"), bundle: nil)
let controller = storyboard.instantiateInitialController() as! NSViewController
self.window!.contentViewController?.presentViewControllerAsSheet(controller)
}
Unfortunately, the sheet is shown out of position and behind the window.
When I run the same code inside a button, everything works fine.
Screenshot
How do i correctly show a storyboard sheet after loading a window?

I have more knowledge of the iOS ecosystem but I suppose that you should show new windows only after the origin window has been shown. windowDidLoad is called when the view has been loaded, not when it has been shown.
Therefore, you should probably put your code into viewDidAppear of the contentViewController.

Related

Height of view as a modal popup - Swift

In the app that I am creating with XCode I created a view that opens as a modal popup. I used this code:
#IBAction func open_view(_ sender: Any) {
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let VC_test_object = storyBoard.instantiateViewController(withIdentifier: "VC_Test")
VC_test_object.modalPresentationStyle = .popover;
self.present(VC_test_object, animated: true, completion: nil)
}
VC_Test is the ViewController in Storyboard. This is the result:
However, I would like to manage the height of the view to create a sort of menu.
As in this example screenshot (from the Documents app):
I can't understand how to do it.
Could you tell me how to manage the height of the popup?
Thanks for your help.
For a code-your-self version this SO link and the answers below it is what you need: Present modal view controller in half size parent controller
However, I would rather use this third party library : Presentr

How to reference a View from within a Window Controller?

I'm having a Window Controller with a toolbar. I also have a View Controller containing some views. How do I reference a view from the View Controller within my Window Controller? I'm still learning macOS development and I'm missing the bigger picture how code is structured and classes are meant to interact.
My concrete problem right now is this: Using XCode 9.4.1 I have a window with a toolbar and a button in it. That's how my WindowsController.swift looks like:
import Cocoa
class WindowController: NSWindowController {
override func windowDidLoad() {
super.windowDidLoad()
window?.titleVisibility = .hidden
}
#IBAction func startExport(_ sender: NSButton) {
print("Start Export")
}
}
In the ViewControllerScene there's a WKWebView that's loading a web page. When the button in the toolbar is pressed, I want to call that Web Views takeSnapshot method. So I need a reference in WindowsController.swift to that Web View, but control-dragging the Web View from the storyboard to WindowsController.swift in the assistant editor doesn't let me create that outlet.
This:
let vc = contentViewController as? ViewController
will take you to your view controller.

Opening window + view from an other view controller

I've got a ViewControllerOne. ViewControllerOne is connected via Ctrl-Drag (in storyboard) to a menu-button mBtn (which means I don't know how it is implemented programmatically).
Clicking on this mBtn, a ViewOne appears (present modal). This ViewOne is bound to ViewControllerOne. ViewOne has a button btnOne.
Clicking on btnOne I want ViewOne to be dismissed and ViewTwo to be shown. ViewTwo belongs to ViewControllerTwo and to WindowControllerTwo.
The WindowControllerTwo-ViewControllerTwo-binding is the standard case as created on a new project.
I have the following code in the IBAction for button btnOne in ViewControllerOne:
#IBAction func onbtnOnePressed(sender: AnyObject){
let m_WindowControllerTwo = NSStoryboard(name: NSStoryboard.Name(rawValue: "Main"), bundle: nil).instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("WindowControllerTwo")) as! NSWindowController // I have no custom class for the window controller as I don't really know what I can use it for ...
let m_ViewTwo = WindowControllerTwo.contentViewController as! ViewControllerTwo // my custom class for ViewTwo
m_ViewTwo.attributeIWantToPassToThisView = self.x // an attribute I want to pass from view a to view b
m_WindowControllerTwo.contentViewController = m_ViewTwo // passing the attribute from a to b
m_WindowControllerTwo.showWindow(self) // this does not work
self.dismiss(nil) // see NOTE
}
This code actually does not work. On debugging it step by step, I'm seeing the window/view flickering but not appearing...
NOTE: I could connect the button btnOne with a ctrl-drag to ViewControllerTwo. This works. But then the current ViewOne does not get dismissed!
Question: What am I doing wrong here? In iOS swift this also works. I don't quite get the WindowController stuff, so I'll need your advice on this.
Instead of this: m_WindowControllerTwo.showWindow(self)
use:
let application = NSApplication.shared()
application.runModal(for: wordCountWindow) //this will present WindowControllerTwo modally.
then to close your present controller add this line: PresentWindowControllerName.close()

Menubar app with NSWindowController

I'm currently trying to build a menubar app. Therefore I need a NSWindowController for an login field. It must be possible to open this NSWindowController when pressing a menu item and also close that window when the user clicked on cancel.
I used showWindow(self) and NSApp.hide(self) but this didn’t work for me. So has anyone an idea what I can try?
Assuming you are using Storyboard
Add an NSWindowController to the storyboard and uncheck visible at launch of the window.
In AppDelegate create a property windowController
var windowController : NSWindowController!
In AppDelegate create an IBAction.
In the action get the main storyboard with
let mainStoryBoard = NSStoryboard(name: NSStoryboard.Name(rawValue: "Main"), bundle: nil)
Then instantiate and assign the window controller (the identifier must match the storyboard identifier)
windowController = mainStoryBoard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(rawValue: "Login")) as! NSWindowController
Get the associated view controller (LoginController is the custom class of the view controller)
let loginController = windowController.window!.contentViewController as! LoginController
Show the main window
windowController.showWindow(self)
In Interface Builder connect the NSMenuItem to First Responder (red cube) and then to the created IBAction.
You can close the window either with the red close button or you need to add custom logic.
If you use a XIB create an NSWindowController subclass and load the XIB with windowController = MyWindowController(window: nil), activate your app with NSApp.activate(ignoringOtherApps: true) get the associated window with let controllerWindow = windowController.window! and show the window with controllerWindow.makeKeyAndOrderFront(self)

Why is drawRect not called in the NSView when I programmatically load my window from a storyboard?

I have a window in my Main.storyboard file that I am trying to load programmatically, and not at application launch. So I have deleted the "Storyboard Entry Point" entirely, and in AppDelegate.swift, I have:
let storyBoard = NSStoryboard(name: "Main", bundle: nil)
let pauseWindowController = storyBoard.instantiateControllerWithIdentifier("pauseWindowController")
pauseWindowController.showWindow(self)
This seems to work, but when I run the app, I get no window. I added tracing code in my app to follow the progression of events, and I find that my custom NSView subclass is initialized, but drawRect is never called. If I remove the above code above and re-add the Storyboard Entry Point (to point to the window controller), everything works fine.
Here is the result of my print calls that I added for tracing, which show the calling class and the method called:
(AppDelegate) applicationDidFinishLaunching
(Pause OverlayWindow : NSWindow) Window init
(PauseOverlayView : NSView) View init
(PauseViewController: NSViewController) viewDidLoad
(PauseViewController: NSViewController) viewDidAppear
(PauseViewController: NSViewController) viewWillDisappear
(PauseViewController: NSViewController) viewDidDisappear
There should be a line (PauseOverlayView : NSView) drawRect line after viewDidAppear, and the window should display, but the method is never called. Why?
I have "Visible At Launch" checked in the Storyboard editor for my window. To my understanding, drawRect is called if the view is dirty and visible. I imagine it's not visible for some reason, but can't find out why.
I found my mistake: I didn't add the pauseWindowController property (var pauseWindowController : NSWindowController!) to the top of my AppDelegate.swift file. And the code should then become
let storyBoard = NSStoryboard(name: "Main", bundle: nil)
pauseWindowController = storyBoard.instantiateControllerWithIdentifier("pauseWindowController") as! NSWindowController
pauseWindowController.showWindow(self)