I need to handle that NSFontPanel has been closed. Is there any method which is called, when that happens? Thx for reply.
NSFontPanel is a subclass of NSPanel, which is a subclass of NSWindow. NSWindow has many delegate methods that will inform you of changes in window state.
In your window controller or app delegate, declare conformance to NSWindowDelegate, then obtain the font panel and set its delegate to the controller object. Finally, implement -windowWillClose: in the controller object, and take whatever action you need there.
For example:
/* AppDelegate.h */
#interface AppDelegate : NSObject <NSWindowDelegate>
#property (assign) IBOutlet NSWindow *window;
#end
/* AppDelegate.m */
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSFontPanel *fp = [[NSFontManager sharedFontManager] fontPanel:YES];
fp.delegate = self;
}
- (void)windowWillClose:(NSNotification *)notification
{
if(notification.object == [[NSFontManager sharedFontManager] fontPanel:NO])
{
/* Handle font panel close here */
NSLog(#"Font panel closing");
}
}
#end
Related
I'm trying to translate some old code to ARC. The old code does this in the WindowController:
#interface PreferencesController () <NSWindowDelegate>
#end
#implementation PreferencesController
-(void)windowWillClose:(NSNotification*) notification {
[self autorelease];
}
#end
My AppDelegate has a strong pointer to the WindowController:
#property(strong) PreferencesController* preferencesCtrl;
In PreferencesController, do I need to declare a (weak) pointer back to the AppDelegate, and then do something like this:
-(void) windowWillClose:(NSNotification *)notification {
[[self appDelegate] setPreferencesCtrl:nil];
}
Well, your thoughts are right.
But I can give you make it more simple.
Set your application delegate as NSWindowDelegate.
#interface AppDelegate : NSObject <NSApplicationDelegate, NSWindowDelegate>
#property (strong) PreferencesController* preferencesCtrl;
#end
#implementation AppDelegate
- (void)doAction
{
// create window
// ...
self.preferencesCtrl.window.delegate = self; // set window delegate
}
- (void)windowWillClose:(NSNotification *)notification
{
self.preferencesCtrl=nil;
}
#end
UPD
Since you are already using NSWindowDelegate methods, I suggest you to create another delegate protocol, say PreferenceControllerDelegate
//in PreferenceController.h before class interface
#class PreferenceControllerDelegate
#protocol PreferenceControllerDelegate <NSObject>
- (void)preferenceControllerWindowWillClose:(PreferenceControllerDelegate *)sender;
#end
#interface PreferenceController : NSWindowController
//...
#property (nonatomic,weak) id<PreferenceControllerDelegate> delegate;
//...
#end
That would be much proper.
Try using #autoreleasepool to force an immediate dealloc when you nil the pointer.
-(void) windowWillClose:(NSNotification *)notification {
//[[self appDelegate] setPreferencesCtrl:nil];
#autoreleasepool {
[[NSApp delegate] setPreferencesCtrl:nil];
}
}
You can also access the app delegate through the NSApp singleton using NSApp.delegate, which is [[NSApplication sharedApplication] delegate], though I guess you'd have to typecast it to avoid a warning. Either way.
I am developing an application in XCode 4.6.
To get text-change notifications from NSTextField controls I:
Put NSTextField control on window.
Connect control delegate to File's Owner via right-click in IB, drag from delegate to File's Owner.
Implement controlTextDidChange in window class.
For the application, the window class is my AppDelegate and File's Owner is NSApplication. For the modal dialog, the window class an NSWindowController and File's Owner is of the same type.
If I put a breakpoint in controlTextDidChange, in the AppDelegate class, it never fires. If I do the same procedure with a modal dialog it works fine.
I know in the main application window case the delegate for the control is not my AppDelegate.
What am I doing wrong in hooking up my control delegate in the main window? I must be missing something simple. Is File's Owner the correct delegate to set for controls?
Any help would be appreciated.
Here is some code as requested.
// AppDelegate.h
// SimpleApplication
#import <Cocoa/Cocoa.h>
#import "SimpleTest/SimpleTest.h"
#interface AppDelegate : NSObject <NSApplicationDelegate>
#property (assign) IBOutlet NSWindow *window;
#property (assign) IBOutlet NSTextField *textField;
#end
// AppDelegate.m
// SimpleApplication
#import "AppDelegate.h"
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Not much to do here for now.
}
// Breakpoint set in this function never fires.
- (void)controlTextDidChange:(NSNotification *)obj
{
NSMutableString* description= [[NSMutableString alloc] init];
id aDelegate= [_textField delegate];
Class delegateClass= [aDelegate class];
[description setString:[delegateClass description]];
[description release];
}
// To provide some information about the delegates.
- (IBAction)textChange:(id)sender
{
NSTextField* theTextField= (NSTextField*)sender;
NSMutableString* description= [[NSMutableString alloc] init];
id aDelegate= [theTextField delegate];
Class delegateClass= [aDelegate class];
[description setString:[delegateClass description]];
[description release];
}
#end
Here is a shot of the right-click information for the NSTextField on the main window -
Identity inspector shows File's Owner as NSApplication, which is what I see in the debugger when I put a breakpoint in textChange and hit return in the text field. However, self, the implementor of controlTextDidChange, is AppDelegate. By contrast, in a modal dialog, self and File's Owner are the same object, derived from NSWindowController.
So, the upshot is that I do not have the correct delegate assigned to the control in the main window - how do I do that?
Can you post some code?
When using delegates make sure you specify that a class implements the required protocol.
#interface MyClass : NSObject <SomeProtocol>
Also make sure you are creating a property to store the delegate.
#property (strong, nonatomic) id<SomeProtocol> delegate;
RE this:
Note that although NSControl defines delegate methods, it does not
itself have a delegate. Any subclass that uses these methods must have
a delegate and the methods to get and set it. In addition, a formal
delegate protocol NSControlTextEditingDelegate Protocol also defines
delegate methods used by control delegates.
...
These include: controlTextDidBeginEditing:, controlTextDidChange:, and controlTextDidEndEditing:
Oh, wow - in adding more detail to my question, I think I figured out the answer. Instead of dragging from text field delegate to File's Owner, just drag to the blue cube that represents App Delegate!
I'm trying to open a window using a NSWindowController in my app delegate.
I created a basic NSWindowController with an associated NIB and try to show the window that way:
#implementation MyAppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Show the main window from a separate nib
MyWindowController * theWindowController = [[MyWindowController alloc] initWithWindowNibName:#"MyWindowController"];
[theWindowController showWindow:self];
}
#end
When I launch the app, the window of MyWindowController only appears for a fraction of second (seems to be released as soon as it launches).
Using ARC, how could I force the window to stick around and not be flushed right away? I do not use NSDocuments and I want to be able to use many of these MyWindowController concurrently.
You need to add a property to your app delegate (or some other object that's going to stick around for the lifetime of your app) that retains theWindowConroller. For example:
#interface MyAppDelegate : NSObject
#property (strong, nonatomic) MyWindowController * windowController;
#end
Then set this property when you initialize the window controller.
#implementation MyAppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Show the main window from a separate nib
self.windowController = [[MyWindowController alloc] initWithWindowNibName:#"MyWindowController"];
[theWindowController showWindow:self];
}
#end
I am making a simple mac app in which i want to switch windows.
I have two NSWindowController class MainWindow and DetailWindow
I am using this code :
MainWindow class:
//MainWindow.h
#class DetailWindow;
#interface MainWindow : NSWindowController{
IBOutlet NSButton *btn1;
DetailWindow *detailwindow;
}
#property (nonatomic, retain) IBOutlet NSButton *btn1;
- (IBAction)btn1Event:(id)sender;
//MainWindow.m
#implementation MainWindow
#synthesize btn1;
- (IBAction)btn1Event:(id)sender {
if (!detailwindow) {
detailwindow = [[DetailWindow alloc] initWithWindowNibName:#"DetailWindow"];
}
[detailwindow showWindow:self];
}
#end
DetailWindow Class:
//DetailWindow.h
#class MainWindow;
#interface DetailWindow : NSWindowController{
IBOutlet NSButton *backbtn;
MainWindow *mainwindow;
}
#property (nonatomic, retain) IBOutlet NSButton *backbtn;
- (IBAction)back:(id)sender;
//DetailWindow.m
#implementation DetailWindow
#synthesize backbtn;
- (IBAction)back:(id)sender {
if (!mainwindow) {
mainwindow = [[MainWindow alloc] initWithWindowNibName:#"MainWindow"];
}
[mainwindow showWindow:self];
}
#end
Now the problem is when i click backbtn on DetaiWindow it will open a new MainWindow.
So i have two MainWindow on screen.
I want just main window at front when i click backbtn.
Any help??
Thank you..!!
Your basic problem is that each window is assuming that it is its own job to create the other. Each has an ivar for the other, but there's no external access to it -- via a property or being an IBOutlet or anything else -- so it always starts out as nil, and a new copy gets created instead of reusing the old one.
There are any number of ways to get around this. Probably the easiest would be to create both windows in Interface Builder and link them up there, having made the ivars IBOutlet. Then you know you never have to create them in code at all.
However, purely on the basis of inertia, here's an alternative that sticks closer to what you've got already. Note that I've assumed for simplicity that mainWindow always exists first. If not, you'll have to duplicate the process the other way around.
//MainWindow.h
#class DetailWindow;
#interface MainWindow : NSWindowController
{
IBOutlet NSButton *btn1;
DetailWindow *detailwindow;
}
#property (nonatomic, retain) NSButton *btn1;
- (IBAction)btn1Event:(id)sender;
//MainWindow.m
#implementation MainWindow
#synthesize btn1;
- (IBAction)btn1Event:(id)sender
{
if (!detailwindow)
{
detailwindow = [[DetailWindow alloc] initWithWindowNibName:#"DetailWindow"];
// having created the other window, give it a reference back to this one
detailWindow.mainWindow = self;
}
[detailwindow showWindow:self];
}
#end
//DetailWindow.h
#class MainWindow;
#interface DetailWindow : NSWindowController
{
IBOutlet NSButton *backbtn;
MainWindow *mainwindow;
}
#property (nonatomic, retain) NSButton *backbtn;
// allow the main window to be set from outside
#property (nonatomic, retain) MainWindow *mainWindow;
- (IBAction)back:(id)sender;
//DetailWindow.m
#implementation DetailWindow
#synthesize backbtn;
#synthesize mainWindow;
- (IBAction)back:(id)sender
{
// no window creation on the way back
NSAssert(mainWindow, "mainWindow not set!");
[mainwindow showWindow:self];
}
#end
Untested, so usual caveats apply.
You have to call orderFront: method with self object on main window.
To do this you must find a reference to the main window. A way to do this is:
[NSApp mainWindow];
This call will return you a pointer to your main window (If you did something incorrect, you could have to cycle through the [NSApp windows] array in order to search for your main window).
When you have found the window, send it a orderFront message, by doing (supposing the code above returns the correct window, as explained before).
[[NSApp mainWindow] orderFront:self];
and the window should magically order front.
I'm pretty new to mac development (coming from a web and iOS background) and I can't work out how I could get a notification every time the value of an NSTextView changes. Any ideas?
Ups I just saw that you want a callback from NSTextView and not NSTextField
Just add in the header of the object which should be the delegate the protocol
#interface delegateAppDelegate : NSObject <NSApplicationDelegate, NSTextViewDelegate> {
NSWindow *window;
}
After that you add a method like
-(void)textDidChange:(NSNotification *)notification {
NSLog(#"Ok");
}
Make sure you connected the delegate property of the NSTextView (not NSScrollView) with the object which should receive the delegate
Here's the solution:
NSTextView *textView = ...;
#interface MyClass : NSObject<NSTextStorageDelegate>
#property NSTextView *textView;
#end
MyClass *myClass = [[MyClass alloc] init];
myClass.textView = textView;
textView.textStorage.delegate = myClass;
#implementation MyClass
- (void)textStorageDidProcessEditing:(NSNotification *)aNotification
{
// self.textView.string will be the current value of the NSTextView
// and this will get invoked whenever the textView's value changes,
// BOTH from user changes (like typing) or programmatic changes,
// like textView.string = #"Foo";
}
#end
set the nstextfield's delegate. in the .h file of the delegate you add the delegate protocol
In the .m file you add a method like -(void)controlTextDidChange:(NSNotification *)obj {
NSLog(#"ok");
}
I hope that helps
Set the delegate and then use
- (void) controlTextDidChange: (NSNotification *) notification
{
}