hide NSMenu from a NSButton inside a custom view - xcode

I have a simple cocoa coredata statusbar application with Xcode 4.6.2.
Here in my AppController.h i have
#interface AppController : NSObject
#property NSStatusItem *statusItem;
#property IBOutlet NSMenu *statusMenu;
In my AppController.m:
#synthesize statusItem = statusItem;
#synthesize statusMenu = statusMenu;
-(void)awakeFromNib{
statusItem = [[NSStatusBar systemStatusBar]statusItemWithLength:NSVariableStatusItemLength];
statusItem.menu = statusMenu;
}
then, in my AppDelegate.m there is a function:
#import "AppController.h"
-(IBAction)someAction:(id)sender{
//code to do something
AppController *x = [[AppController alloc]init];
[x.statusMenu cancelTracking];
}
I want to close the menu via a button that performs an action inside a custom view of a NSMenuItem (from Connection Inspector->Outlets->view ctrl+drag to the button). I cannot select 2 different sent actions for a NSButton, so i have to close the menu declared in AppController class from the IBAction someAction that is in AppDelegate class. How to do it? The code i've posted doesn't work.
Thanks in advance

Your code probably doesn't work because you are initializing a second AppController.
You need a reference to your original AppController in AppDelegate. This can be achieved by using cocoa bindings. In your .XIB file, drag a new blue Object from your Object Library, set it to be a AppController class using the inspector, then control-drag into your AppDelegate header to create a binding. Use that reference and remove the AppController *x = [[AppController alloc] init];.

Maybe try this:
[[NSStatusBar systemStatusBar] removeStatusItem:[GSAppDelegate alloc].statusMenu];

Related

Change background image of a button programmatically cocoa obj-c

I am creating NSCollection View (in Cocoa) with many identical buttons in size and appearance, except for their icons (or you could probably call them Background Images).
In my xib file I have the button binded to the Collection View (Model key path: representedObject.foto) and the Array Controller has class of MyButton and Keys: foto.
I created My Button class with NSImage property - is this the right way to do it?
How do I set an Image that I have in my project in AppController.m so that it appears on the button when running my app?
Everything else should be fine, because I have previously create NSCollectionView with Labels and it worked.
MyButton.h
#import <Cocoa/Cocoa.h>
#interface MyButton : NSButton
#property(retain, readwrite) NSImage *foto;
#end
MyButton.m
#import "MyButton.h"
#implementation MyButton
#end
AppController.h
#interface AppController : NSObject {IBOutlet NSArrayController *controller;}
#property (strong) NSMutableArray *modelArray;
#end
AppController.m
#import "AppController.h"
#import "MyButton.h"
#implementation AppController
- (void) awakeFromNib {
MyButton *FirstOne = [[MyButton alloc] init];
//FirstOne.foto = ???
_modelArray = [[NSMutableArray alloc] init];
[controller addObject:FirstOne];}
#end
Where is your image located in your project? If its in an .xcasset file, then you can set the image with:
FirstOne.image = [NSImage imageNamed:#"StatusBarIcon"];
You can learn about storing images in assets here. I would recommend using these assets as it allows you to keep all the images that you may use in your project organised, and it helps reduce the hassle of maintaining images for multiple resolutions.

Get a reference to status menu item and change its title

I have a Mac OS app with a status menu (made in Interface Builder). I want to change status menu item title when certain event happens. I can do it just fine inside the action handler, because I have a reference to the item there (sender):
- (IBAction)playPauseMusic:(id)sender {
// ...
[sender setTitle:#"New Title"];
}
But how to do it in other parts of my app? I don't know how to get a reference to menuItem in the following code:
- (void) someOtherMethod:(int)isPlaying {
menuItem = ...;
if(isPlaying) {
[menuItem setTitle:#"Pause"];
}
}
What to do to make the above work?
Update. Here's how I attach the status menu:
// MyAppDelegate.h:
#interface MyApp : NSApplication
#end
#interface MyAppDelegate : NSObject <NSApplicationDelegate>
{
NSMenu *statusMenu;
NSStatusItem *statusItem;
// ...
}
#property (strong) IBOutlet NSMenu *statusMenu;
// ...
#end
// MyAppDelegate.m:
#synthesize statusMenu;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
statusItem = [[NSStatusBar systemStatusBar]
statusItemWithLength:NSVariableStatusItemLength];
[statusItem setMenu:[self statusMenu]];
}
If you want to access an item within the menu, then set a tag on the menu item (in IB, for example) and use:
NSMenuItem *menuItem = [[statusItem menu] itemWithTag:100]; // 100 = example
menuItem.title = #"Something";
If the code that wants to set the title is not the same object that holds statusItem then you'll need to expose a setStatusMenuTitle:forItemWithTag: method which performs the above code.
I cannot tell you how to get access to that object without more details, however.
First, I created an outlet for the menu item in Xcode. I followed the "Create and connect a new outlet" video guide. I made a strong outlet for my menu item:
#property (strong) IBOutlet NSMenuItem *playMenuItem;
Then added it to the interface:
#interface MyAppDelegate ...
{
// ...
NSMenuItem *playMenuItem;
}
Then added #synthesize declaration in implementation:
#synthesize playMenuItem;
Finally, the following worked:
[playMenuItem setTitle:#"New Title"];
P.S. If anyone can show me how to make it simpler, I'll be grateful.

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!

NSWindowController's window released immediately

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

Creating a UITabBarController using a NIB outside of AppDelegate?

Still new to iOS programming, and despite copious amounts of research, I have run in to another roadblock.
What I want to implement:
I want a UITabBarController that gets loaded when I navigate from the main UI. I would also like to use a NIB to define its properties.
All of the examples I can find put the UITabBarController in the AppDelegate, but I would not like to load it unless it gets used. I also dont know if all of the UIGestureRecognizers would remain active if I just did it modally (I cant get a working implementation).
What I have so far
First, I load an initial loading view from AppDelegate
AppDelegate.h
#class InitialViewController;
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) UIViewController *viewController;
#end
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[InitialViewController alloc] initWithNibName:#"InitialViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
From this view, as I am just making a skeleton of the UI, I have two buttons, one goes to what would be the main interface, and the other to the UITabBarController.
InitialViewController.h
#interface InitialViewController : UIViewController
- (IBAction)toMain:(id)sender;
- (IBAction)toTabs:(id)sender;
#property (strong, nonatomic) UIViewController *mviewController;
#property (strong, nonatomic) UIViewController *tviewController;
#end
InitialViewController.m
- (IBAction)toMain:(id)sender {
self.mviewController = [[MainViewController alloc] initWithNibName:#"MainViewController" bundle:nil];
[[[UIApplication sharedApplication] delegate] window].rootViewController = self.mviewController;
}
- (IBAction)toTabs:(id)sender {
self.tviewController = [[tabViewController alloc] initWithNibName:#"tabViewController" bundle:nil];
[[[UIApplication sharedApplication] delegate] window].rootViewController = self.tviewController;
}
On loading MainViewController, it behaves exactly like I want. But when I load the tab view, I get one long tab at the bottom and a black background. I can add in things in viewdidload, like changing the background color, but no actual tabs or views linked to the tabs in the XIB.
I suspect there is something I am missing in two areas: in the tab .h, and some linking associated with that in interface builder. Or setting a new rootViewController isnt enough.
tabBarController.h
#import <UIKit/UIKit.h>
#interface iPodViewController : UITabBarController <UITabBarControllerDelegate>
#end
If someone can point me in the right direction and/or show me an implementation that works, I would be most grateful.
-- as a note, when I go in to the tabbar.xib, and use the assistant editor, it opens InitialViewController.h --
Unlike other view controllers (e.g. UITableViewController) you should not subclass the UITabViewController. Therefore, unlike you other view controllers, you don't subclass and then make your subclass the owner of the nib, pointing at the view in the nib, with a customised view.
Instead, for whichever class that you want to own your UITabBarController, add a plain, vanilla UITabBarController as an outlet property on this class. (e.g. your app delegate).
Then create a nib file and drag a UITabBarController object into the nib. Set the owner of the nib to be the class that you want to own your tab bar controller (e.g. your app delegate) and connect the outlet you created as a property to the tab bar controller in the nib.
#interface myTabOwningClass
#property (strong, nonatomic) IBOutlet UITabBarController myTabBarControllerOutlet;
Now at the point you want to create and display your tab bar controller, use the following method:
[[NSBundle mainBundle] loadNibNamed:#"MyTabControllerNib" owner:myTabOwningClass options:nil];
This will initialise the property (i.e. myTabBarControllerOutlet in our example) on the owning class and load the tab bar controller from the nib, including all sub view controllers for each tab etc. that you have defined in the nib.

Resources