I need progress feedback in my app. Using an NSWindowcontroller (subclass IndicatorWindowController) that controls a Window containing an NSProgressIndicator (myBar). Everything works fine if I don't finish the procedure with [myIWC.myWindow close]. If I have this command, the window won't even show.
- (IBAction)runIndicatorWindow:(id)sender;
{
IndicatorWindowController* myIWC = [[IndicatorWindowController alloc] initWithWindowNibName:#"ProgressWindow"];
[myIWC showWindow:sender];
for (double barLoop=0; barLoop<=100; barLoop++) {
myIWC.myBar.doubleValue = barLoop;
[myIWC.myBar display];
}
[myIWC.myWindow close];//<-When this is not commented out, nothing shows
}
Related
I have a menu application and I'm launching a NSPanel from a menu item: when the user clicks on the menu item I lazily instantiate a custom NSWindowController (just the first time), and then I show it calling showWindow:
The custom NSViewController is linked to a xib file:
This is how I create it:
// #property (nonatomic,strong) AddFeedController* addFeedController;
- (AddFeedController*) addFeedController
{
if (!_addFeedController)
{
_addFeedController = [[AddFeedController alloc]initWithWindowNibName:#"AddFeedController"];
}
return _addFeedController;
}
The problem is that if I try to paste some text inside of one of those two text field, it doesn't paste anything and it beeps.
EDIT
I managed to restore the original menu (I had to copy it from another project's xib, because only the original is recognized), and I modified the addFeedController accessor this way:
- (AddFeedController*) addFeedController
{
if (!_addFeedController)
{
_addFeedController = [[AddFeedController alloc]initWithWindowNibName:#"AddFeedController"];
[_addFeedController.window setLevel: NSPopUpMenuWindowLevel];
}
return _addFeedController;
}
I also modified the method that displays the window:
- (IBAction) launchFeedController : (id) sender
{
[self.addFeedController showWindow: self];
// I added these lines:
[NSApp activateIgnoringOtherApps:YES];
[self.addFeedController.window makeKeyAndOrderFront:self];
}
The first time the panel appears immediately, with no problem. But when I close the panel and try to launch it a second time it doesn't appear.
This is probably something simple that I am missing but this is what is happening:
I am making a Menu item app (application is agent = YES)
So I have a MainViewAppDelegate that kind of runs the entire thing. It gets a detection when a button on the menu item gets clicked.
Then I have an upload NSWindowController:
#import <Cocoa/Cocoa.h>
#interface UploadView : NSWindowController
- (IBAction)upload:(id)sender;
#end
.m:
-(id)init {
if (! (self = [super initWithWindowNibName:#"UploadView"])) {
// Initialization code here.
return nil;
}
return self;
}
In MainViewAppDelegate, when that button is pressed I do:
if (!uploadView) {
uploadView = [[UploadView alloc] init];
}
[uploadView showWindow:self];
Now, this works as long as I don't click out of xcode. Once I do that (say I make chrome the active tab) then it does not work anymore even if I go back to xcode.
Any thoughts?
I dont see any issue in the UploadView code. But can you try connecting the UploadView Panel in xib to File's Owner window outlet and try. I created a similar demo now and tried and i dont see any issue.
All I had to add was:
[NSApp activateIgnoringOtherApps:YES];
before trying to open the window.
I have an UIWebView loaded with div, act as editor to write. Now i am adding UIWebView as sub view on UIWindow to set the frame equal to full screen and to hide the UIKeyboard, but at some button method, i need to get UIWebview from UIWindow and sent it back to UIKeyboard. Here is my code which is not working:
keyboardWindowFrame= nil;
for (UIWindow *testWindow in [[UIApplication sharedApplication] windows])
{
if (![[testWindow class] isEqual:[UIWindow class]])
{
keyboardWindowFrame = testWindow;
[webViewForEditing setFrame:CGRectMake(5, 63, 310, 400)];
[webViewForEditing.scrollView setContentSize:CGSizeMake(310, 400)];
[keyboardWindowFrame addSubview:webViewForEditing];
break;
}
}
- (IBAction)keyboardButtonSelected:(id)sender
{
[keyboardWindowFrame sendSubviewToBack:webViewForEditing]; //need to send UIWebView back to UIWindow so i can write
}
I think I am trying to do the same thing as you and so although your question is not particularly clear hopefully my answer will help.
It seems that you have a view 'webViewForEditing' which you want to add and bring in front of the keyboard. When you click a button you want to put this view behind the keyboard again.
I have also tried using the sendSubViewToBack code with no joy.
In the end though I managed to get it to work using:
[[self view] exchangeSubviewAtIndex: withSubviewAtIndex: ];
(Credit goes to Sunny with it adapted from a question here)
I used the following code below, with to switch between a UIView and the keyboard:
- (IBAction)toggleButtonPressed:(id)sender {
UIWindow * window = [UIApplication sharedApplication].windows.lastObject;
if (window.subviews.count == 1) {
[window addSubview:_menuView];
}
else {
[window exchangeSubviewAtIndex: 0 withSubviewAtIndex: 1];
}
}
I am only working with two views (_menuView and the keyboard) which means I check how many subviews my window has to make sure I only add _menuView once.
Then it is easy to exchange the two views.
Even if you had more subviews in your window I am sure you could use a modified version of this. As long as none of your other views change places then exchanging them will always switch the same two views.
NOTE: As an aside. I am not sure if this code works if called when the keyboard is not first responder. I get the variable for Window using the last object in the window, which is always the keyboard if it has been made first responder. It might need tweaking to get it working at other times.
I formulated another, more eloquent, answer while working on this:
Add the views you want to the window view that holds the keyboard view:
#interface BViewController : UIViewController {
UIWindow * window;
}
// Add the code when the keyboard is showing to ensure it is added while we have a keyboard and to make sure it is only added once
-(void) keyboardDidShow: (NSNotification *) notification {
window = [UIApplication sharedApplication].windows.lastObject;
if (window.subviews.count == 1) {
[window addSubview:_menuView];
[window addSubview:_gameView];
[window addSubview:_stickerView];
[self hideViews];
}
}
- (void)hideViews {
_menuView.hidden = YES;
_gameView.hidden = YES;
_stickerView.hidden = YES;
}
So now we have our UIWindow view which contains our views and also our keyboard. They are all hidden so our keyboard appears at the front and can be typed on.
Now use a simple function to decide which view to bring in front of the keyboard:
- (void)bringViewToFront: (UIView *)view {
[self hideViews];
view.hidden = NO;
}
Hiding the views makes sure we only have our correct view at the front.
I spent a lot of time thinking how we could move different views forward and back, using the exchange function. Actually using hide and reveal means we can get our view immediately and still easily have access to the keyboard by hiding all the views.
I'm writing a multi-document application using Cocoa. The user must enter a password when opening a document. After a certain amount of time without activities on a document the user is once again required to enter the password.
Right now I'm using NSAplication's beginSheet:modalForWindow:modalDelegate:didEndSelector:contextInfo: to show the password prompt in a custom sheet. While it works it has the unfortunate side-effect of the window being brought to front and given focus even if another document is being worked on at the time. It is only problematic if my application is in front.
Is there a way to prevent opening a sheet from snatching focus if its parent window is not active?
There isn't a simple way. The hacky way would be to make a subclass of NSWindow for both the document's window and the sheet's window, and in that class, override both orderFront: and makeKeyWindow to do nothing during the time you call beginSheet. For example,
In the NSWindow subclass:
-(void)awakeFromNib
{
hack = NO;
}
-(void)hackOnHackOff:(BOOL)foo
{
hack = foo;
}
- (void)orderFront:(id)sender
{
if (!hack)
[super orderFront:sender];
}
- (void)makeKeyWindow
{
if (!hack)
[super makeKeyWindow];
}
And then your beginSheet call would look like:
-(void)sheet
{
SpecialSheetWindow* documentWindow = [self windowForSheet];
[documentWindow hackOnHackOff:YES];
[sheetWindow hackOnHackOff:YES];
[[NSApplication sharedApplication] beginSheet:sheetWindow
modalForWindow:documentWindow
modalDelegate:self didEndSelector:#selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:nil];
[documentWindow hackOnHackOff:NO];
[sheetWindow hackOnHackOff:NO];
}
I have a Mac OS X app written in objetive-c Cocoa. You can see most of the code in this previous question. Essentially you click a button on the main window (the app delegate) and it opens another window where the user can enter information.
In the following code (that gets called when the user press the button in the app's main window)
- (IBAction)OnLaunch:(id)sender {
MyClass *controllerWindow = [[MyClass alloc] initWithWindowNibName:#"pop"];
[controllerWindow showWindow:self];
NSLog(#"this is a log line");
}
The NSLog line gets printer immediately after I called showWindow. Is there any way to wait until controllerWindow is closed to continue with the NSlog?
The reason for this is that the user set's a value on the new window I opened and I need to collect that value on the same OnLaunch so I need to wait.
I know that modal windows are bad form in Mac, but I have no control over this feature.
I've tried with
[NSApp runModalForWindow:[controllerWindow window]];
and then setting the popup window to
[[NSApplication sharedApplication] runModalForWindow:popupwin];
and it works but then the focus never gets passed to the main window anymore
Thanks!
If you want the window to be modal for your application, use a sheet: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Sheets/Tasks/UsingCustomSheets.html
However, there is no way to suspend execution of a method while the sheet is displayed, this would be tantamount to blocking the current run loop. You would have to break you code into the begin and end methods as described in the linked documentation.
Here are the steps you need to follow:
In TestAppAppDelegate create an NSWindow outlet to hold your sheet and an action to dismiss the sheet
Create a nib with an NSWindow as the root object. I think you already have this in "pop". Set the Visible at Launch option to NO (this is very important)
Set the file's owner of this nib to TestAppAppDelegate and connect the window to your new outlet, and the close button to your new action
In your method to launch the sheet (OnLaunch), use the following code:
(ignore this it's to make the code format properly!)
if(!self.sheet)
[NSBundle loadNibNamed:#"Sheet" owner:self];
[NSApp beginSheet:self.sheet
modalForWindow:self.window
modalDelegate:self
didEndSelector:#selector(didEndSheet:returnCode:contextInfo:)
contextInfo:nil];
Your close button action should be [NSApp endSheet:self.sheet];
Your didEndSheet: method should be [self.sheet orderOut:self];
You can use UIVIew method animateWithDuration:delay:options:animations:completion: to accomplish this.
You said you want the next line to execute once the window is closed, rather than after it is opened. In any case, you may end the OnLaunch method this way:
- (IBAction)OnLaunch:(id)sender {
MyClass *controllerWindow = [[MyClass alloc] initWithWindowNibName:#"pop"];
[controllerWindow animateWithDuration:someDelay:options: someUIAnimationOption
animations:^{
[controllerWindow showWindow:self]; // now you can animate it in the showWindow method
}
completion:^{
[self windowDidFinishShowing]; // or [self windowDidFinishDisappearing]
}
}
- (void) windowDidFinishShowing {
NSLog(#"this is a log line");
}