objective-c OSX class inheritance - objective-c

I have a method “ShowPop:nil” in a “Navigation” class - it displays a popover.
I have inherited the Navigation class from the AppDelegate.h. When I call [Self ShowPop:nill] from AppDelegate.m the popover wont pop but the method does run.
Note, I know the popover method works because it pops perfectly from a IB button connection from the same method.
Sample code below.
#interface Navigation_Main : NSObject
{
}
#property (weak) IBOutlet NSPopover *popover_AddStuff;
- (IBAction)ShowPop:(id)sender;
- (IBAction)ShowPop:(id)sender;
{
[_popover_AddStuff showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMaxYEdge];
}
.
**#import "Navigation_Main.h"**
#interface AppDelegate : Navigation_Main <NSApplicationDelegate,NSTextFieldDelegate>
{
- (IBAction)showPopup:(id)sender;
}
- (IBAction)showPopup:(id)sender {
//[self ShowPop:nil]; ---No pop
[super ShowPop:nil]; ---No pop
}

NSPopover throws an exception when the positioning view is nil, and (as a consequence) won't show the popover. Ensure you pass a view for the popover to be shown relative to, not nil.

Related

Method of one class not executing when called form a different class

I am working on a front end for a project in objective-c and I am having some trouble getting methods of my class Window which is a subclass of NSViewController to fully execute when called from a different class.
I have a method of the class Window that is called setColor which changes the color of my NSTableView variable which is linked to a bordered scroll view in my interface. I am able to successfully change the color by calling the setColor method like this from the init method in Window: [self setColor :self];
However when I do this [window1 setColor: window1] with window1 being an object of the class Window that I have declared in class Door, nothing seems to happen since the color of the boarded scroll view remains the same.
My Window.h file looks like this:
#interface Window : NSViewController {
#public
IBOutlet NSTableView *dataTableView;
}
#property (retain) IBOutlet NSTableView *tableView;
- (IBAction)SetColor:(id)sender;
#end
My Window.m looks like this:
#synthesize tableView;
- (void) awakeFromNib {
// [self SetColor :self];
}
- (IBAction)SetColor:(id)sender;
{
NSLog(#"changing the color");
[self->tableView setBackgroundColor: NSColor.blueColor];
}
Door.h looks like this
#interface Door : NSViewController {
Window* window1;
}
-(IBAction)buttonPress:(id)sender;
#property (retain) Window* window1;
#end
Door.m looks like this:
-(void) dealloc{
[window1 release];
}
-(id)init{
self = [super init];
if(self){
window1 = [Window alloc];
}
-(IBAction)buttonPress :(id)Sender;
{
[window1 setColor: window1];
}
I am using Xcode 3.2 so I cannot use ARC.
window1 = [Window alloc] will not load a Nib or storyboard and connect the outlet IBOutlet NSTableView *dataTableView to the table view inside it.
If "Window" is a view controller, you need to initialize it and the outlets in it a more standard way. View controllers need the proper initialization or the outlets are nil, and in Objective-C, if you send a method to nil, it just does nothing.

NSPopover color

Is there any way to color NSPopover? Ive seen apps like facetab etc that have cool colors and resizeable popovers, how is this done?
Ay guides, hints?
Thanks.
Set popover.contentViewController.view as a subclass of NSView with a custom background drawing (i.e. override drawRect: and fill a rect with your custom background color).
Then set the popover.appearance = NSPopoverAppearanceHUD to remove the default border around the view.
Note that there will still be a very thin border around the view, so if you want to remove it completely, you may want to use MAAttachedWindow or a similar solution.
In Swift 4:
Go to File->New File->Cocoa Class
Name your class. eg. PopColor. Make sure it is a subclass of NSView
Set the contents of the file to:
import Cocoa
class PopoverContentView:NSView {
var backgroundView:PopoverBackgroundView?
override func viewDidMoveToWindow() {
super.viewDidMoveToWindow()
if let frameView = self.window?.contentView?.superview {
if backgroundView == nil {
backgroundView = PopoverBackgroundView(frame: frameView.bounds)
backgroundView!.autoresizingMask = NSView.AutoresizingMask([.width, .height]);
frameView.addSubview(backgroundView!, positioned: NSWindow.OrderingMode.below, relativeTo: frameView)
}
}
}
}
class PopoverBackgroundView:NSView {
override func draw(_ dirtyRect: NSRect) {
NSColor.green.set()
self.bounds.fill()
}
}
In your storyboard, select the view which has your popover content and go to the Identity Inspector
Set the Class to PopoverContentView
Your popover and its triangle will now be green.
You can use MAAttachedWindow instead.
You can subclass NSView and set it as the NSPopover's view controller's view.
Yes and no. Unfortunately NSPopover isn't designed to be customisable. You can use some simple hacks for adding additional background view behind contentViewController's view and colorise or customise it as you want. In this case, you can get the customisable background that will be masked the same as generic NSPopover border and tail.
For more details you can take a look at the code of NSPopover+MISSINGBackgroundView category that implements this approach or just use this piece of code as CocoaPod library.
The complete code to change the color of NSPopover including the triangle is here:
I assume people have hooked the popover outlets and methods
#import "AppDelegate.h"
#interface MyPopoverBackgroundView : NSView
#end
#implementation MyPopoverBackgroundView
-(void)drawRect:(NSRect)dirtyRect
{
[[NSColor redColor] set];
NSRectFill(self.bounds);
}
#end
//===============================================================================================
#interface MyPopView : NSView
#end
#implementation MyPopView
-(void)viewDidMoveToWindow{
NSView *aFrameView = [[self.window contentView] superview];
MyPopoverBackgroundView * aBGView =[[MyPopoverBackgroundView alloc] initWithFrame:aFrameView.bounds];
aBGView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
[aFrameView addSubview:aBGView positioned:NSWindowBelow relativeTo:aFrameView];
[super viewDidMoveToWindow];
}
#end
//-----------------------------------------------------------------------------------------
#interface AppDelegate ()
#property (weak) IBOutlet NSWindow *window;
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
//close when clicked outside
[self.popover setBehavior:NSPopoverBehaviorTransient];
//change its color
MyPopView *myPopview = [MyPopView new];
[self.popover.contentViewController.view addSubview:myPopview];
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}
- (IBAction)closePopover:(id)sender {
[self.popover close];
}
- (IBAction)showPopover:(id)sender {
[self.popover showRelativeToRect:[sender bounds]
ofView:sender
preferredEdge:NSMaxYEdge];
}
#end
This is what I did to change the popover color.
Assuming that you have properly defined your NSPopover:
//AppController.h
#import <Foundation/Foundation.h>
#interface AppController : NSObject
#property (weak) IBOutlet NSPopover errorPopover;
// whatever else you have ...
#end
//AppController.m
#import "AppController.h"
#implementation AppController
#synthesize errorPopover = _errorPopover;
// whatever else you have ...
-(IBAction)doSomethingThatCallsPopover:(id)sender {
_errorPopover.appearance = NSPopoverAppearanceHUD; //set color of error popup
[[self errorPopover] showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMaxXEdge];
}
#end
NSPopover Class Reference - I really wish they would provide usage code in the developer docs.

Understanding custom Delegate

So I have an app, and in the app there is a tableView, I have a uinavigationbarbutton that presents a modal viewController. When the user hits a go button in the modal interface, I want it dismiss the modal view and get some of the information in the modal view. I will than put that info in the tableView. To do this, I wrote a custom delegate, but it doesn’t work. I included my code below. Thanks for any help.
TrackerMainViewController.h //the tableView
#import "NewItemViewController.h"
#interface TrackerMainViewController : UITableViewController <UITableViewDelegate, DetailDelegate>
TrackerMainViewController.m
-(void)finishedAddingFoodItemFromDetail:(NSDate *)date whatWasEaten:(NSString *)whatFood whichMeal:(NSString *)meal {
NSLog(#"in delegate method here");
[self.tableView reloadData];
[self dismissModalViewControllerAnimated:YES];
}
NewItemViewController.h // the modal view
#protocol DetailDelegate <NSObject>
-(void)finishedAddingFoodItemFromDetail:(NSDate *)date whatWasEaten:(NSString *)whatFood whichMeal:(NSString *)meal;
#end
#interface NewItemViewController : UIViewController {
id <DetailDelegate> _delegate;
}
#property (nonatomic, retain) id <DetailDelegate> delegate;
#end
NewItemViewController.h
#implementation NewItemViewController
#synthesize delegate = _delegate;
//the go button in the modal view
- (IBAction)Go:(id)sender {
[self.delegate finishedAddingFoodItemFromDetail:[NSDate date] whatWasEaten:#"chicken" whichMeal:#"breakfast"];
}
I put a log in both the go button and in the implementation of the delegate in the tableview, but only the go log is being called.
Thanks
In the code you posted, you dont set the delegate. You need to set it similar to this detailView.delegate = self, otherwise it is nil. You can send messages to a nil-object without any warning and error, nothing will happen.

Second Window Creation Objective-C Cocoa

I was wondering if it is possible to open a second window with like a button. I have no clue how to do this, please help.
First set up an IBAction to get called when the user clicks the button.
- (IBAction)buttonClicked:(id)sender {
}
In Interface Builder, control-drag from the NSButton object you want to fire that action to the method implementation.
Now, to create a second window, you'll probably want to create a SecondWindowController class to manage it. Declare an IBOutlet to the NSWindow and hook it up in Interface Builder, just like you did for the IBAction (by control-dragging to the IBOutlet declaration).
In the initializer, load the nib file that contains the window you're presenting.
- (id)init {
if (self = [super init]) {
[NSBundle loadNibNamed:#"DubBouncerConversionProgressWindow" owner:self];
}
return self;
}
Then, define a method to present the window by calling orderFront: on it.
- (void)displayWindow {
if (![progressWindow isVisible]) {
[progressWindow setIsVisible:YES];
[progressWindow orderFront:nil];
}
}
Now, when the user clicks the button you can call -displayWindow on an instance of SecondViewController.
- (IBAction)buttonClicked:(id)sender {
[mySecondViewController displayWindow];
}
Here's a full picture of what's going on:
FirstViewController.h
#interface FirstViewController : NSObject {
SecondViewController *mySecondViewController;
}
- (IBAction)buttonClicked:(id)sender;
#end
FirstViewController.m
#implementation FirstViewController
- (IBAction)buttonClicked:(id)sender {
if (!mySecondViewController) {
// If the second view controller doesn't exist yet, make it!
mySecondViewController = [[MySecondViewController alloc] init];
}
[mySecondViewController displayWindow];
}
#end
SecondViewController.h
#interface SecondViewController : NSObject {
IBOutlet NSWindow *progressWindow;
}
- (void)displayWindow;
#end
SecondViewController.m
#implementation SecondViewController
- (id)init {
if (self = [super init]) {
[NSBundle loadNibNamed:#"DubBouncerConversionProgressWindow" owner:self];
}
return self;
}
- (void)displayWindow {
if (![progressWindow isVisible]) {
[progressWindow setIsVisible:YES];
[progressWindow orderFront:nil];
}
}
#end
Connect the button to the NSWindow's orderFont: action. I haven't got Xcode 4, so I can't tell you how to do it in there, but for Xcode 3, open the xib in Interface Builder. While holding the control key, click and drag a line from the button to another window in the nib (drag over the title bar if the window is opened up, otherwise drag it onto the icon in the xib project window). In the menu that pops up, choose "orderFront:" or "makeKeyAndOrderFront:" (depending on the required behaviour).
If the window is in another nib, you'll need to use an approach like Stephen's.

Connect NSImageView to view using IB?

I've only programmed on the iPhone so far, so Cocoa is sort of confusing in certain ways for me. Here's where I've hit a snag. I wanted my window so that the background was invisible, and without a title-bar. Something like this:
Here's how I'm doing it:
I set my window's class to a custom window, which I've created like this:
CustomWindow.h
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
#interface CustomWindow : NSWindow {
#private
NSPoint initialLocation;
}
#property(assign)NSPoint initialLocation;
#end
CustomWindow.m
//trimmed to show important part
#import "CustomWindow.h"
#implementation CustomWindow
#synthesize initialLocation;
- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag {
// Removes the window title bar
self = [super initWithContentRect:contentRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
if (self != nil) {
[self setAlphaValue:1.0];
[self setOpaque:NO];
}
return self;
}
#end
Now, in my .xib file for this window I've added a custom view onto the window. I've set the view class to a custom class I've created that inherits from NSView. Here's how I'm setting that up:
MainView.h
#import <Cocoa/Cocoa.h>
#interface MainView : NSView {
#private
//nothing to see here, add later
}
#end
MainView.m
//trimmed greatly again to show important part
#import "MainView.h"
#implementation MainView
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
}
return self;
}
- (void)drawRect:(NSRect)rect {
// Clear the drawing rect.
[[NSColor clearColor] set];
NSRectFill([self frame]);
}
#end
So here's my question. I've added a NSImageView to my custom view (MainView) in Interface Builder. However, for some reason I can't figure out how to connect this image view to an instance variable in my custom view. They seem like they can't be connected like I normally would if I was creating an iPhone app. Any ideas how this would be done?
You connect objects created in your XIB in Mac OS X the same way you do for iOS programs. Just add an NSImageView property to your main view, mark it as an IBOutlet and connect it up.
For example,
In MainView.h create a property for your NSImageView and make it an IBOutlet:
#import <Cocoa/Cocoa.h>
#interface MainView : NSView {
NSImageView *imageView;
}
#property(retain) IBOutlet NSImageView *imageView;
#end
In interface builder, make sure the class for the custom view is set to MainView, to do this click on the File's Owner object in the custom view XIB and then select the identity option in the inspector and enter MainView as the class type.
Next, CTRL+click File's owner and drag the arrow to the NSImageView and select the imageView outlet.
That's all there is to it. You should be able to reference the image view from code now.