NSTextView value changed - events

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
{
}

Related

How do I validate an NSButton in an NSToolbar?

I have a document-based app with a tool bar containing several NSButton which I need to validate. Base on other code here, I have subclassed NSToolbar:
#interface CustomToolbar : NSToolbar
#end
#implementation CustomToolbar
-(void)validateVisibleItems
{
for (NSToolbarItem *toolbarItem in self.visibleItems)
{
NSResponder *responder = toolbarItem.view;
while ((responder = [responder nextResponder]))
{
if ([responder respondsToSelector:toolbarItem.action])
{
[responder performSelector:#selector(validateToolbarItem:) withObject:toolbarItem];
}
}
}
}
#end
MyDocument (the File's owner) is set as the delegate of the toolbar. However
-(BOOL)validateToolbarItem:(NSToolbarItem *)toolbarItem
is never called. The buttons have an action set on them, so not sure why [responder respondsToSelector:toolbarItem.action] is always false.
I have tried subclassing the NSButton items:
#interface DocumentToolbarActionItem : NSToolbarItem
#implementation DocumentToolbarActionItem
-(void)validate
{
Document* document = [[self toolbar] delegate];
[self setEnabled:[document validateUserInterfaceItem:self]];
}
#end
But this results in an endless loop.
The document's validateUserInterfaceItem: method works for all other items in the app and I need to have my toolbar button call it to determine if they should be enabled or not.
My guess is that you're not calling through [super validateVisibleItems] and, so, losing the superclass behaviour of validation through the responder chain.

NSFontPanel - How to handle closing

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

Incorrect Delegate for Controls on Main Application Window

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!

auto resize textfield when textfield is editing

I have problem with my project on Mac OS. I have a textfield, I want to change size it automatically when textfield is editing!Please suggest me a way to solve this. Thanks so much!
You need to set an object as the delegate of your NSTextField. As NSTextField is a subclass of NSControl, it will call the -controlTextDidChange: method on your object if you implement it.
#interface MyObject : NSObject
{
IBOutlet NSTextField* textField;
}
#end
#implementation MyObject
- (void)awakeFromNib
{
[textField setDelegate:self];
}
- (void)controlTextDidChange:(NSNotification *)aNotification
{
if([notification object] == textField)
{
textField.font = [UIFont fontWithName:#"HelveticaNeue-Light" size:14];
}
}
#end

UILabel subclass

I know that this is a newbie question but I am a newbie so here goes:
I wish to use Chalkduster font quite a lot throughout my app (buttons, labels etc) and have tried subclassing UILabel to achieve this. I have the following in Default.h:
#import <UIKit/UIKit.h>
#interface Default : UILabel
{
UILabel *theLabel;
}
#property (nonatomic, strong) IBOutlet UILabel *theLabel;
#end
and this in my .m:
#import "Default.h"
#implementation Default
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
UIFont *custom = [[UIFont alloc] init];
custom = [UIFont fontWithName:#"Chalkduster" size:18];
self.font = custom;
NSLog(#"h");
}
return self;
}
#end
When I change the class in interface builder and run, I'm not seeing the Chalkduster font. I'd appreciate a hand in getting this set up as I believe it will save me a lot of time.
Cheers.
Some problems to fix:
1) You're mixing up the idea of Default being a label and Default containing a label. To subclass, get rid of the property inside your class and make your changes to self rather than theLabel (inside the if (self) { section).
2) Anything you code after an unconditional return isn't going to get executed...and I'm surprised the compiler didn't complain about those statements.
Edit: ...and one more thing that just dawned on me.
3) If you're loading from a xib or storyboard, the initialization is done by initWithCoder: instead of initWithFrame:, so:
- (id)initWithCoder:(NSCoder *)coder {
self = [super initWithCoder:coder];
if (self) {
self.font = [UIFont fontWithName:#"Chalkduster" size:18];
}
return self;
}
First of all I don't think that You're subclassing UILabel correctlly. So I made tutorial for You explaining how to do it. You don't need to IBOutlet object which is subclassed. JUST CALL IT WITH SELF. for example: self.font = ... If You want to subclass UILabel do this:
Create new class with title myLabel like this:
.h
#import <UIKit/UIKit.h>
#interface MyLabel : UILabel {
}
#end
.m
#import "MyLabel.h"
#implementation MyLabel
-(void)awakeFromNib {
UIFont *custom = [[UIFont alloc] init];
custom = [UIFont fontWithName:#"Chalkduster" size:18];
self.font = custom;
}
#end
Now select Your label in storyboard and go to indentity inspector and in Custom Class select created class above. Like this:
Output:
Note: Don't forget to release custom because You are allocating it.
Move the return self; three lines down. You return from the init method before you do your custom initialization.
Edit to reflect new information from comment:
When deserializing the view from a nib you also have to override initWithCoder:

Resources