NSOpenPanel style as sheet not floating window ?

With an NSOpenPanel, is there a way to style as sheet & not a floating window, without using beginSheetModal ?

Replies

I doubt it. The idea is that the panel is used to open a document, so how can you already have a document open to use with a sheet? Also, sandboxed apps do some clevery trickery to provide a sandbox escape and that might prevent the sheet from being attached to anything inside your process.

So are you saying that I have to have a document open to specify in the sheet ?

No. I am saying that the concept of a sheet depends on the prior existence of a window. A sheet is a sheet because it is contextually attached to a window for some reason. There could be situations where you want to add some some to an existing data structure, represented by a windows. In those cases, a sheet could make sense. But I don't see how you are going to get the sheet to work as a sheet when it is in a different process as in the sandbox.

What does "without using beginSheetModal" mean? That is the way to present an open or save panel as a sheet, necessarily attached to a window. What are you actually trying to do, if not present the sheet on an underlying window?


>>I don't see how you are going to get the sheet to work as a sheet when it is in a different process as in the sandbox.


This is just how it works. There's a bit of fakery going on behind the scenes (in macOS frameworks) that presents the content of the panel (provided by a separate process) on top of a window or sheet of your process, so that it looks like the content is inside your window or sheet.

Running beginSheetModal works as expected displaying a sheet attached to the main window with open & cancel options, but getting a result as it returns as void is the problem. When not using a sheet I run .runModal() set as a variable then just then switch it's case for the Modal response which I can then use for a return result.


If I set up a case in the completionHandler switching option I can't return anything because it's void.

Ah, I see.


The difficulty you've run into is not essentially about open panels, but is the difference between a synchronous API (runModal) and an asynchronous API (beginSheetModal). Instead of this:


result = someSynchronousAPI()
doSomething(with: result)
return


you'd do this:


someAsynchronousAPI() {
    result in
    doSomething(with: result)
}
return


In the first case, you return after completing the synchronous code and continue with the rest of your code. In the second case, you return after initiating the asynchronous code but don't immediately continue with your code. When the asynchronous completion handler is called, you continue with the rest of your code.


It's an important pattern to learn in "modern" programming, and it's not really hard — once you get your brain wrapped around it. 🙂


FWIW, Swift will eventually be enhanced to provide syntax that improves the readability of asynchronous code (something vaguely like C#'s async/await), but it'll be a while before that arrives. For the present, completion handlers are the way to go.

Thanks for the help, I see what you mean.

It looks like QuincyMorris is correct. I've never used an NSOpenPanel as a sheet, but it should work. There is a sheet method in NSSavePanel which should be accessible from NSOpenPanel.


func beginSheetModal(for window: NSWindow, completionHandler handler: @escaping (NSApplication.ModalResponse) -> Void)



It makes sense to save as a sheet since the document is already open. It would also make sense to use this method to add additional content to an already open document.