Binding image to NSPopupbutton from NSArrayController - objective-c

This question is an extension to link
(The question in the link mainly targets, binding NSPopupbutton to a NSArrayController)
I have a Person class having properties NSString *name and NSImage *avatar
I have to show all the names of persons in Popup button as seen in the below image.
But now, as requirement has changed, I need to show avatar of person also.
How do I use Cocoa bindings to bind person's avatar to NSPopup button so that it looks like the one in above image for michael(last menu option)
Note: Michael has been temporarily added for demonstration using following code:
person.title = #"Michael";
person.image = [NSImage imageNamed:#"avatar.png"];
[_popupButton.menu addItem:person];

There are two ways you can achieve that:-
First take the cell-based tableview inside that two column one for image cell and second for text cell. Populate the table through bindings and then add your tableview inside your popup button in the below way:-
NSMenu *theMenu = [[NSMenu alloc] initWithTitle:#""];
NSMenuItem *Item = [[NSMenuItem alloc] initWithTitle:#"NameList" action:NULL keyEquivalent:#""];
[Item setView:self.tableVw];
[theMenu addItem:Item];
[self.popUptn setMenu:theMenu];
Second follow the below simple steps:-
Assuming your array contains the name elements.
1) Select your arrayContoller bind to FileOwner's and ModelKeyPath->array.
2) Select PopUpButton inside binding Inspector->Selected Object bind to FileOwner's and ModelKeyPath->yourString. This will select the required name accordingly.
3) Select PopUpButton inside binding Inspector->Content Valuesand ModelKeyPath->array
4) Now for setting the image inside popupButton refer below code:-
NSMenuItem *menuItm=[self.popUpBtn itemWithTitle:#"Michael"];
[menuItm setImage:[NSImage imageNamed:#"dot.gif"]];
Edit:-
1) In the first method your text and image both are populating through binding just you need to add that tableview inside your popupbutton.
2) In the second method your popupbutton will display the image for last name but programmatically. And also, if required to display the images for all names then use for loop to set images inside menu item.

Related

iOS Segmented Control Set Segments After Creation

In a custom uitableviewcell, the segmented control is created when the row is created. Each row is a question in a form. Depending on the type of question, the segmented control can have different answers. In the UISegmentedControl reference it only lists the init method as allowing setting all segments at once. Is there a better way than using remove and insert to update the segment to have the pertinent segments?
In the custom UITableView cell's init it has
_answerSegmented = [[UISegmentedControl alloc] init];
[_answerSegmented addTarget:self action:#selector(answerChanged:) forControlEvents:UIControlEventValueChanged];
_answerSegmented.backgroundColor = [UIColor columnHeaderBackground];
[self addSubview:_answerSegmented];
It's not until later that it knows what the segments should be
NSMutableArray *answers = [NSMutableArray arrayWithObjects:#"IN", #"OUT", nil];
if (_question.noItem.boolValue) {
[answers addObject:#"N/O"];
}
if (_question.naItem.boolValue) {
[answers addObject:#"N/A"];
}
_answerSegmented.segments = answers; // <---- this line gives a compile error
No, there is no better way. If all segmented controls have the same number of segments then create the control with that number of segments. Then simply use setTitle:forSegmentAtIndex: to change the title of each segment, one at a time.
If the number can change, use removeAllSegments and insertSegmentWithTitle:atIndex:animated:.
Or simply create a new segmented control and remove the old one each time.

How can I bind to the Image property of a NSPopUpButtonCell?

I've created a NSTableView, and have set up all my bindings (via an NSArrayController). I want one of the columns to have a NSPopUpButtonCell, but, instead of showing text, I want it to show an image - so the user can change the image from the popup control.
My column is bound (using the SelectedObject binding) to the correct property, and the the NSPopUpButtonCell is bound (using the ContentValues binding) to my complete list of images (which is from another NSArrayController containing an array of image names - NSStrings).
I've created a NSValueTransformer to convert an image name (NSString) to an NSImage, and have tested this works by creating an addition column with an NSImageCell, and that displays the image correctly.
Is there a way to do this?
I'm hoping I can target the binding at the NSPopUpButtonCell's image property, rather than its title property.
Edit: I had the idea of trying to use an NSAttributedString, with an embedded image. But, the problem remains, in that I want the binding to use setAttributedTitle, rather than setTitle.
After a lot of trial and error, I've managed to solve this problem. I'm convinced there remains a more correct solution, but, for now, this'll do.
My solution:
Change the Pop Up Button Cell > Menu to a custom class
In the custom class, inherit from NSMenu:
#interface RSMenu : NSMenu
Override insertItemWithTitle, and customize to your own needs.
For example:
-(NSMenuItem *)insertItemWithTitle:(NSString *)aString
action:(SEL)aSelector
keyEquivalent:(NSString *)charCode
atIndex:(NSInteger)index {
NSImage *image = [NSImage imageNamed:aString];
NSMenuItem* menuItem = [super insertItemWithTitle:image ? #"" : aString
action:aSelector
keyEquivalent:charCode atIndex:index];
if ( nil != image ) {
[menuItem setImage:image];
}
return menuItem;
}
And here is the result:
Hope this helps someone else.

NSDocument based application and NSToolbar

I have application based on NSDocument (NSPersistentDocument), in application I can create (as usually) more than one document.
Main document window (based on NSPersistentDocument) has, added IB, toolbar. In code I add to toolbar item (NSToolbarItems) using methods insertItemWithItemIdentifier and - (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag.
Code samples:
[_toolbar insertItemWithItemIdentifier:#"addTape" atIndex:2];
and
- (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag {
NSToolbarItem *item =nil;
if ([itemIdentifier isEqual:#"addTape"]) {
item = [[NSToolbarItem alloc] initWithItemIdentifier: itemIdentifier];
item.label = NSLocalizedString(#"Add Tape",#"Add Tape");
item.paletteLabel = NSLocalizedString(#"Add Tape",#"Add Tape");
item.toolTip = NSLocalizedString(#"Adds new tape",#"Adds new tape");
item.image = [NSImage imageNamed:#"NSAddTemplate"];
item.target = self;
item.action = #selector(addTape:);
item.tag = 101;
}
}
Everything is correct until I have opened only one document. When I open second document (or create new document) on first document window toolbar items are doubled (after opening third document, items are tripled on first window and doubled on second, and so on).
Edit: I noticed, that itemForItemIdentifier is called on each window, everytime I try to add toolbar item. In example: if I have two windows (two opened document) and on one I try to add one button itemForItemIdentifier is called two times.
It is strange to me, because every document has own toolbar with delegate set only to this document.
I don't have any idea what I have done wrong. Maybe someone will point me where I made a mistake.
You don't typically insert toolbar items yourself; implement the delegate methods toolbarAllowedItemIdentifiers: and toolbarDefaultItemIdentifiers: and the toolbar will be initialized according to those lists.
I found solution: I cannot use tooolbar created from nib, because each created this method toolbar has this same identifier. When I created toolbars in code, using different identifiers, the problem has gone.

setting an accessibilityLabel on a UIImageView contained in UITableView header

I have a UITableView that I build in loadView. One of the things I do in loadView is create a UIView to act as the table header and stuff a UIImageView into it. The image view contains an image that is a stylized title, so I want to add an accessibility label for VoiceOver users. However, I can't get VoiceOver to "focus" on the image in order to read the label, and the Accessibility Inspector doesn't respond to clicking on the image in the simulator. My (abbreviated) code follows:
... in -loadView ...
// Make header view
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(...)];
UIImageView *titleImageView = [[UIImageView alloc] initWithImage:[self titleImage]];
titleImageView.accessibilityLabel = [self accessibilityLabelForTitleImage];
[headerView addSubview:titleImageView];
// Make table view
self.tableView = [[UITableView alloc] initWithFrame:CGRect(...) style:UITableViewStylePlain];
self.tableView.tableHeaderView = headerView;
... code continues ...
I've stepped through in gdb and accessibilityLabelForTitleImage returns a string. po [titleImageView accessibilityLabel] prints out the correct string, but I'm still unable to focus on the image view. Note that the views themselves appear and respond as appropriate.
Am I missing something? Is there a way to force VoiceOver to acknowledge an image view?
In Voice-Over , in order to make an element accessible :-
you have to set setIsAccessibilityElement property as true which i don't find in your code.
The other important point is that to make child elements (subviews) to be accessible , you have to seperately make them accessible while the parent should not be accessible(you have to specify this also).
Implement the UIAccessibilityContainer Protocol in your custom - cell.
It will be a big story if i go on .Please refer this Accessibility voice over by apple.
Hope this helps.
I used KIF for testing my IOS app. In my tableview, I assigned value to tableview.accesssibilityIdentifier instead of tableview.accessibilityLabel. It worked for me. Wanna give it a try?
Voice-Over sometimes can get nasty and just by setting isAccessibilityElement might not work.
In this case try setting accessibilityElements on the parent view and include the child views in the array, like this:
parentView.accessibilityElements = [childView1, childView1, childView1]
Doing it also ensures that the accessibility items are being read in the order you want.

Setting title on NSMenuItem, without effect

I'm getting an NSMenuItem from the Main Menu, with the code here : Getting NSMenuItem of NSMenu tree by title
However, something strange happens :
An NSMenuItem connected with an action : When using the sender
property (NSMenuItem) and setting the title, it works.
BUT : When getting the item with the function above and set the title,
the NSMenuItem's title does change, but the change is NOT
reflected in the menu it belongs to.
What am I doing wrong? (I'm sure this one is really stupid... )
NSMenuItem* mi = [[core mainMenu] getItemWithPath:#"View" tag:PP_MENU_TAG_STATUSBAR];
[mi setTitle:#"newTitle"];
NSLog(#"mi : %#",[mi title]);
// mi changes, but no changes take effect in the mainMenu
I would forget the
Getting NSMenuItem of NSMenu tree by title code and just connect each menu in IB.
Then use the setTitle on it when needed
UPDATE*
(see comments)
It took me awhile to figure out why even my test one was not working!!. I had put in a attributed title within IB.
So when I later used setTitle. The property was being set but the actual displayed menu was overridden by the attributed title.
Removing the attributed title from IB. fixed this. And setTitle works as expected.
Also I have never used attributed title before. And I just pasted in some formatted coloured text in the IB attributed title. And the menu item was the same in colour and font.
Which I have always wanted to be able to do but thought was not possible.
And doing it programmatically is easy.
NSMutableAttributedString * string = [[NSMutableAttributedString alloc] initWithString:#"newTestMenu"];
[string addAttribute:NSForegroundColorAttributeName value:[NSColor redColor] range:NSMakeRange(0,string.length)];
[_testMenu setAttributedTitle:string];