NSView subclass for NSMenuItem - cocoa

I want to create a subview of NSView and link it to a MenuView.xib.
I'll have:
- MenuView.m
- MenuView.h
- MenuView.xib
in xcode I created my xib and set as customclass my 'MenuView'. Now I would like to add my new view programmatically via a command like this:
NSView *vv = [[MenuView alloc] initWithFrame:CGRectMake(0, 0, 300, 200)];
NSMenuItem *newItem = [[NSMenuItem alloc] initWithTitle:#"title" action:nil keyEquivalent:#""];
[newItem setView:vv];
but I just see an empty space without any content. How can I tell the class MenuView.m to render with the MenuView.xib file? Is that wrong?
Thanks.

Use an NSViewController, it's designed for loading views from a nib file. In your nib file, set NSViewController as the class of File's Owner and then set the view outlet of File's Owner so that it points to your view in the nib.
Then you can just do this:
NSViewController* viewController = [[NSViewController alloc] initWithNibName:#"YourNibName" bundle:nil];
YourCustomView* view = [viewController view]; //this loads the nib
[viewController release];
//do something with view

To load a view from a nib (adapted from another answer of mine):
NSNib *nib = [[NSNib alloc] initWithNibNamed:#"MenuView" bundle:nil];
NSArray *nibObjects;
if (![nib instantiateNibWithOwner:self topLevelObjects:&nibObjects]) return nil;
NSMenuItem *item = nil;
for (id obj in nibObjects)
if ([obj isKindOfClass:[NSMenuItem class]]) {
item = obj;
break;
}
[someView insertSubview:item];
If you want something other than self as the file owner, change the parameter to instantiateNibWithOwner:.

Related

xCode: Activating an IBAction from within a dynamically added subview

I have a separate UIView class that constructs a simple footer bar that contains a UIButton.
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:CGRectMake(0, 410, 320, 50)];
if (self) {
int buttonHeight = self.frame.size.height;
int buttonWidth = 70;
int nextBtnPosX =0;
int nextBtnPosY =0;
self.backgroundColor =[UIColor colorWithRed:254.0/255.0 green:193.0/255.0 blue:32.0/255.0 alpha:1.0];
[self sendSubviewToBack:self];
UIButton *nextBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[nextBtn setTitle:#"Next" forState:UIControlStateNormal];
nextBtn.frame = CGRectMake(nextBtnPosX, nextBtnPosY, buttonWidth, buttonHeight);
[nextBtn addTarget:self.superview action:#selector(GoToNextPage) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:nextBtn];
}
return self;
}
I have several ViewControllers that then add this footer view class above to each view as a subview.
UIView *newFooter = [[theFooter alloc] init];
[self.view addSubview:newFooter];
Now the actual UIButton within the footer view needs to have its taget different for each viewController it is added to.
So I though it would be best to add the IBAction to the actual view controller then call this via the footer view.
But this is where I have come into a problem. How do I call the parent Controller to init the IBAction(GoToNextPage) from within the footer subview, from the addTarget?
Also would it be easier to have it all within the footer subview and pass in the target required, if so how else would this be done.
Here is a rough overview on what you should do.
This is how your UIView's header file should look
#protocol myViewControllerDelegate <NSObject>
#optional
- (void)didPushButton:(id)sender;
#end
#interface UIViewController : UITableViewController
{
__unsafe_unretained id <myViewControllerDelegate> delegate;
}
#property (nonatomic, assign) id <myViewControllerDelegate> delegate;
#end
Remember to #synthesize delegate; in your main file.
Finally in your main file, you will have an IBAction that receives the UIButton action.
Let's say that action is named buttonPushed.
Set that action to:
- (IBAction)buttonPushed:(id)sender
{
if (delegate)
[delegate didPushButton:sender];
}
Finally remember, that you need to set the delegate to each viewController you are using this viewController.
UIView *newFooter = [[theFooter alloc] init];
[self.view addSubview:newFooter];
newFooter.delegate = self;

Make AppDelegate's Navigation Controller accessible from DetailViewController of SplitView

My DetailView of a SplitView has a Map with Annotations. Upon clicking an Annotation the entire window (and not just the DetailView) should go to another view. Unfortunately that doesn't work.
This is how I'm creating my NavigationController in my AppDelegate
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
[self.window addSubview:navigationController.view];
This is how I'm creating the SplitView
left = [[MapSplitViewLeft alloc] initWithStyle:UITableViewStylePlain];
right = [[MapViewController alloc] init];
splitViewController = [[UISplitViewController alloc] init];
splitViewController.viewControllers = [NSArray arrayWithObjects:left,right, nil];
self.view = splitViewController.view;
left.right = right;
[left release];
[right release];
And that's what's being called when clicked on an Annotation:
- (void)showDetails:(id)sender {
NSLog(#"Yes it works");
VenueViewController *vviewcontroller = [[VenueViewController alloc]
initWithNibName:#"VenueViewController" bundle:[NSBundle mainBundle]];
AppDelegate *del = (AppDelegate *)[UIApplication sharedApplication].delegate;
[del.navigationController pushViewController:vviewcontroller animated:YES];
}
When I click on the Annotation I only get "Yes it works" but nothing else is happening.
Thanks so much for any advise.
Every UIViewController has the property "navigationController". Try with your current ViewController to push the new Viewcontroller.
[self.navigationController pushViewController:vviewcontroller animated:YES];
edit: Sorry, you mean the entire window! I think that would not work.
edit2: Maybe this answer can help you how to add a view over window in uiviewcontroller But i think thats that view is not on your navigationController-Stack

why the subclass of NSMenu not responding?

I created a menu resource in a separate xib file, made it to be a subclass NSMenu like the following, and the file's owner to be the StatusMenu
#interface StatusMenu : NSMenu
{
#private
IBOutlet NSMenuItem *menuitem1;
IBOutlet NSMenuItem *menuitem2;
}
- (IBAction)action1:(id)sender;
- (IBAction)action2:(id)sender;
- (void)show;
#end
where show method is implemented in the following way
- (void)show
{
NSImage *menuImage = [[NSImage alloc] initWithContentsOfFile: [[NSBundle mainBundle] pathForResource:#"myicon" ofType:#"png"]];
statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength] retain];
[statusItem setImage:menuImage];
[statusItem setMenu:self];
[statusItem setHighlightMode:YES];
}
Then I created and launched the StatusMenu instance in the app delegate like the following
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
statusMenu = [[StatusMenu alloc] init];
statusMenu.user = self.user;
[statusMenu show];
}
Now, I can see the icon on the status bar. But when I click on the icon, no responding is happening. What could be wrong?
You don't usually subclass NSMenu to do what you're trying to do.
You can simply create another class (call It MenuController or something), put It in your storyboard/xib and have an outlet to It in your AppDelegate.
Here`s a sample project for you to check out.

UITabBarController + UINavigationController problem xcode project

I have a problem, I have created a project window based application in xcode, then I create a UITabBarController that manages two views all programmatically, the second view is a tableView and I want to see in the top a UINavigationController, I have tried a lot but I don't know how to have a UINavigationController in the second view. this is the code:
ProjectAppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//Creo una tabBarController
UITabBarController *tabBarController = [[UITabBarController alloc] init];
//Create the two view controllers
UIViewController *vc1 = [[Visuale1ViewController alloc] init];
UIViewController *vc2 = [[Visuale2ViewController alloc] init];
//Make an array containing the two view controllers
NSArray *viewControllers = [NSArray arrayWithObjects:vc1, vc2, nil];
//The viewControllers array retains vc1 and vc2, we can release
//our ownership of them in this method
[vc1 release];
[vc2 release];
//Attach them to the tab bar controller
[tabBarController setViewControllers:viewControllers];
//Setto la tabBarController come rootViewController di window
[window setRootViewController:tabBarController];
//The window retain tabBarController, possiamo lasciare il nostro riferimento
[tabBarController release];
[self.window makeKeyAndVisible];
return YES;
}
Visuale1ViewController.h
#implementation Visuale1ViewController
- (id)init{
[super initWithNibName:#"Visuale1ViewController" bundle:nil];
//Get the tab bar item
UITabBarItem *tbi = [self tabBarItem];
//Give it a label
[tbi setTitle:#"Visuale 1"];
return self;
}
// The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)bundle {
return [self init];
}
Visuale2ViewController.h
#implementation AnswerViewController
- (id)init{
//Call the superclass's designated initializer
/*[super initWithNibName:nil
bundle:nil];*/
[super initWithStyle:UITableViewStyleGrouped];
answers = [[NSMutableArray alloc] init];
for (int i = 0; i<10 ; i++) {
[answers addObject:[Answer DefaultAnswer]];
}
//Get the tab bar item
UITabBarItem *tbi = [self tabBarItem];
//Give it a laber
[tbi setTitle:#"Visuale 2"];
return self;
}
- (id)initWithStyle:(UITableViewStyle)style{
return [self init];
}
//All below are all methods to work the table view, and all go well, the only problem it's the UINavigationController, to manage then the detail of the table...
Now I want to know how I can put a UINavigationController in the second view. I try do this, in ProjectAppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//Creo una tabBarController
UITabBarController *tabBarController = [[UITabBarController alloc] init];
//Create the two view controllers
UIViewController *vc1 = [[Visuale1ViewController alloc] init];
UIViewController *vc2 = [[Visuale2ViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:vc2];
//Make an array containing the two view controllers
NSArray *viewControllers = [NSArray arrayWithObjects:vc1, navController, nil];
//The viewControllers array retains vc1 and vc2, we can release
//our ownership of them in this method
[vc1 release];
[vc2 release];
//Attach them to the tab bar controller
[tabBarController setViewControllers:viewControllers];
//Setto la tabBarController come rootViewController di window
[window setRootViewController:tabBarController];
}
In this way I can visualize the NavigationBar, but I lost the name of the SecondTabBar. Sorry for my english, how I can do this?
Yes in the second view you have to set title as
[self.navigationItem setTitle:#"Visuale2"];
For TabBar title-
UITabBar *tabBar = [self.tabBarController tabBar];
NSArray *tabBarItems = [tabBar items];
UITabBarItem *secondTabBarItem = [tabBarItems objectAtIndex:1];
[secondTabBarItem setTitle:#"Visuale2"];
I left the code as it was and I added in init Visale2ViewController this:
UIImage *i = [UIImage imageNamed:#"Hypno.png"];
[tbi setImage:i];
and now in can see the text Visuale2 in tabBar and the image...i don't know why...
You need to set the tabBarItem property for your UINavigationController. Something like this.
UITabBarItem *tabItem = [[UITabBarItem alloc] initWithTitle:#"Visuale 2" image:nil tag:1];
UIViewController *vc2 = [[Visuale2ViewController alloc] init];
navController = [[UINavigationController alloc] initWithRootViewController:vc2];
navController.tabBarItem = tabItem;
After looking at it,the scenario seems to be same like me.What I faced for the first time when doing Tab+Navigation.
I am sure that there is some problem with your Tab+Navigation based application. Although it shows the Tab as well as navigation are not able to navigate the basic flow.And it is very difficult to solve your problem with such less code.
Instead of this, I had an alternate solution for the same:
Once you have a tab bar in a XIB, the easiest way to approach this is to drag a UINavigationController object over from the Library window (looks like a left nav bar button on a gold background) into the Tree View for your tab bar (the text only view, not the GUI). Place it under the tab bar, then drag your existing view controller under the tab bar controller instead of under the tab bar.
When you go to view that tab you should then see a navigation bar on the top of it... if you are loading the navigation controller from another xib, you'll modify the nav bar in the tab bar xib.
else you can below you can follow the best url for the same:
http://books.google.co.in/books?id=2yYlm_2ktFYC&pg=PA179&lpg=PA179&dq=navigation+with+the+tab+based+application+iphoneSDK&source=bl&ots=nf2YYjX5Am&sig=COpHj9wOtsDChQBglpsljSTsElw&hl=en&ei=3ZoFTeGSOI_tsgbc_Iz6CQ&sa=X&oi=book_result&ct=result&resnum=6&ved=0CDAQ6AEwBQ#v=onepage&q&f=false
http://www.youtube.com/watch?v=LBnPfAtswgw
Hope this will surely solve your problem.

Objective-J Cappuccino want a list of buttons on main menu, when I click the panel refreshes with UI of button selected

Dear all, I am new to objective-j/c and cappuccino not really sure how this all fits together.
The code below is taken from http://github.com/jfahrenkrug/CappuccinoLocations1
What I need to do is:
I need a landing main menu which is a CPView called ie MainView with five or so buttons, when you click on the LocationButton on MainView is replaces MainView by with LocationView, which displays the contents of jfahrenkrug's work. A similar effect will happen with each other button.
What is the correct Objective-c/j way of handling this approach?
#import <Foundation/CPObject.j>
#import "src/Location/LocationView.j"
#implementation AppController : CPObject
{
LocationView locationView;
}
- (void)applicationDidFinishLaunching:(CPNotification)aNotification
{
var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask],
mainContentView = [theWindow locationView],
bounds = [locationView bounds];
[mainContentView setBackgroundColor:[CPColor colorWithRed:212.0 /255.0 green:221.0/ 255.0 blue:230.0/255.0 alpha:1.0]];
locationView = [[LocationView alloc] initWithFrame:CGRectMake(0,0,920.0,590.0)];
[locationView setCenter:[mainContentView center]];
[locationView setBackgroundColor:[CPColor whiteColor]]
[locationView setAutoresizingMask:CPViewMinXMargin | CPViewMaxXMargin | CPViewMinYMargin | CPViewMaxYMargin];
var shadow = [[CPShadowView alloc] initWithFrame:CGRectMakeZero()];
[shadow setFrameForContentFrame:[locationView frame]];
[shadow setAutoresizingMask:CPViewMinXMargin | CPViewMaxXMargin | CPViewMinYMargin | CPViewMaxYMargin];
[mainContentView addSubview:shadow];
[mainContentView addSubview:locationView];
[theWindow orderFront:self];
}
Now we have the locationView.j
#import "LocationsController.j"
#import "LocationListView.j"
#import "MapController.j"
#import "LocationsToolbar.j"
#import "LocationDetailView.j"
#import "LocationDetailController.j"
#implementation LocationView : CPView
{
LocationsController locationsController;
LocationListView locationListView;
MapController mapController;
MKMapView mapView;
CPTextField coordinatesLabel;
LocationsToolbar locationsToolbar;
LocationDetailView locationDetailView;
LocationDetailController locationDetailController;
CPTextField searchField;
// id delegate #accessors;
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if(self){
locationsController = [[LocationsController alloc] init];
[locationsController loadExampleLocations];
locationListView = [[LocationListView alloc] initWithFrame:CGRectMake(0.0,0.0,226.0,400.0)];
[locationListView setContent:[locationsController locations]];
[locationListView setDelegate:locationsController];
[locationsController setLocationListView:locationListView];
var locationScrollView = [[CPScrollView alloc] initWithFrame:CGRectMake(10.0,65.0,243.0,400.0)];
[locationScrollView setDocumentView:locationListView];
[locationScrollView setAutohidesScrollers:YES];
[[locationScrollView self] setBackgroundColor:[CPColor whiteColor]];
[self addSubview:locationScrollView];
mapController = [[MapController alloc] init];
mapView = [[MKMapView alloc] initWithFrame:CGRectMake(510,65,400,400) apiKey:'' ];
[mapView setDelegate:self];
mapController.mapView = mapView;
[self addSubview:mapView];
coordinatesLabel = [[CPTextField alloc] initWithFrame:CGRectMake(510,465,200,35)];
[coordinatesLabel setTextColor:[CPColor colorWithHexString:#"009900"]];
[coordinatesLabel setFont:[CPFont systemFontOfSize:14.0]];
[coordinatesLabel setEditable:NO];
[coordinatesLabel setStringValue:#"-/-"];
[mapController setCoordinatesLabel:coordinatesLabel];
[self addSubview:coordinatesLabel];
locationsToolbar = [[LocationsToolbar alloc] initWithFrame:CGRectMake(10.0,467.0,226.0,25.0)];
[locationsToolbar setDelegate:locationsController];
[self addSubview:locationsToolbar];
locationDetailController = [[LocationDetailController alloc] init];
locationDetailController.mapController = mapController;
locationsController.locationDetailController = locationDetailController;
[mapController setDelegate:locationDetailController];
locationDetailView = [[LocationDetailView alloc] initWithFrame:CGRectMake(510,490,400,90)];
[locationDetailView setDelegate:locationDetailController];
[locationDetailController setLocationDetailView:locationDetailView];
[self addSubview:locationDetailView];
searchField = [CPTextField roundedTextFieldWithStringValue:#"" placeholder:#"Location" width:200.0];
[searchField setFrameOrigin:CGPointMake(510.0,35.0)];
[searchField setDelegate:self];
[self addSubview:searchField];
var searchButton = [[CPButton alloc] initWithFrame:CGRectMake(710.0,37.0,60.0,24.0)];
[searchButton setTitle:"Search"];
[searchButton setTarget:self];
[searchButton setAction:#selector(searchLocation)];
[self addSubview:searchButton];
}
return self;
}
I'm not sure I understand your question but essentially a window has a default view called the content view. You get it like so:
var contentView = [theWindow contentView];
To the content view you can add subviews (and buttons).
[contentView addSubview:myLocationView];
The location of those subviews is determined by the 'frame' of the subview.
[myLocationView setFrame:CGRectMake(10, 10, 100, 100)];
You can replace the content view's subviews with something else by either removing the previous views or using the setSubviews message.
[contentView setSubviews:[aButton, anotherButton]];
So essentially if you want to swap out one view for another, call 'setSubviews' on its super view with the new views you want. Hope that helps to get you started.

Resources