{"id":22,"date":"2005-07-27T03:14:30","date_gmt":"2005-07-27T07:14:30","guid":{"rendered":""},"modified":"2005-09-15T20:31:31","modified_gmt":"2005-09-16T00:31:31","slug":"dynamically-populating-an-nspopupbuttoncell-in-an-nstableview","status":"publish","type":"post","link":"https:\/\/www.corbinstreehouse.com\/blog\/2005\/07\/dynamically-populating-an-nspopupbuttoncell-in-an-nstableview\/","title":{"rendered":"Dynamically populating an NSPopUpButtonCell in an NSTableView"},"content":{"rendered":"<p id=\"top\" \/>\n<p>It is quite common. You have a PopUpButton (NSPopUpButtonCell) in an NSTableView and you want to dynamically change the contents based on the selected row:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.corbinstreehouse.com\/blog\/PopupCellPicture1.png\" height=\"95\" width=\"434\" border=\"1\" hspace=\"4\" vspace=\"4\" alt=\"Popupcellpicture1\" \/><\/p>\n<p>How do you do this? There are a few tricky steps. First, add a menu to the nib and set the delegate for the menu to be your Controller:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.corbinstreehouse.com\/blog\/MenusDelegatePopupButton.png\" height=\"253\" width=\"653\" border=\"1\" hspace=\"4\" vspace=\"4\" alt=\"Menusdelegatepopupbutton\" \/><\/p>\n<p>Okay. Next is the tricky part. In IB, when you have a column in a tableview selected, it has a little white triangle in the corner:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.corbinstreehouse.com\/blog\/CellCloseupPopup.png\" height=\"23\" width=\"175\" border=\"1\" hspace=\"4\" vspace=\"4\" alt=\"Picture 1-3\" \/><\/p>\n<p>Clicking on that will allow you to modify properties of the cell (in this case, the NSPopUpButtonCell). However, we want to set the menu for the NSPopUpButtonCell, so drag from that little triangle to your menu and set the menu outlet:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.corbinstreehouse.com\/blog\/PopupCellHookUp.png\" height=\"483\" width=\"516\" border=\"1\" hspace=\"4\" vspace=\"4\" alt=\"Popupcellhookup\" \/><\/p>\n<p>Okay, good! Now, all your controller needs is a little bit of code to dynamically populate the menu:<\/p>\n<style type=\"text\/css\">\n    p.p1 {margin: 0.0px 0.0px 0.0px 24.0px; text-indent: -24.0px; font: 10.0px Monaco}\n    p.p2 {margin: 0.0px 0.0px 0.0px 48.0px; text-indent: -48.0px; font: 10.0px Monaco; color: #236e25}\n    p.p3 {margin: 0.0px 0.0px 0.0px 48.0px; text-indent: -48.0px; font: 10.0px Monaco}\n    p.p4 {margin: 0.0px 0.0px 0.0px 72.0px; text-indent: -72.0px; font: 10.0px Monaco}\n    p.p5 {margin: 0.0px 0.0px 0.0px 96.0px; text-indent: -96.0px; font: 10.0px Monaco}\n    p.p6 {margin: 0.0px 0.0px 0.0px 138.0px; text-indent: -138.0px; font: 10.0px Monaco}\n    span.s1 {color: #760f50}\n    span.s2 {color: #000000}\n    span.s3 {color: #0000ff}\n    span.s4 {color: #891315}\n  <\/style>\n<\/p>\n<p class=\"p1\">&#8211; (<span class=\"s1\">void<\/span>)menuNeedsUpdate:(NSMenu *)menu {<\/p>\n<p class=\"p2\"><span class=\"s2\"><\/span><span class=\"Apple-converted-space\">\u00c2\u00a0 \u00c2\u00a0 <\/span>\/\/ remove all previous items<\/p>\n<p class=\"p3\"><span class=\"Apple-converted-space\">\u00c2\u00a0 \u00c2\u00a0 <\/span><span class=\"s1\">while<\/span> ([menu numberOfItems] > <span class=\"s3\">0<\/span>) {<\/p>\n<p class=\"p4\"><span class=\"Apple-converted-space\">\u00c2\u00a0 \u00c2\u00a0 \u00c2\u00a0 \u00c2\u00a0 <\/span>[menu removeItemAtIndex:<span class=\"s3\">0<\/span>];<\/p>\n<p class=\"p3\"><span class=\"Apple-converted-space\">\u00c2\u00a0 \u00c2\u00a0 <\/span>}<\/p>\n<p class=\"p2\"><span class=\"s2\"><\/span><span class=\"Apple-converted-space\">\u00c2\u00a0 \u00c2\u00a0 <\/span>\/\/ dynamically build the menu<\/p>\n<p class=\"p3\"><span class=\"Apple-converted-space\">\u00c2\u00a0 \u00c2\u00a0 <\/span><span class=\"s1\">int<\/span> i;<\/p>\n<p class=\"p3\"><span class=\"Apple-converted-space\">\u00c2\u00a0 \u00c2\u00a0 <\/span><span class=\"s1\">int<\/span> selectedRow = [tableViewStuff selectedRow];<\/p>\n<p class=\"p3\"><span class=\"Apple-converted-space\">\u00c2\u00a0 \u00c2\u00a0 <\/span><span class=\"s1\">for<\/span> (i = <span class=\"s3\">0<\/span>; i &lt;= selectedRow; i++) {<\/p>\n<p class=\"p4\"><span class=\"Apple-converted-space\">\u00c2\u00a0 \u00c2\u00a0 \u00c2\u00a0 \u00c2\u00a0 <\/span>NSMenuItem *item = [[NSMenuItem alloc]<span class=\"Apple-converted-space\">\u00c2\u00a0<\/span><\/p>\n<p class=\"p5\"><span class=\"Apple-converted-space\">\u00c2\u00a0 \u00c2\u00a0 \u00c2\u00a0 \u00c2\u00a0 \u00c2\u00a0 \u00c2\u00a0 <\/span>initWithTitle:[NSString stringWithFormat:<span class=\"s4\">@\u00e2\u20ac\u0153Menu %d\u00e2\u20ac\u009d<\/span>, i]<span class=\"Apple-converted-space\">\u00c2\u00a0<\/span><\/p>\n<p class=\"p6\"><span class=\"Apple-converted-space\">\u00c2\u00a0\u00c2\u00a0 \u00c2\u00a0 \u00c2\u00a0 \u00c2\u00a0 \u00c2\u00a0 \u00c2\u00a0 \u00c2\u00a0 \u00c2\u00a0 \u00c2\u00a0 <\/span>action:<span class=\"s1\">@selector<\/span>(menuClicked:) keyEquivalent:<span class=\"s4\">@\u00e2\u20ac\u0153\u00e2\u20ac\u009d<\/span>];<\/p>\n<p class=\"p4\"><span class=\"Apple-converted-space\">\u00c2\u00a0 \u00c2\u00a0 \u00c2\u00a0 \u00c2\u00a0 <\/span>[item setTarget:<span class=\"s1\">self<\/span>];<\/p>\n<p class=\"p4\"><span class=\"Apple-converted-space\">\u00c2\u00a0 \u00c2\u00a0 \u00c2\u00a0 \u00c2\u00a0 <\/span>[menu addItem:item];<\/p>\n<p class=\"p3\"><span class=\"Apple-converted-space\">\u00c2\u00a0 \u00c2\u00a0 <\/span>}<\/p>\n<p class=\"p1\">}<\/p>\n<p>Okay, that should work, right? Normally, yes. But in a tableview when a cell is tracked, it is first copied. Unfortunately, a small bug in the menu code doesn&#8217;t copy the delegate. Therefore, we must fix it up in the nstableview&#8217;s delegate method:<\/p>\n<p class=\"p1\">&#8211; (<span class=\"s1\">void<\/span>)tableView:(NSTableView *)tableView<span class=\"Apple-converted-space\">\u00c2\u00a0<\/span><\/p>\n<p class=\"p2\"><span class=\"Apple-converted-space\">\u00c2\u00a0 <\/span>willDisplayCell:(<span class=\"s1\">id<\/span>)cell<span class=\"Apple-converted-space\">\u00c2\u00a0<\/span><\/p>\n<p class=\"p3\"><span class=\"Apple-converted-space\">\u00c2\u00a0\u00c2\u00a0 <\/span>forTableColumn:(NSTableColumn *)tableColumn<span class=\"Apple-converted-space\">\u00c2\u00a0<\/span><\/p>\n<p class=\"p4\"><span class=\"Apple-converted-space\">\u00c2\u00a0 \u00c2\u00a0 \u00c2\u00a0 \u00c2\u00a0 \u00c2\u00a0 \u00c2\u00a0 \u00c2\u00a0 <\/span>row:(<span class=\"s1\">int<\/span>)row<span class=\"Apple-converted-space\">\u00c2\u00a0<\/span><\/p>\n<p class=\"p1\">{<\/p>\n<p class=\"p5\"><span class=\"Apple-converted-space\">\u00c2\u00a0 \u00c2\u00a0 <\/span><span class=\"s1\">if<\/span> ([cell isKindOfClass:[NSPopUpButtonCell class]]) {<\/p>\n<p class=\"p6\"><span class=\"Apple-converted-space\">\u00c2\u00a0 \u00c2\u00a0 \u00c2\u00a0 \u00c2\u00a0 <\/span>[[cell menu] setDelegate:<span class=\"s1\">self<\/span>];<\/p>\n<p class=\"p5\"><span class=\"Apple-converted-space\">\u00c2\u00a0 \u00c2\u00a0 <\/span>}<\/p>\n<p class=\"p1\">}<\/p>\n<p>That&#8217;s it! Have fun&#8230;happy coding.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>It is quite common. You have a PopUpButton (NSPopUpButtonCell) in an NSTableView and you want to dynamically change the contents based on the selected row: How do you do this? There are a few tricky&#8230; <a class=\"read-more\" href=\"https:\/\/www.corbinstreehouse.com\/blog\/2005\/07\/dynamically-populating-an-nspopupbuttoncell-in-an-nstableview\/\">[read more]<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[6,1],"tags":[],"class_list":["post-22","post","type-post","status-publish","format-standard","hentry","category-cocoa","category-general"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.corbinstreehouse.com\/blog\/wp-json\/wp\/v2\/posts\/22","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.corbinstreehouse.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.corbinstreehouse.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.corbinstreehouse.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.corbinstreehouse.com\/blog\/wp-json\/wp\/v2\/comments?post=22"}],"version-history":[{"count":0,"href":"https:\/\/www.corbinstreehouse.com\/blog\/wp-json\/wp\/v2\/posts\/22\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.corbinstreehouse.com\/blog\/wp-json\/wp\/v2\/media?parent=22"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.corbinstreehouse.com\/blog\/wp-json\/wp\/v2\/categories?post=22"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.corbinstreehouse.com\/blog\/wp-json\/wp\/v2\/tags?post=22"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}