NSWindow update content when show/hide - objective-c

I have added NSWindow element in my.xib file and inserted some element to it, such as imageView. And then created class of type NSWindow named customNSWindow and assign these class to the xib element which I have created(NSWindow). Now from another WindowController I need to show/hide the customNSWindow. This is done by putting an outlet to the WindowController.
viewController.h
#property (strong) IBOutlet NSWindow *ImageEditWindow;//(custom window)
viewController.mm
-(IBAction)ButtonClick:(id)sender {
if(! [_ImageEditWindow isVisible] ){
[_ImageEditWindow makeKeyAndOrderFront:sender];
}
}
But I don't know I how to update image in ImageEditWindow, I cannot find way to call a method inside the custom class I created, using _ImageEditWindow outlet.
Edit
Here is the custom class for NSWindow
CustomIKImageEditor.h
#interface CustomIKImageEditor : NSWindow
#property (weak) IBOutlet IKImageView *IKImg;
-(void) updateIKImage: (NSImage*)staticImageToEdit;
#end
CustomIKImageEditor.mm
-(void) updateIKImage: (NSImage*)staticImageToEdit {
NSDictionary* _imageProperties;
CGImageRef source = [self CGImageCreateWithNSImage: staticImageToEdit];
_imageProperties = NULL;
[_IKImg setImage: source imageProperties: NULL];
}

This line:
#property (strong) IBOutlet NSWindow *ImageEditWindow;//(custom window)
Should be:
#property (strong) IBOutlet CustomIKImageEditor *ImageEditWindow;//(custom window)

Related

IBInspectable property values not updating in xib

I'm running into a minor complication using IBInspectable properties and not sure if it might have something to do with my xibs and xib usage. I'm trying to reuse a custom control between multiple view controllers. The control is a custom tab manager:
The IBInspectable Attributes are configured in this xib as: First, Second, Third.
Here is the corresponding code for the header file.
IB_DESIGNABLE
#interface TabContainerView : NSView
#property (nonatomic, strong) IBOutlet NSView *view;
#property (weak) IBOutlet TabContentView *contentView;
#property (weak) IBOutlet TabView *firstTab;
#property (weak) IBOutlet TabView *secondTab;
#property (weak) IBOutlet TabView *thirdTab;
#property (nonatomic, strong) IBInspectable NSString *tabOneText;
#property (nonatomic, strong) IBInspectable NSString *tabTwoText;
#property (nonatomic, strong) IBInspectable NSString *tabThreeText;
#end
#import "TabContainerView.h"
#interface TabContainerView ()
#property (nonatomic, strong) NSMutableArray *tabsArray;
#property (nonatomic, assign) NSInteger selectedTabIndex;
#property (weak) IBOutlet NSTextField *tabOneTextField;
#property (weak) IBOutlet NSTextField *tabTwoTextField;
#property (weak) IBOutlet NSTextField *tabThreeTextField;
#end
#implementation TabContainerView
#pragma mark Init
- (id)initWithFrame:(NSRect)frameRect {
NSString* nibName = NSStringFromClass([self class]);
self = [super initWithFrame:frameRect];
if (self) {
if ([[NSBundle mainBundle] loadNibNamed:nibName
owner:self
topLevelObjects:nil]) {
[self configureView];
}
}
return self;
}
#pragma mark Configure View
- (void)configureView{
[self.view setFrame:[self bounds]];
[self addSubview:self.view];
self.tabOneTextField.stringValue = self.tabOneText;
self.tabTwoTextField.stringValue = self.tabTwoText;
self.tabThreeTextField.stringValue = self.tabThreeText;
}
#end
This works fine in the TabContainerView.xib without issue. Now when I attempt to use this control in two different view controllers, I run into problems. Both of my view controllers are also loaded from Xibs.
In view controller 1 I have something like this:
In view controller 1 I've subclassed the custom view to the TabContainerView subclass which works just fine when I run the application. I've also changed the text to be specific for this view controller. List, Map, Filter are the IBInspectable property values for view controller one. In view controller 2 (not shown), I've done the exact same thing, however different IBInspectable property values specific for view controller 2. However, when I run the application the values never update and always stay as First, Second, and Third. I'm not sure if there is something I'm doing that's causing this problem but any help or tips would be appreciated. (IBDesignable seems to give me a lot of warnings where it breaks and not sure if maybe it's just loading the last saved value for the xib.)
Have you imported #import "TabContainerView.h" in controller 2 .h file.

Double click on row in NSTableView doesn't display the new view

I have an os x app that uses core data.
I have 3 .xib files in my app, those are:
1. MainMenu.xib
2. MasterTableViewController.xib
3. DetailViewController.xib
When started , app displays a view that has NSTableView with couple of records in it.
I name that view MasterTableViewController
I want when user double click on the row, to hide the "master" view and to display my "detail" view. I named that view DetailViewController.
When double clicked on the row in the NSTableView in the "master" view,nothing happen, "master" view remains visible. What I want is "master" view to dissapear, and "detail" view to appear.
Here is the code that I have right now, and more explanations follows:
AppDelegate.h
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate>
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (nonatomic,strong) NSViewController *mainAppViewController;
#property (weak) IBOutlet NSView *mainAppView;
- (void)changeViewController:(NSInteger)tag;
#property (weak) IBOutlet NSTableView *websitesTableView;
- (void)tableViewDoubleClick:(id)nid;
#end
AppDelegate.m
#import "AppDelegate.h"
#import "MasterTableViewController.h"
#import "DetailViewController.h"
#interface AppDelegate ()
#property (weak) IBOutlet NSWindow *window;
- (IBAction)saveAction:(id)sender;
#end
#implementation AppDelegate
NSString *const masterTable = #"MasterTableViewController";
NSString *const detail = #"DetailViewController";
-(void)awakeFromNib {
[_websitesTableView setTarget:self];
[_websitesTableView setDoubleAction:#selector(tableViewDoubleClick:)];
}
- (void)tableViewDoubleClick:(id)nid {
NSInteger rowNumber = [_websitesTableView clickedRow];
NSTableColumn *column = [_websitesTableView tableColumnWithIdentifier:#"websiteUrl"];
NSCell *cell = [column dataCellForRow:rowNumber];
NSInteger tag = 2;
[self changeViewController:tag];
}
- (void)changeViewController:(NSInteger)tag {
[[_mainAppViewController view]removeFromSuperview];
switch (tag) {
case 1:
self.mainAppViewController = [[MasterTableViewController alloc]initWithNibName:masterTable bundle:nil];
break;
case 2:
self.mainAppViewController = [[DetailViewController alloc]initWithNibName:detail bundle:nil];
break;
}
[_mainAppView addSubview:[_mainAppViewController view]];
[[_mainAppViewController view] setFrame:[_mainAppView bounds]];
[[_mainAppViewController view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// automatically run the master table view controller
NSInteger tag = 1;
[self changeViewController:tag];
}
Now, some of you may wondering, where is the rest of the code. I have ommited the boiler plate code for the core data below in the AppDelegage.m, since it is unchanged. I used binding to make my NSTableView to work and to display my records, so MasterTableViewController.h and .m files are empty, and same is true for the DetailViewController.h and .m file.
Important note - What i can't understand here: If I change the tag in 2 in the applicationDidFinishLaunching method, detail view is displayed normally, but if i switch it back on 1, and then double click on the row, "master" view (with the NSTableView) remains visible, and nothing happen (views are not swapped)
Anyone can help me to find out what is wrong with my code?
Regards, John
You apparently had a second instance of your AppDelegate class instantiated in the MasterTableViewController.xib file. There should be only one AppDelegate instance and that's the one in MainMenu.xib. So, it shouldn't be in MasterTableViewController.xib.
One of the instances was receiving the double-click action method from the table, but the other one was the one with the outlet to the main window.
You need(ed) to get rid of the second instance and find another way to access the app delegate from the MasterTableViewController.

How to change NSMenuItem Title (Login to Logout)

Im surprised that this hasn't already been asked:
But how does one go about changing the NSMenuItem title in a NSStatusBar menu. When a user logs in I want the menu item to say logout. I have tried creating an outlet to modify my NSMenuItem as a would a label or something.
AppDelegate.h
#property (retain) IBOutlet NSMenuItem *loginItem;
AppDelegate.m
[loginItem setTitle:#"Logout"];
But that didnt work.
The only thing that I was able to do was delete the old NSMenuItem, then add a new one, but it would just add it to the bottom. Is the only way to do this to remove every menu item then re-add them?? That seems very inefficient.
The method you describe should work, though, in general, keeping IBOutlets for all your menu items can be tedious. (If your solution isn't working, make sure the IBOutlet is actually connected in the nib file, and make sure that you're setting the title at an appropriate time. If you're trying to set it in your controller's init method, for example, that's too early on, and the outlets haven't yet been connected up: move the method to awakeFromNib or similar.
A better approach in the long run is to use the <NSMenuDelegate> protocol and NSMenuValidation (informal) protocol to update menu items dynamically (and lazily).
For example, define your controller class like the following:
#interface MDAppDelegate : NSObject <NSApplicationDelegate, NSMenuDelegate>
#property (strong) NSStatusItem *statusItem;
#property (weak) IBOutlet NSWindow *window;
#property (weak) IBOutlet NSMenu *statusItemMenu;
#property (weak) IBOutlet NSMenuItem *toggleLoginLogoutMenuItem;
#property (weak) IBOutlet NSTextField *statusField;
#property (weak) IBOutlet NSTextField *progressField;
#property (weak) IBOutlet NSProgressIndicator *progressIndicator;
#property (assign) BOOL loggedIn;
- (IBAction)toggleLoginLogout:(id)sender;
#end
In the nib file, the delegate outlet of the statusItemMenu is set to the MDAppDelegate controller class. That assures that the MDAppDelegate class is in the responder chain and allow it to work with validating the menu items.
Then you could implement your .m like the following:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
_statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
_statusItem.menu = _statusItemMenu;
_statusItem.title = NSLocalizedString(#"NSStatusItem", #"");
[self updateLoggedInStatus];
}
- (void)updateLoggedInStatus {
[self.statusField setStringValue:(self.loggedIn ? #"Logged in" : #"Logged out")];
}
- (IBAction)toggleLoginLogout:(id)sender {
[self performSelector:#selector(finishFakeLoginLogout:)
withObject:nil afterDelay:2.0];
}
- (void)finishFakeLoginLogout:(id)sender {
self.loggedIn = !self.loggedIn;
[self updateLoggedInStatus];
}
- (void)menuNeedsUpdate:(NSMenu *)menu {
#if MD_DEBUG
NSLog(#"[%# %#]", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
#endif
}
- (BOOL)validateMenuItem:(NSMenuItem *)menuItem {
#if MD_DEBUG
NSLog(#"[%# %#]", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
#endif
SEL action = menuItem.action;
if (action == #selector(toggleLoginLogout:)) {
[menuItem setTitle:(self.loggedIn ? #"Logout" :#"Login")];
}
return YES;
}
Sample project: http://github.com/NSGod/NSStatusBarFinagler
You don't need to connect your menu item just try this..
NSMenuItem *menuItem = (NSMenuItem*) sender;
NSString *menuString = menuItem.title;
if ([menuString isEqualToString:#"Login"])
{
[menuItem setTitle:#"LogOut"];
}
NSMenuItem menuItem = (NSMenuItem) sender;
this line automatically collect the menu items in your app.

Delegate does not get called

I have a UIPageViewController which I setup in the viewDidLoad method of the RootViewController as follows:
[self addChildViewController:self.pageViewController];
[self.view addSubview:self.pageViewController.view];
The delegate pageViewControllerspineLocationForInterfaceOrientation is called successfully and I can set the spine accordingly.
However, I want to setup the PageViewController on a button click so I moved the code to the event handler of the button pressed event. Now the delegate is not called.
Any ideas how I can fix it?
It is some what complicated but can be achieved through the code below :
Step 1: Add below code to .h file of rootViewController.
#property (strong, nonatomic) IBOutlet UIButton *previousClick;
#property (strong, nonatomic) IBOutlet UIButton *nextClick;
Step 2: Connect them to the xib or storyboard which ever you use.
Step 3: Add two IBAction methods to .m file.
#pragma mark - IBAction Methods
- (IBAction)previousClick:(id)sender
{
[_modelController pageViewController:self.pageViewController viewControllerBeforeViewController:_dataViewController];
}
- (IBAction)nextClick:(id)sender
{
[_modelController pageViewController:self.pageViewController viewControllerAfterViewController:_dataViewController];
}
Step 4: You also need to put below lines too to .m file
#interface RootViewController ()
#property (readonly, strong, nonatomic) ModelController *modelController;
#property (readonly, strong, nonatomic) DataViewController *dataViewController;
#end
And synthesize them as below
#synthesize modelController = _modelController;
#synthesize dataViewController = _dataViewController;
Step 5: Last and final add below line to - (UIPageViewControllerSpineLocation)pageViewController:(UIPageViewController *)pageViewController spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation method.
_dataViewController = currentViewController;
after the currentViewController's alloc init call.
If you find that the added buttons are hidden by the pageViewController just bring them to the front using the code below in side the -viewDidLoad method
[self.view bringSubviewToFront:self.previousClick];
[self.view bringSubviewToFront:self.nextClick];

How do I hide a button when an IBAction is performed?

I am attempting to hide a NSButton that performs miniaturize when a different NSButton on the interface is clicked. My attempts thus far have been unsuccessful, this is what I have tried:
.h file:
#interface AppDelegate : NSObject <NSApplicationDelegate> {
IBOutlet NSWindow *window;
IBOutlet WebView *webView;
IBOutlet NSButton *doMinimize;
}
#property (assign) IBOutlet NSWindow *window;
#property (assign) IBOutlet NSButton *button;
#property (nonatomic, retain) IBOutlet WebView *webView;
.m file:
#implementation AppDelegate
#synthesize window;
#synthesize webView;
#synthesize doMinimize;
- (IBAction)toggleFullscreen:(id)sender
{
...
[doMinimize setEnabled:NO];
[doMinimize setTransparent:YES];
...
}
It appears that no matter in what action I try to disable and make the button transparent, it doesn't seem to respond to anything. Do I have to give the button it's own class to make this work? If so, how would I then be able to modify that button from an IBAction inside of a different class?
I apologize in advance if my question is silly, I'm relatively new to the world of Objective-C and am just now starting to get my feet wet.
Thanks in advance.
Have you tried -setHidden:?
[doMinimize setHidden:YES];