Custom NSCell drawWithFrame:inView method not getting invoked in OSX 10.8 - objective-c

I have an application where I have defined a custom cell and have overridden the method
- (void) drawWithFrame:inView:
This method was drawing my custom cells without any problems as long as I was building my app using Xcode 3.2 on OS X 10.6 or older.
Now I am attempting to migrate the code to build with Xcode 4+ on OS X 10.8. And what I have found out is that my custom cell is not getting drawn anymore. After putting break points and running the app through the debugger, I realized that the overridden - (void) drawWithFrame:inView: method of the custom cell is not getting invoked at all.
My questions are:
1) What is it that makes this method to not invoke at all on OS X 10.8, while it gets invoked and works perfectly fine on OS X 10.6 or older?
2) What alternative do I have to fix this issue?
Thanks,
Mriganka

I am having the same problem, except i am using xcode 4.x on OSX 10.7
Maybe its an xcode 4.x thing?
What I have noticed is that drawWithFrame on my subclassed NSTextFieldCell does NOT get invoked when i call setEnabled (changing from YES to NO or NO to YES) on the parent NSTextField, after initialization of my NSTextFieldCell, but before drawWithFrame on that NSCell gets invoked automatically.
However, if I call setEnabled (after initializing my subclassed NSTextFieldCell) and no change occurs (ie. setEnabled:YES but it is already set to YES), then drawWithFrame does indeed get invoked.
Unfortunately, i need to perform setEnabled from YES to NO to YES, as i want to disable my NSTextField while a server call is being made, and then enable it on the callback. If the callback is (for example 'wrong password'), i need to custom draw the NSTextFieldCell border red.. and I have to do this by overriding drawWithFrame.
My guess is that setEnabled utilizes NSGraphicsContext and does a savesGraphicsState/restoreGraphicsState (perhaps in error), which throws off the graphics context that is utilized in NSTextFieldCell/drawWithFrame.
My guess is that the NSGraphicsContext within setEnabled is ONLY utilized if a change occurs (setEnabled from YES to NO or NO to YES), since when a change DOES NOT occur, I have no issue… I think this would make sense as there would be no point in rendering new graphics to show the user that the view is not selectable or editable, because it does indeed ALREADY LOOK not selectable or editable.

The answer to my problem was to re-draw manually after i called setEnabled, by calling setNeedsDisplay on the NSTextField.
I think this will probably work for you as well, as it causes the draw to occur manually.
glhf!
-Eric

Related

How to get an NSDocument subclass to print custom views

What needs to be hooked up for an NSDocument subclass to call its print methods when File->Print... is chosen?
How does the File->Print menu get hooked up? (Right now the selector/action is hooked up to first responder's print method. That's in a storyboard, while my NSDocument subclass has its own xib.)
I've tried implementing all of:
-(void)print:(id)sender;
-(void)printDocument:(id)sender;
-(void)printDocumentWithSettings:(NSDictionary *)printSettings showPrintPanel:(BOOL)showPrintPanel delegate:(id)delegate didPrintSelector:(SEL)didPrintSelector contextInfo:(void *)contextInfo;
-(NSPrintOperation*)printOperationWithSettings:(NSDictionary *)printSettings error:(NSError *__autoreleasing *)outError;
But none of them are ever called when I choose Print. Where are these methods supposed to go/who calls them? (I also tried a basic app with a custom view and didn't have luck there either.)
Okay. Looks like the problem is due to a bug in Xcode: When creating a Document based app using storyboards the file menu is by default hooked to print: and printDocument: is not available.
The strange part is that my print: call is getting hijacked somewhere along the line but I can't figure out where (at the application level, not the document, because the print dialog is a window not a sheet). printDocument: works as expected, but must be defined manually in order to hook it up.
This is for a document-based app, targeting 10.10, and using storyboards.
In the storyboard with Main Menu, add a User Defined Action for printDocument: (This is where storyboard based differs, and I feel is a bug. Xib based do not require this User Defined Action.)
Hook up the selector for File -> Print to First Responder and choose printDocument: instead of print:
Don't define printDocument: in your NSDocument subclass. If you want to, then be sure to call super or perhaps one of the methods below.
From NSDocument.h
/* The action of the File menu's Print... item in a document-based application.
The default implementation of this method merely invokes
[self printDocumentWithSettings:[NSDictionary dictionary]
showPrintPanel:YES
delegate:nil
didPrintSelector:NULL
contextInfo:NULL].
*/
- (IBAction)printDocument:(id)sender;
The default implementation of printDocumentWithSettings in turn calls printOperationWithSettings, so you can use either of those methods to draw custom information prior to the print sheet appearing.
The accepted solution of setting the menu item to -printDocument: is correct, but not (technically) because of an Xcode bug. (It is very a poor default setting, though.)
The menu item is calling the -print: of the whatever is the first-responder. NSView implements -print:, so if anything has been set as first-responder you will print with NSView's -print:, not your document's -print:. If editing your document requires text editing, the control you are using to implement editing will be set to first-responder, and that control will get the -print:.
Take a look at the TextEdit sample code from Apple (https://developer.apple.com/library/mac/samplecode/TextEdit/Introduction/Intro.html)
In my non-document based app I have set a custom action for the print menu item. In that method I notified my controller about the print operation via NSNotificationCenter. Maybe that works for you too :)

How to programmatically terminate an NSDraggingSession?

Context:
OS X Application implemented in Cocoa/ObjC
Xcode 6.1
Base SDK: 10.0
Deployment Target: 10.8+
Question:
In my app, I have a custom NSView subclass which implements NSDraggingSource. I'm using the new NSDraggingSession-based API (not the old deprecated one).
I have my dragging source fully implemented, no problems.
I am already implementing:
-[NSDraggingSource draggingSession:movedToPoint:]
I would like to additionally do some hit detection within this method and depending on the results of that hit test, possibly cancel the current drag session programmatically.
So: What is the best way to cancel/terminate the current NSDraggingSession programmatically? (preferably from -[NSDraggingSource draggingSession:movedToPoint:])
It might be nice to also be able to specify the NSDragOperation upon termination too.
Notes:
I've tried calling -[NSResponder cancelOperation:] on my custom view, thinking this might have something to do with dragging sessions, but that doesn't work. I get an exception with unrecognized selector.
I DO NOT need help doing hit detection.
I DO NOT need help implementing NSDraggingSource in general.

UISegmentedControl setSelectedSegmentIndex issue

I have a weird problem with UISegmentedControl.
I'm setting the selected segment index by using the method:
[self.toolbarSegmentedControl setSelectedSegmentIndex:0];
So the problem is - the click handler:
- (IBAction)segmentedControlClick:(id)sender
is not called in simulator but under device it IS called when passing this method. Why so and where is the wrong and right behavoir?
Your handler is intercepting the event UIControlEventValueChanged.
When you change a value of a UIControl programmatically, you should not count on that this event will be invoked, because only user interactions should send actions of UIControl.
Instead, if you wish, you can invoke it yourself:
[self.toolbarSegmentedControl setSelectedSegmentIndex:0];
[self.toolbarSegmentedControl sendActionsForControlEvents:UIControlEventValueChanged];
That will do it.
Perhaps the iOS version on your device is different to that of your simulator.
The behaviour of setSelectedSegmentIndex has changed in iOS5 -- specifically, segmentChangeAction is no longer called as a result. See this other Stack Overflow question for details.

How to activate a custom screensaver preview in Cocoa/Obj-C?

I have created a fairly simple screensaver that runs on Mac OS 10.6.5 without issue.
The configuration screen has accumulated quite a few different options and I'm trying to implement my own preview on the configureSheet window so the user (just me, currently) can immediately see the effect of a change without having to OK and Test each change.
I've added an NSView to the configureSheet and set the custom class in Interface Builder to my ScreenSaverView subclass. I know that drawRect: is firing, because I can remove the condition for clearing the view to black, and my custom preview no longer appears with the black background.
Here is that function (based on several fine tutorials on the Internet):
- (void)drawRect:(NSRect)rect
{
if ( shouldDrawBackground )
{
[super drawRect:rect];
shouldDrawBackground = NO;
}
if (pausing == NO)
[spiroForm drawForm];
}
The spiroForm class simply draws itself into the ScreenSaverView frame using NSBezierPath and, as mentioned, is not problematical for the actual screensaver or the built-in System Preferences preview. The custom preview (configureView) frame is passed into the init method for, um, itself (since its custom class is my ScreenSaverView subclass.) The -initWithFrame method is called in configureSheet before returning the configureSheet object to the OS:
[configureView initWithFrame:[configureView bounds] isPreview:YES];
Maybe I don't have to do that? It was just something I tried to see if it was required for drawing.
I eventually added a delegate to the configureSheet to try triggering the startAnimation and stopAnimation functions of my preview via windowWillBeginSheet and windowWillEndSheet notifications, but those don't appear to be getting called for some reason. The delegate is declared as NSObject <NSWindowDelegate> and I set the delegate in the configureSheet method before returning the configureSheet object.
I've been working on this for days, but haven't been able to find anything about how the OS manages the ScreenSaverView objects (which I think is what I'm trying to emulate by running my own copy.)
Does anybody have any suggestions on how to manage this or if Apple documents it somewhere that I haven't found? This isn't really required for the screensaver to work, I just think it would be fun (I also looked for a way to use the OS preview, but it's blocked while the configureSheet is activated.)
OK, there are a couple of 'duh' moments involved with the solution:
First of all, I was setting the delegate for the sheet notifications to the sheet itself. The window that the sheet belongs to gets the notifications.
Secondly, that very window that the sheet belongs to is owned by System Preferences, I don't see any way to set my delegate class as a delegate to that window, so the whole delegate thing doesn't appear to be a viable solution.
I ended up subclassing NSWindow for the configureSheet so that I could start and stop animation on my preview by over-riding the makeKeyWindow and close methods.
- (void) makeKeyWindow
{
if (myPreview != nil)
if ( ! [myPreview isAnimating])
{
[myPreview startAnimation];
}
[super makeKeyWindow];
}
I also had to add an IBOutlet for my preview object itself and connect it in Interface Builder.
Still working out a couple of issues, but now when I click on my screensaver Options button, my configureSheet drops down and displays its own preview while you set options. Sheesh. The hoops I jump through for these little niceties. Anyway, I like it. Onward and upward.

Am I using NSTimer correctly in iPhone View-based app?

I'm working on a simple proof-of-concept for an iPhone app (and important bit of info, I'm pretty new to Mac OSX development all around). I created a view based app with a timer. I declared my NSTimer in the interface of my app's controller, used #property and #synthesize, and I initialize it in the controller's viewDidLoad method with scheduledTimerWithTimeInterval method. My selector is a method with the signature -(void)someMethod:(NSTimer *)timer which is declared in the interface and defined in the implementation file of the controller as well. I can step past the line where I assign the timer and see that it points to a valid object, but my program goes no further than the end of the viewDidLoad method and never reaches the breakpoint at the first line of my method that is called by the timer. Also, I see GDB: Program received bad signal: "EXC_BAD_ACCESS" in the status bar of xcode at this point (viewDidLoad end is reached). I didn't do anything in IB but add a view and a picker just so I'd see if the UI actually loads...it never does.
So, am I doing something wrong with the NSTimer, or are my troubles elsewhere? How can I use the debugging tools in xcode to get more information?
EXC_BAD_ACCESS usually indicates a memory management error, without seeing the code probably from somewhere else in your app. It's a very common error for beginners, but an important subject to fully understand, so I'd suggest looking through some of the questions on memory management here and find a few guides or tutorials to look through. It's actually pretty easy to learn.
Also, it shouldn't hurt but unless you need to access the timer in between fire events, you don't actually need to store it as an instance variable. Once you create and start a timer it's added to and retained by the application's run loop.
Have you got NSZombieEnabled?
Might be useful if this is failing on an over released object.