6

I have a NSCollectionView (OS X, not iOS) bound to my model. Each collection view item has a button and a label. I'm handling the click actions and I have the sender and event arguments but I unable to distinguish one button from the others. Most other questions not dealing with Collection Views say to use the tag property, but this isn't exposed on the Interface Builder's bindings tab. There is an Argument and Argument2 bindings, but they dont seems to correspond to the tag property in the objc code and I don't know how to otherwise access these Arguments.

-(void)image_click:(id)sender forEvent:(NSEvent *)event
{
    NSButton *btn = sender;
    NSLog(@"image clicked, %ld", (long)btn.tag);   //image clicked, 0
}

How do I differentiate between buttons in Objective-C code inside the click actions of a bunch of buttons in a collection view?

jrturton
  • 118,105
  • 32
  • 252
  • 268
Jeff
  • 13,943
  • 11
  • 55
  • 103
  • Please refer to this answer by Peter Hosey - http://stackoverflow.com/questions/15468789/get-the-representedobject-values-of-nscollectionviewitem-nsbutton-click – Sagar Natekar Feb 17 '14 at 21:08

5 Answers5

2

Add a Model in your project named MyModel and declare property uniqueID in MyModel.h

@interface MyModel:NSObject  
@property (retain) NSString* unqiueID;  
@end  

MyModel.m

@implementation MyModel  
@synthesize uniqueID=_uniqueID;
@end

In AppDelegate.m create some model objects and add them into an array

In IB add an ArrayController and bind it to the array declare in AppDelegate

In IB select CollectionView and bind its Content property to ArrayController and set its ControllerKey property to arrangedObjects

In your Template View Use NSButton's Target and Argument bindings to send unique arguments to the selector specified

Your Arguments binding should look like this
Bind to: Controller View Item
Model Key Path: representedObject.uniqueID
Selector Name: buttonClicked:

and Target bindings
Bind to: App Delegate
Model Key Path: self
Selector Name: buttonClicked:

The steps are explained in detail in the following tutorial
https://developer.apple.com/library/mac/documentation/cocoa/Conceptual/CollectionViews/Introduction/Introduction.html#//apple_ref/doc/uid/TP40009030
Hope this helps

Nisar Ahmed
  • 67
  • 1
  • 8
  • 1
    You should declare the selector in AppDelegate.m -(void)buttonClicked:(id)object If you setup bindings correctly then object would be your unique argument – Nisar Ahmed Jun 30 '13 at 06:30
  • Are you sure the link to the tutorial is correct? That is just the `NSCollectionView` class reference, not a tutorial and it doesn't talk about the binging argument or target. – Jeff Jul 01 '13 at 15:51
  • https://developer.apple.com/library/mac/documentation/cocoa/Conceptual/CollectionViews/Introduction/Introduction.html#//apple_ref/doc/uid/TP40009030 – Nisar Ahmed Jul 03 '13 at 18:37
2

I'm assuming you want to determine the model object being represented by the button in the view. I was able to determine the model object by looping over the buttons in the collection view. I couldn't use the selection index or any other similar attribute, but in the end, the model can be determined.

Assuming your NSArrayController already has your array, then do the following:

Bindings:

The Collection View only needs one binding

Bind to:         <NSArrayController instance>
Controller Key:  arrangedObjects
Model Key Path:  <blank>

Controller:

You should hook up the controller to the content view

property (weak) IBOutlet NSCollectionView *collectionView;

Finally, the controller receiving the button click message should implement this IBAction:

- (IBAction) collectionViewClick:(id)sender
{  
  id objectInClickedView = nil;

  for( int i = 0; i < [[self.collectionView content] count]; i++ ) {
    NSCollectionViewItem *viewItem = [self.collectionView itemAtIndex:i];

    if( [sender isDescendantOf:[viewItem view]] ) {
      objectInClickedView = [[self.collectionView content] objectAtIndex:i];
    }
  }
}

Which will assign the object to objectInClickedView. If you're actually interested on the view or viewItem, you can modify the code.

Dave FN
  • 652
  • 1
  • 14
  • 29
1

I would do it like this (because the button you want to press should be coupled with the corresponding model, therefore the represented object):

  1. Add a method to the model of your collectionViewItem (e.g. buttonClicked)
  2. Bind the Button Target to Collection View Item
  3. While binding set model key path to: representedObject
  4. While binding set selectorname to: methodname you chose earlier (e.g. buttonClicked)
  5. Add protocol to your model, if you must tell delegate
Dom
  • 658
  • 6
  • 10
  • This is simpler and more direct than some of the other suggested methods. In code you define a custom object that will hold the data you want to display in the collection view and that will also implement the required button action, e.g., `- (IBAction)buttonClicked:(id)sender`. In Interface Builder, bind the NSCollectionView content to an array of those objects, and bind the button's target to CollectionViewItem > representedObject > buttonClicked:. – spinacher Dec 06 '16 at 17:56
0

As per this "//image clicked, 0" i think you are getting 0 for each and every button click,am i correct?

If so, you can have a outlet to the button in collectioViewItem and overide -(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil to set/increment the tag of each instance of the button.

Suhas Aithal
  • 842
  • 8
  • 20
-1

use this in cellForItemAtIndexPath method

   [[cell myButton] addTarget:self action:@selector(myClickEvent:event:) forControlEvents:UIControlEventTouchUpInside];


   -(IBAction)myClickEvent:(id)sender event:(id)event {

          NSSet *touches = [event allTouches];

          UITouch *touch = [touches anyObject];

          CGPoint currentTouchPosition = [touch locationInView:_myCollectionArray];

          NSIndexPath *indexPath = [_myCollectionArray indexPathForItemAtPoint: currentTouchPosition];

   }
SAMIR RATHOD
  • 3,512
  • 1
  • 20
  • 45