I've created a new cocoa application using .xib files (not storyboarded, the app has to be backwards compatible with mavericks/mountain lion) and I would like to have a custom windowcontroller for the main window. Is this possible? I can't seem to find a way to connect the window to my desired custom controller. The window has a reference outlet in AppDelegate, however I need a custom NSWindowController for this window as it doesn't open on application launch. The application launches silently as a menu bar app and the main application is launched via button press in the drop down from the menu bar.
Is there a way to link a controller to the window in the interface builder? Or do I have to do something along the lines of :
wc = [[CustomWindowController alloc] initWithWindowNibName:#"Main"];
Thanks!
Yes, open up Utilities (the right panel) in Interface Builder, and at the bottom click on the Object Library (circle with square in it).
Search for Object (blue cube), and drag it into your Document Outline (the panel on the left inside of interface builder)
From there, select that object you just created, and change the Class in the Identity Inspector to be the window controller you want.
Finally you can go into the Connections Inspector and connect your window to the window outlet
I can't seem to find a way to connect the window to my desired custom
controller. The window has a reference outlet in AppDelegate, however
I need a custom NSWindowController for this window as it doesn't open
on application launch.
Another way:
1) Delete the window in MainMenu.xib. Delete the window property in AppDelegate.m--because you deleted the window, it is no longer relevant.
2) File>New>File>Cocoa Class. Enter a class name, e.g. MainWindowController; select "Subclass of: NSWindowController"; check "Also create .xib file for user interface".
3) Create an outlet in AppDelegate.m:
#import "AppDelegate.h"
#import "MainWindowController.h"
#interface AppDelegate ()
#property (strong, nonatomic) MainWindowController* windowController;
#end
4) Declare an action in AppDelegate.h:
#interface AppDelegate : NSObject <NSApplicationDelegate>
-(IBAction)launchWindow:(id)sender;
#end
and implement it in AppDelegate.m:
- (void)launchWindow:(id)sender {
[self setWindowController:[[MainWindowController alloc]
initWithWindowNibName:#"MainWindowController"]];
[[self windowController] showWindow:nil];
}
5) In MainMenu.xib, hook up the Menu Item to the launchWindow() action: control drag from the Menu Item to the AppDelegate object and select launchWindow.
Create the controller and make it extend from NSWindowController.
In your xib file select the File's Owner and set it to your custom class.
Select your NSWindow and connect it to the File's Owner.
To open the window:
In your .h:
#property (strong, nonatomic) YourWindowController *yourWinController;
In your .m:
self.yourWinController = [[YourWindowController alloc] initWithWindowNibName:#"YourWindowController"];
[self.yourWinController showWindow: nil];
Related
I'm pretty new to XCode/Objective-C/Cocoa. I want to implement a settings window for my app.
I have a MainMenu.xib which also holds my main Window. From the menu, I want to open a settings window. I created Settings.xib and appropriate .h and .m files to hold what that window would do.
Settings.h:
#import <Cocoa/Cocoa.h>
#interface Settings : NSWindowController <NSApplicationDelegate>
-(IBAction)openSettings:(id)senderId;
#property (nonatomic, retain) Settings *thisWindow;
#end
Settings.m:
#import "Settings.h"
#implementation Settings
- (void)windowDidLoad {
[super windowDidLoad];
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
}
// open preferences window
- (IBAction)openSettings:(id)senderId
{
_thisWindow = [[Settings alloc] initWithWindowNibName:#"Settings"];
[_thisWindow showWindow:self];
}
#end
I dragged my Preferences menu item to first responder, and selected openSettings: from there.
However, the item is still disabled and I'm pretty sure it's because I did nothing to link the Settings interface to my MainMenu.xib, which works with AppDelegate.h/m.
How do I make this work? All other solutions I found didn't quite work for me.
If I understand you clear you want to store your MainMenu and MainWindowController in a two separate classes.
Open your main menu nib-file. Remove window from the object tree.
Check in Project Settings -> General -> Main interface is still your MainMenu (without .xib-extension).
Create (implement) your custom MainWindowController class (with a nib-file may be).
Open AppDelegate class. In - (void)applicationDidFinishLaunching:(NSNotification *)aNotification method create an instance of main window controller class, show the window
Use this code below
MainWindowController *controller=[[MainWindowController alloc] initWithNibName:#"MainWindowController"];
[controller showWindow:nil];
[controller.window makeKeyAndOrderFront:nil];
Here it is.
Okay so in your mainwindowcontroller, declare a property of type NSWindowController *settingsWindow. Init it with the corresponding xib.
Then create a method called -(void)openSettings, with one line [self.settingsWindow showWindow:self];
Then also in your mainWindowController initialization, init a NSMenuItem, and set it's action to openSettings. Then add that NSMenuItem to the Mainmenu where you'd like programmatically, like this
//mainMenu is your application's menu-- if you switched index to 1 it would be the 'File' menu
NSMenu *mainMenu = [[[NSApp mainMenu] itemAtIndex:0] submenu];
[mainMenu insertItem:newItem atIndex:4];
I ended up using my AppDeleate.m to open the dialog instead. I linked the menu button to the AppDelegate object in the interface builder, and used openSettings:. Here's how it looks:
// open preferences window
- (IBAction)openSettings:(id)senderId
{
_settingsWindow = [[Settings alloc] initWithWindowNibName:#"Settings"];
[_settingsWindow showWindow:self];
}
In AppDelegate.m, instead of Settings.m.
i have a simple cocoa coredata statusbar application with Xcode 4.6.2. This is the situation:
Renamed MainMenu.xib to PreferencesWindow.xib, deleted the mainmenu, created a simple and working coredata function with arraycontrollers and bindings in the window.
I have created a new file->User Interface->Main Menu and named it StatusBarMenu.xib. Added a simple menu to it and removed the main menu.
Created new file->objective-c class->subclass of NSObject and named it StatusBarController.
Here's the code for the interface:
#property IBOutlet NSMenu *statusMenu;
#property NSStatusItem *statusItem;
#property [some items for statusbar image]
implementation:
#synthesize [everything]
-(void)awakeFromNib{
statusItem = [[NSStatusBar systemStatusBar]statusItemWithLength:NSVariableStatusItemLength];
[some string, path and stuff for the images]
statusItem.menu = statusMenu;
statusItem.toolTip = #"";
statusItem.highlightMode = YES;
}
Then I've created another new file->objective-c class->subclass of NSWindowController, named it PreferencesWindowController and leave it as it is.
Then a new file->objective-c class->subclass of NSObjects named PreferencesAppController. Here's the code for .h:
#property (assign) IBOutlet NSWindow *mainWindow;
#property (retain) PreferencesWindowController *prefController;
-(IBAction)showPreferences:(id)sender;
.m code:
#synthesize [everything];
-(IBAction)showPreferences:(id)sender{
if(!self.prefController)
self.prefController = [[PreferencesWindowController alloc] initWithWindowNibName:#"PreferencesWindow"];
[self.prefController showWindow:sender];
}
In the AppDelegate files there's only code for coredata, nothing added.
Then in the PreferencesWindow.xib I've added NSObject (the blue cube) for PreferencesAppController with some bindings: Outlets-> mainWindow binded to the window with the simple coredata function. AppDelegate has the window outlet binded to the same window, then Referencing Outlets->File's Owner delegate, some saveaction and managedobjectcontext.
In the StatusBarMenu.xib i've created a StatusBarController object and binded it to the menu (outlets->statusMenu), created another blue object called PreferencesAppController with Received Actions->showPreferences binded to a menu item.
Then i run the program and everything goes fine: an icon appears in the status bar, the dropdown menu works, if i click on "preferences..." the preferences window appears but... it isn't focused! It's on top of the other windows but i have to click to make it focused.
The coredata saving functions works fine except that i have to manually save with a button, quitting the application from the statusbar menu does not save, but this is a marginal issue.
Why isn't the window focused?
I'm assuming from your description of your app as a “statusbar application” that it is meant to run in the background and not show up in the Dock.
This means that your application is not the active application. The user clicking on your status item and choosing an item from its menu does not change that.
When an application that is not the active application opens a window, that window does not take focus (since this ordinarily would amount to stealing focus from whatever the user has been doing in the application that is active).
So, you need to activate your application.
I use a xib file to show an NSWindow named mainWindow - now I want to get a reference to mainWindow via code (e.g. NSWindow *mainWindow). I can't find anything in the documentation, any pointers?
The xib file will have placeholder objects in it for the app delegate and / or the file's owner.
On the assumption that it has the app delegate in it, you can get a reference to the window or any object in the xib by
Declare a property in the app delegate of the right type and with IBOutlet as part of its type:
#property (weak) IBOutlet NSWindow* theWindow;
Locate the app delegate object in the xib. Click and drag it while the control key is pressed. You should get a line between the mouse pointer and the object.
Drag on to the window and release the mouse button.
You should see a list of the outlets in the app delegate. Select theWindow and your done.
I'm very new in Mac OS programming. At the moment I'm trying to create simple measurement application which will have one window with the toolbar at the top and the appropriate view in the bottom. Clicking button in the toolbar should result in switching view below it - e.g. clicking on the "Connection" button will show with connection settings, "Measurements" will show current data from the device.
The problem is - I don't know how to handle swapping views, maybe in other words - something I know but not exactly...
I found similar discussion here: NSViewController and multiple subviews from a Nib but there is no answer how to create NSWindowController and how to assign it to the Main window. Because I guess it is necessary to create NSWindowController to be able to swapping views. If I'm wrong, please correct me.
So I'm creating new project (called Sample here) and there is SampleAppDelegate.h file, which looks like:
#interface SampleAppDelegate : NSObject <NSApplicationDelegate> {
#private
NSWindow *window;
}
#property (assign) IBOutlet NSWindow *window;
#end
There is window ivar, which holds the only one window, created from the MainMenu.xib (as I think).
So how should I create NSWindowController for the window from the SampleAppDelegate?
Should I just create my WindowController subclass and in the function
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
of the SampleAppDelegate like this:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
MyWindowController *wc = [[MyWindowController alloc] initWithWindow:self.window];
[wc showWindow:self];
self.myWindowController = wc;
[wc release];
}
I'll be very grateful for any hints and help.
Marcin
You shouldn't need an NSWindowController to do view swapping, NSWindowController used (I think) just when you need multiple toplevel windows.
You can just subclass NSViewController for each type of view that you want, put each view into a nib, and call -(NSView *)view when you need a view to put into the bottom part of the window. You should be able to just add it to the window like normal, or put it in an NSBox by using setContentView:view
For your two views you'd create MeasurmentsViewController and a ConnectionViewController. Then you'd create your views in MeasurementsView.nib and ConnectionView.nib, and use those nibs to initialise your view controllers.
Then in your main window, if you were to put an NSBox, if you wanted to put the MeasurementsView into it
NSView *measurementsView = [measurementsViewController view];
[boxAtBottomOfWindow setContentView:measurementsView];
and to put the ConnectionView into it
NSView *connectionView = [connectionViewController view];
[boxAtBottomOfWindow setContentView:connectionView];
I have a view controller that is instantiated in appDelegate and pushed onto a navigation controller. The view controller's view is created with a xib file. The xib file puts a UILabel on the view (among other things). Now I need to set the label's text property programatically but I don't see how to get a reference to it. How do I reference the label object?
I'm using xcode 3.2.5 and building an iPad app.
Aside from IBOutlets, you can also set a tag property on the label in the IB. Then, when you need it you can do:
UILabel *label = (UILabel *)[self.view viewWithTag:111];
111 of course being the tag you assigned to the label in IB.
You do this with what's called an "outlet". You define them in your controller, mark them clearly as IBOutlet and then connect them in Interface Builder to your file owner (or other delegate object created in IB).
For instance, in your FooController.m you might have this:
#interface FooController ()
#property (nonatomic, weak) IBOutlet UILabel* fooLabel;
#end
Then you would select your label, and either control drag from it to the file owner, or go to its connections tab, and drag from the + under referencing outlet, to the file owner and select the fooLabel.
UPDATE: Code sample changed to reflect modern way of handling this case.
[self.view viewWithTag:NUMBER_OF_TAG]; does the trick. But remember that if you want to access the view you must do it on the viewWillAppear or viewDidAppear events.