2013-08-29 2 views
1

NSArrayController의 arrangedObjects의 다양한 keyPaths에 바인딩 된 열과 NSArrayController가 사전 배열에 바인딩 된 NSTableView의 기본 설정이 있습니다.확인란을 사용하여 NSTableView에서 선택 관리

이 설정을 사용하면 tableview에서 하나 이상의 행을 선택하면 자동으로 작동합니다. 테이블 뷰와 배열 컨트롤러가 함께 작동하며 NSArrayController를 쿼리하여 선택한 객체의 목록을 쉽게 얻을 수 있습니다.

내 테이블 열 중 하나에 체크 박스 종류 인 NSButtonCells가 있습니다. 코코아 바인딩을 사용하여 각 행의 체크 박스를 해당 행의 선택 상태에 바인딩하는 방법이 있습니까? 각 행을 나타내는 NSDictionary에 다른 값을 추가 할 수는 있지만 NSArrayController에서 이미 사용할 수있는 선택 정보가 중복된다는 것을 알고 있습니다.

필요한 경우 구현의 빠른 스케치에 감사드립니다.

감사

답변

1

그래서, 이에 대한 대답은 심장 약한되지 않습니다. 그 이유는 NSTableView가 자연스럽게 원하지 않는 일을하기 위해서입니다.

코코아의 기본 NSTableView는 여러 선택 동작 이용하여 시작 를 - 행을 클릭하면 그것을 선택하고 다른 행 이 선택 해제 - 제어를 들고와 열을 클릭 만

이제 행의 선택 상태를 전환, 체크 박스 열을 추가하십시오. 이 행에 대한 규칙은 다릅니다 : - 확인란을 클릭하면 해당 행의 선택 상태가 토글됩니다

클릭 수를 캡처하여 직접 처리 할 수 ​​있다면 간단합니다. 이제는 문제를 해결할 수 있지만 문제는 NSTableView로 계속 전달되어 일반적인 방법으로 선택을 변경한다는 것입니다. [참고 :이 전달을 피할 수있는 방법이있을 수 있습니다. 알고 계시면 알려주세요.]

다음과 같이 수행 할 수 있습니다. - 각 개체에 'selectedInView'입력란 추가 기본 객체 배열에 있습니다. keyPath : "selectedObjects"에 대한 옵서버를 연관된 NSArrayController에 추가합니다. 선택 영역이 변경되면 각 객체에 대해 selectedInView 필드를 설정합니다. 이런 식으로 뭔가 : 이미 선택이 존재 때 체크 박스 오작동이 유일한 시간 :

if([keyPath isEqualToString:@"selectedObjects"]) { 
// For table view checkbox's: keep "selectedInView" of song dictionaries up to date 
[_arrayController.arrangedObjects enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 
    BOOL sel = [_arrayController.selectedObjects containsObject:obj]; 
    if([[obj objectForKey:@"selectedInView"] boolValue] != sel)[obj setValue:[NSNumber numberWithBool:sel] forKey:@"selectedInView"]; 
}]; 

이제 까다로운 부분이 온다. 다음은 사례 유형입니다.

설정 : 행의 1,2,3가 선택됩니다. 확인란 4 행을 클릭했습니다. 결과 : 네 번째 행의 확인란이 선택되었습니다. 네 번째 행이 선택됩니다. 행의 1,2,3 선택을 취소합니다 (NSTableView가 자연스럽게 수행하기 때문에)

이 문제를 해결하려면 확인란을 클릭 할 때마다 현재 선택 항목을 기억하기 위해 임시 배열을 생성해야합니다. 클릭 다음의 tableview 그것의 선택 처리를 수행하고있다

- (void)tableView:(NSTableView *)tableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row { 
    if([tableColumn.identifier isEqualToString:@"CheckBox"]) { 
    NSMutableDictionary *song = [_arrayController.arrangedObjects objectAtIndex:row]; 
    if(!_tempSelectedSongs && _arrayController.selectedObjects) _tempSelectedSongs = [[NSMutableArray arrayWithArray:_arrayController.selectedObjects] retain]; 
    if(_tempSelectedSongs) { 
     if([_tempSelectedSongs containsObject:song]) { 
     [_tempSelectedSongs removeObject:song]; 
     } else if(![_tempSelectedSongs containsObject:song]) { 
     [_tempSelectedSongs addObject:song]; 
     } 
    } 
    } 
} 

이제 한 후, 우리는 그것이 있어야 무엇을 선택을 설정합니다. 실제로 선택을 수행하기 전에 테이블 뷰 선택을 수정할 수있는 유망한보고 기능이 있습니다.당신과 같이 수정할 수 있습니다 : 이것은 위대한 작품을

- (NSIndexSet *)tableView:(NSTableView *)tableView selectionIndexesForProposedSelection:(NSIndexSet *)proposedSelectionIndexes { 
    NSMutableIndexSet *newSet = [NSMutableIndexSet indexSet]; 
    if(_tempSelectedSongs) { 
    NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet]; 
    [_tempSelectedSongs enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 
     NSUInteger index = [_arrayController.arrangedObjects indexOfObject:obj]; 
     if(index != NSNotFound) [indexSet addIndex:index]; 
    }]; 
    proposedSelectionIndexes = indexSet; 
    [_tempSelectedSongs release]; _tempSelectedSongs = nil; [_tempSelectedSongsTimer invalidate]; [_tempSelectedSongsTimer release]; _tempSelectedSongsTimer = nil; 
    } 
    [proposedSelectionIndexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) { 
    NSProgressIndicator *progress = ((BDDiscreteProgressCell *)[[_arrayController.arrangedObjects objectAtIndex:idx] objectForKey:@"BDCell"]).progress; 
    if(!progress) 
     [newSet addIndex:idx]; 
    }]; 
    return newSet; 
} 

, 그러나 NSTableView는 위임 함수가 호출되는 순서에 문제가있는 것입니다. 분명히 우리는 첫 번째 함수, 즉 임시 배열을 설정하는 두 번째 함수를 두 번째 함수보다 먼저 호출해야합니다. 여기서 우리는 정보를 사용합니다.

어떤 이유로 든 체크 박스를 DE- 선택하면 이것이 작동하는 방식이며 이지만 확인란을 선택하면 반대가 발생합니다.

if([keyPath isEqualToString:@"selectedObjects"]) { 
    if(_tempSelectedSongs) { 
    _arrayController.selectedObjects = _tempSelectedSongs; 
    [_tempSelectedSongs release]; _tempSelectedSongs = nil; 
    } 
    // For table view checkbox's: keep "selectedInView" of song dictionaries up to date 
    [_arrayController.arrangedObjects enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 
    BOOL sel = [_arrayController.selectedObjects containsObject:obj]; 
    if([[obj objectForKey:@"selectedInView"] boolValue] != sel)[obj setValue:[NSNumber numberWithBool:sel] forKey:@"selectedInView"]; 
    }]; 
} 

편집 :이 경우에 그래서, 당신은 당신의 위의 키 패스의 관찰자에게 좀 더 많은 코드를 추가 할 수 있습니다 추가하는 경우가 밝혀 : 하나의 행이 선택되는 경우는 체크 박스가 있어요 "클릭되지 않은,"이 수행 자동으로 selectedObjects 알림을 트리거하지 않으므로 새 선택을 구현하기 위해 타이머에서 함수를 실행해야합니다.

관련 문제