Question

I have set up an NSCollectionView in a cocoa application. I have subclassed the collection view's NSCollectionViewItem to send me a custom NSNotification when one of its views it selected / deselected. I register to receive a notification within my controller object when this notification is posted. Within this method I tell the view that has just been selected that it is selected and tell it to redraw, which makes it shade itself grey.

The NSCollectionViewItem Subclass:

-(void)setSelected:(BOOL)flag {
[super setSelected:flag];

[[NSNotificationCenter defaultCenter] postNotificationName:@"ASCollectionViewItemSetSelected" 
                                                    object:nil 
                                                  userInfo:[NSDictionary dictionaryWithObjectsAndKeys:(ASListView *)self.view, @"view", 
                                                            [NSNumber numberWithBool:flag], @"flag", nil]];}

The Controller Class (in the -(void)awakeFromNib Method):

//Register for selection changed notification
[[NSNotificationCenter defaultCenter] addObserver:self 
                                         selector:@selector(selectionChanged:) 
                                             name:@"ASCollectionViewItemSetSelected" 
                                           object:nil];

And the -(void)selectionChanged:(NSNotification *)notification method:

- (void)selectionChanged:(NSNotification *)notification {
// * * Must get the selected item and set its properties accordingly

//Get the flag
NSNumber *flagNumber = [notification.userInfo objectForKey:@"flag"];
BOOL flag = flagNumber.boolValue;

//Get the view
ASListView *listView = [notification.userInfo objectForKey:@"view"];

//Set the view's selected property
[listView setIsSelected:flag];
[listView setNeedsDisplay:YES];

//Log for testing
NSLog(@"SelectionChanged to: %d on view: %@", flag, listView);}

The application that contains this code requires there to be no empty selection within the collection view at any time. This is where i get my problem. I've tried checking when a view's selection is changed and reselecting it if there is no selection, and manually selecting the views using NSCollectionView's

-(void)setSelectionIndexes:(NSIndexSet *)indexes

But there is always a situation which occurs that causes there to be an empty selection in the collection view.

So I was wondering if there is an easier way to prevent an empty selection occurring in an NSCollectionView? I see no checkbox in interface builder.

Thanks in advance!

Ben

Update

I ended up just subclassing my NSCollectionView, and overriding the - (void)mouseDown:(NSEvent *)theEvent method. I only then sent the method [super mouseDown:theEvent]; if the click was in one of the subviews. Code:

- (void)mouseDown:(NSEvent *)theEvent {
NSPoint clickPoint = [self convertPoint:theEvent.locationInWindow fromView:nil];

int i = 0;
for (NSView *view in self.subviews) {
    if (NSPointInRect(clickPoint, view.frame)) {
        //Click is in rect
        i = 1;
    }
}

//The click wasnt in any of the rects
if (i != 0) {
    [super mouseDown:theEvent];
}}
Was it helpful?

Solution

I ended up just subclassing my NSCollectionView, and overriding the - (void)mouseDown:(NSEvent *)theEvent method. I only then sent the method [super mouseDown:theEvent]; if the click was in one of the subviews. Code:

- (void)mouseDown:(NSEvent *)theEvent {
NSPoint clickPoint = [self convertPoint:theEvent.locationInWindow fromView:nil];

int i = 0;
for (NSView *view in self.subviews) {
    if (NSPointInRect(clickPoint, view.frame)) {
        //Click is in rect
        i = 1;
    }
}

//The click wasnt in any of the rects
if (i != 0) {
    [super mouseDown:theEvent];
}}

OTHER TIPS

I also wanted to avoid empty selection in my collection view.
The way I did it is also by subclassing, but I overrode -hitTest: instead of -mouseDown: to return nil in case the click wasn't on an item :

-(NSView *)hitTest:(NSPoint)aPoint {
    // convert aPoint in self coordinate system
    NSPoint localPoint = [self convertPoint:aPoint fromView:[self superview]];
    // get the item count
    NSUInteger itemCount = [[self content] count];

    for(NSUInteger itemIndex = 0; itemIndex < itemCount; itemIndex += 1) {
        // test the point in each item frame
        NSRect itemFrame = [self frameForItemAtIndex:itemIndex];
        if(NSPointInRect(localPoint, itemFrame)) {
            return [[self itemAtIndex:itemIndex] view];
        }
    }

    // not on an item
    return nil;
}

Although I'm late to this thread, I thought I'd just chime in because I've had the same problem recently. I got around it using the following line of code:

[_collectionView setValue:@NO forKey:@"avoidsEmptySelection"];

There is one caveat: the avoidsEmptySelection property is not part of the official API although I think that it's pretty safe to assume that its the type of property that will stick around for a while.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top