I am writing a non-NSDocument-based application similar in style to, say, AddressBook.app. It has a single window located in MainMenu.nib.
Currently, I am struggling with integrating NSUndoManager with this application. If I create an instance of NSUndoManager and store it into an instance variable of my AppController class, the "Undo" menu item doesn't get enabled on registering undos with the manager.
What do I have to do in order to connect the NSUndoManager instance to the menu items and have it manage the window's dirty state?
You can create in your AppDelegate class, your undo manager as member of the class.Then you set AppDelegate to be the delegate of the window in interface builder.After this you write this method in AppDelegate:
- (NSUndoManager*) windowWillReturnUndoManager: (NSWindow*) window
{
< return the undo manager created >
}
Related
I have moved most of the core functionality of my non-document based macOS app to a custom, embedded framework.
The app code has a standard main storyboard with an initial window, and the window has a "window content" relationship/segue into a storyboard reference pointing to a storyboard inside the embedded framework. Therein lies a custom NSViewController subclass and a custom NSView subclass.
I want to group all the input event handling code inside the framework, which means implementing mouseDown(with:) on the custom NSView subclass, and --lo and behold-- it gets called when I click inside the app window. So far, so good.
Next, I implemented keyDown(with:) to similarly handle keyboard input. However, at runtime, it does not get called and instead, I hear the annoying beep (NSBeep).
I tried implementing keyDown(with:) on the view controller instead, but it's all the same.
Finally, I tried implementing the key handler on my NSWindowController subclass instead, and that does work.
So I could get around this by forwarding the event like so:
class WindowController: NSWindowController {
override func keyDown(with event: NSEvent) {
contentViewController?.view.keyDown(with: event)
}
}
, but it is very inelegant. I would prefer to not pollute the app code with input logic.
This doesn't seem to have anything to do with embedding frameworks, however. I put together a minimal project from the 'Cocoa App' template and confirmed that indeed keyDown(with:) only gets called if implemented on the window controller code, but not on the view or view controller side.
How can I get keyDown(with:) to be called on the view or view controller (not the window or window controller) in a storyboard-based app? (so I can move it from the main app to my embedded framework).
Edit: The question has been marked as duplicate. I tried the solutions pointed in answers to the other question (namely, override acceptsFirstResponder to return true). This solves the problem in my minimal demo project, but when I tried it on my full app, it still does not work (I did see that question and did try to override acceptsFirstResponder in my app before posting this question).
I will now try to modify my minimal poeject to see if I can reporduce the issue in the main app.
Edit 2: I have refactored the minimal project to:
Send the view controller to a separate storyboard,
Send the view controller's storyboard and represented classes (custom view, custom view controller) to a separate, embedded framework.
Now the basic setup mirrors that of my app in all that seems to matter, but still can not reproduce the issue in the minimal project. I will investiate further...
Edit 3: I haven't been able to reproduce the issue on the minimal project.
On my app's custom view, I implemented:
public override var acceptsFirstResponder: Bool {
return true
}
public override func performKeyEquivalent(with event: NSEvent) -> Bool {
let retVal = super.performKeyEquivalent(with: event)
return retVal
}
On startup, acceptsFirstResponder is called twice.
When hitting any key, performKeyEquivalent(with:) is called twice, too. Inspectig the intermediate variable retVal above reveals that the super class's implementation always returns false. After returning from this method, NSBeep() is called and keyDown(with:) isn't.
If instead of super.performKeyEquivalent(with:) I force-return true, I can avert the call to NSBeep() (but keyDown(with:) is still not called...)
Edit 4 (Final):
Out of desperation, I cleared the "Custom Class" field of the window controller's Identity Inspector in my app's main storyboard (to the default NSWindowController).
Suddenly, my custom view's keyDown(with:) starts getting called.
I reinstated the custom class to confirm.
It still works.
I clean the build folder and try again.
It still works.
Now I can no longer reproduce the issue even on my main app. I really don't know what to say...
When I create a cocoa based mac osx application in xcode. I get a default class AppDelegate which is sublcass of NSObject < NSApplicationDelegate >
The application is one main window which has some buttons , tableview etc,
My question is should I make this AppDelegate class to be the controller of my main window ? or should I create a new controller. Under what condition should I choose my delegate to be the controller and when should I not ?
If the application is not some throwaway test application you should create a new controller and put there logic for the view. If the application starts to grow you may need even more controllers and views e.g. Status bar could be separate view with a separate controller.
In the AppDelegate you should put only the things that are specific for the complete application like menu, starting, stopping etc.
I'm stuck on a very stupid issue. I've built my mac osx app user interface with Interface Builder (and xcode3).
Now when I run my app I can't see the app window (but only the menu on top).
The MyDocument.xib file is correctly loaded (from xCode navigation sidebar) and I can see my user interface in interface builder.
In my code I haven't changed this method:
- (NSString *)windowNibName
{
// Override returning the nib file name of the document
// If you need to use a subclass of NSWindowController or if your document supports multiple NSWindowControllers, you should remove this method and override -makeWindowControllers instead.
return #"MyDocument";
}
What am I doing wrong ?
thanks
Check out the following methods in the NSApplicationDelegate documentation:
(BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender
(BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag
Each window has an option (checkbox) called visible at start (or something like that; can't check ATM). Doublecheck if that's activated.
It was a bad configured ArrayController!
No error messages.. just the interface not showing up
I am a beginner to Obj-C and Xcode 4 and I am currently going through the "Your First Mac Application" on the Mac Dev website. I have managed to get through the main part but I'm struggling on the "Refactor the Application Delegate" section.
I have created a new class (to use as a controller), added an object set to this new class, made the connections from the class to the slider, mute button and textfield, and I have connected the new class object to the app delegate interface file.
Unfortunately an instance of the track class is never created, and therefore the program doesn't work, as the awakeFromNib function never gets called. I have tried placing it in both the app delegate file and the new controller class.
Where am I going wrong???
You have to either create an instance of your new class in IB, or you need to create it programmatically in your AppDelegate object (usually in init or awakeFromNib). You need to have a pointer to that object in your AppDelegate. If you create the new object in IB, you connect it to the Track* pointer in IB. If you do it in code, it's something like:
in .h file:
TrackClass *track;
in .m file:
track = [[Track alloc] init];
Which did you do?
I had the same issue while trying out the tutorial and found out the problem was with my implementation of awakeFromNib
Wrong Code:
- (void)awakeFromNib:(NSNotification *)aNotification
Right Code
- (void)awakeFromNib
There should be no argument passing the implementation of awakeFromNib.
I have a small osx cocoa app that brings up an IKPictureTaker at start up, I would like for my application to quit after this picture taker is closed. I read that I need to add this code to my NSWindowController class but I have no idea how to access this class (it shows up no where in my class list in XCode):`
-(BOOL) applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
{
return YES;
}
You need to create a custom object that implements the NSApplicationDelegate protocol and implement the applicationShouldTerminateAfterLastWindowClosed method there.
If you already have an application delegate (you more than likely do), just add it there.
You have to add this method to your application delegate, whatever object that is.