I have implemented my sheet (NSPanel) with the following method:
- (void)showInWindow:(NSWindow *)mainWindow {
if (!finestra1)
[NSBundle loadNibNamed:#"XibName" owner:self];
[NSApp beginSheet:finestra1 modalForWindow:mainWindow modalDelegate:nil didEndSelector:nil contextInfo:nil];
[NSApp runModalForWindow:finestra1]; //This call blocks the execution until [NSApp stopModal] is called
}
The sheet is appearing in the middle of my screen, how to attach it to the top of my main window and make it appear with a "slide down" effect instead?
Thanks in advance.
Have you tried simply removing the -runModalForWindow: line?
The way I was taught, the sheet you're presenting should be an NSWindow, not an NSPanel.
Let me know if you'd like me to upload a simple demo project.
Related
I'm trying to get a sheet to display modally when the app finishes launching. If I place the code in a generic action and execute it somewhere after app launch, it works as desired and the sheet drops down nicely. If I take the same code and place it in applicationdidfinishlaunching, the sheet displays as a separate window (which is not what I need).
[NSApp beginSheet:settingsWindow
modalForWindow:[NSApp keyWindow]
modalDelegate:nil
didEndSelector:nil
contextInfo:nil];
[NSApp runModalForWindow:settingsWindow];
[NSApp endSheet:settingsWindow];
[settingsWindow orderOut:self];
The visible at launch option is disabled. Grateful for any suggestions. I also tried it in awakefromnib with the same incorrect result.
Edit: Using [self performSelector:#selector(someAction:) withObject:self afterDelay:0.5]; where the contents of someAction are as above, yields the correct result. Why is this?
NSApp's beginSheet: modalForWindow: modalDelegate: didEndSelector: contextInfo: and endSheet: are deprecated in OS X 10.10. You should instead use beginSheet: completionHandler: on NSWindow instance to show the sheet window modally.
NSWindow *mainWindow = [NSApp windows][0];
[mainWindow beginSheet:settingsWindow completionHandler: nil];
By the way, does the [NSApp keyWindow] return an instance in didFinishLaunching?
How do I implement the view in following image.
The view which appears when + button is clicked in System Preferences > Network
I have following questions:
Does this view system has a specific name (like popover), because I have seen it in many places in Mac.
How to implement it in IB ?
Can this be done in a popover window instead of NSWindow ?(or is it only possible in NSWindow like toolbar)
Update:
Updating the title for better visibility
In Cocoa these are called sheets. Take a look at the sheet programming guide, however, this is terribly out of date!
You need to call -beginSheet:completionHandler: on the window you want to display the sheet. If you have single-window application you can ask the AppDelegate for the window and launch the sheet like so,
// This code should be in AppDelegate which implement the -window method
NSWindow *targetWindow = [self window]; // the window to which you want to attach the sheet
NSWindow *sheetWindow = self.sheetWindowController.window // the window you want to display at a sheet
// Now start-up the sheet
[targetWindow beginSheet:sheetWindow completionHandler:^(NSModalResponse returnCode) {
switch (returnCode) {
case NSModalResponseCancel:
NSLog(#"%#", #"NSModalResponseCancel");
break;
case NSModalResponseOK:
NSLog(#"%#", #"NSModalResponseOK");
break;
default:
break;
}
}];
You will notice that when the sheet completes it will return a certain modal response --- we will return to this point in a shortly.
Next you need to implement the content that you want to display in the sheet; this must be done in an NSWindow. I find it much easier to use a NSWindowController and implement the window in a separate XIB file. For example, see below,
Now you need to implement the code in your custom NSWindowController (or plain NSWindow if you are old-school and love to manage your own NIB loading) which will issue the correct modal response. Here I have hooked up the cancel and OK buttons to the following actions methods,
- (IBAction)cancelButtonAction:(id)sender {
[[[self window] sheetParent] endSheet:self.window returnCode:NSModalResponseCancel];
}
- (IBAction)OKButtonAction:(id)sender {
[[[self window] sheetParent] endSheet:self.window returnCode:NSModalResponseOK];
}
The model response will get sent to your completion handler block.
Sample project on github.
I am very much new to OSX development. Consider this as my first app. I want to display a sheet when a button is clicked on the main window. I am using Nib
Following is my code for .h file
#import <Foundation/Foundation.h>
#import "WebKit/Webkit.h"
#interface MainViewObject : NSObject
- (IBAction)accountButtonPressed:(id)sender;
- (IBAction)cancelSheetButtonPressed:(id)sender;
.m file as follows
#import "MainViewObject.h"
#implementation MainViewObject
- (IBAction)accountButtonPressed:(id)sender {
[NSApp beginSheet:self.accountSheet
modalForWindow:[mainWindowView window]
modalDelegate:nil
didEndSelector:nil
contextInfo:nil];
[NSApp runModalForWindow:self.accountSheet];
[NSApp endSheet:self.accountSheet];
[self.accountSheet orderOut:self];
}
- (IBAction)cancelSheetButtonPressed:(id)sender {
// Return to normal event handling
[NSApp endSheet:self.accountSheet];
// Hide the sheet
[self.accountSheet orderOut:sender];
}
When I run the app I get something like this:
http://i.imgur.com/DzJJ6.png
I am stuck and I have no idea what wrong in this. I am not able to get the sheet and the not able to even close the app. I have referred to some examples on internet.
- (IBAction)accountButtonPressed:(id)sender {
[NSApp beginSheet:self.accountSheet
modalForWindow:[mainWindowView window]
modalDelegate:nil
didEndSelector:nil
contextInfo:nil];
[NSApp runModalForWindow:self.accountSheet];
[NSApp endSheet:self.accountSheet];
[self.accountSheet orderOut:self];
}
Wow, looking at that, it's no surprise the screenshot looks as it is.
Let's walk through that one line at a time. When you click the Accounts button, you're doing 4 things immediately in succession:
You're telling the application to begin showing the sheet attached to your main window. This is OK, and is actually the only code you want in that accountButtonPressed: method.
Right after beginning that sheet, you tell the application you want to also show that sheet all by itself (not attached to any windows but right in the middle of the screen), in an application-modal fashion, which blocks all other events from being processed in the application. In other words, this line doesn't really make sense. You either show a window as a sheet in a "document-modal" fashion (which only ties up the window that the sheet is attached to) or in an "application-modal" fashion, but not both at the same time. ;-)
Immediately after having just shown the sheet, you tell NSApp to stop showing the sheet. Now, you do want to do this eventually, but dismissing the sheet 0.0005 seconds after having just shown it will likely leave your users a little frustrated.
You now tell the sheet to hide itself. This needs to be done from your didEndSelector: method, which brings us to the problems in your first method.
-
[NSApp beginSheet:self.accountSheet
modalForWindow:[mainWindowView window]
modalDelegate:nil
didEndSelector:nil
contextInfo:nil];
This is good but read the documentation for beginSheet:modalForWindow:modalDelegate:didEndSelector:contextInfo: and also the Sheet Programming Topics: Using Custom Sheets. (The Companion guides links at the top of Class Reference pages are especially helpful for learning how to use the APIs in the real world. They were extremely helpful when I was learning).
Specifying nil for the modalDelegate: means you don't have anything that's waiting to be notified about when the sheet has stopped being shown (this happens when you call [NSApp endSheet:sheet]). You also haven't specified the #selector you want called when the sheet is ended. A selector is kind of like a function, aka a "method".
Your code should look something like this:
#implementation MDAppDelegate
- (IBAction)showSheet:(id)sender {
[NSApp beginSheet:self.sheet
modalForWindow:self.window
modalDelegate:self
didEndSelector:#selector(sheetDidEnd:returnCode:contextInfo:)
contextInfo:NULL];
}
- (IBAction)cancel:(id)sender {
[NSApp endSheet:self.sheet];
}
- (IBAction)ok:(id)sender {
[NSApp endSheet:self.sheet];
}
- (void)sheetDidEnd:(NSWindow *)sheet
returnCode:(NSInteger)returnCode
contextInfo:(void *)contextInfo {
[sheet orderOut:nil];
}
#end
In this example, you click the Show Sheet button, and the sheet starts being shown attached to the main window. In the sheet, there is a Cancel and an OK button, which both call their respective methods. In each of these methods, you call [NSApp endSheet:self.sheet]. This tells NSApp that it should then call the sheetDidEnd:returnCode:contextInfo: method on the object specified to be the modal delegate. In sheetDidEnd:returnCode:contextInfo: you then tell the sheet to hide itself.
EDIT:
Every NSWindow has a "Visible at launch" flag that can be set in Interface Builder. If this flag is set, the window will be visible at the time the nib file is loaded. If it isn't set, the window is hidden until you programmatically show it. Just edit the flag in the nib file like shown:
I've created a sheet which I would like to display various messages while the program is doing data crunching. The sheet opens and closes correctly and I have a Text Label on the sheet which is connected to my main controller (the owner of the sheet) with an IB Outlet.
The Nib loads correctly, open and closes correctly, but the static text label is never updated. The connected IBOutlet was defined this way:
IBOutlet id mySheetText;
The call I am using to try and modify the text on the sheet is this:
[mySheetText setStringValue:#"Some text message..."];
This format works fine if the Label is in the main window, but does nothing if the Label is on the sheet.
All the connections in IB appear to be correct. I'm sure that I'm missing something very simple, and i'm guessing that it has something to do with the fact that the sheet is a different "window" than the main window, but I can't seem to find anything in the docs to point me in the right direction.
Incidentally, here is the way I connected the sheet...
NSWindow *mySheet;
#property (assign) IBOutlet NSWindow *mySheet;
#synthesize mySheet;
...and opened it:
if (!serverSyncSheet) {
[NSBundle loadNibNamed:#"mySheetNibFile" owner:self];
}
[NSApp beginSheet: self.mySheet
modalForWindow: [[NSApp delegate] mainWindow]
modalDelegate: self
didEndSelector: NULL
contextInfo: NULL];
Any ideas?
* EDIT *
Ok, so it turns out that I am partially correct. If I attempt to read the text value, it turns out that it IS setting it to the correct text, but the sheet is not being updated to DISPLAY the change. I suspect that I need to tell the window to redraw... never done that before. Back to the docs to see if I can find it. If anyone knows the method to call, let me know. :) Thanks!
Well, my suspicions were correct... it was something simple.
I just had to redraw the window:
[mySheet display];
Doh! :)
I have an application that will load a couple of windows depending on which button is pressed. All except one of these open on the mainScreen (the screen in which the main window is open in). One of them (the preference window) opens on the first screen (the screen with the menu bar). I cannot understand way it is doing this, is there a way to change the screen that a NSWindow opens on?
I could not get toohtik's answer to work. What I ended up doing was subclassing NSWindow and then overriding constrainFrameRect: toScreen:. This will automatically open the new window on the "main screen" of the application.
- (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
{
AppDelegate *delegate = [[NSApplication sharedApplication] delegate];
return [super constrainFrameRect:frameRect toScreen:delegate.window.screen];
}
I dont't know why you have that behaviour but you can change it through initWithFrame method that takes NSScreen argument.