Как создать действие из выбора строки из NSTableView

Когда я выбираю строку из NSTableView, она не запускает код из метода tableViewSelectionDidChange. Я поставил точки останова в этом методе, и он даже не входит в метод.

Любые идеи? Я что-то упустил в своем инициализаторе?

PersonController.h

#import <Foundation/Foundation.h>

@interface Person : NSObject {
  IBOutlet NSTableView *personsTable;
  NSMutableArray *personsList;
  NSMutableArray *personCollection;

  IBOutlet NSTextField *selectedPersonName;
  IBOutlet NSTextField *selectedPersonGender;
@private

}

- (void)tableViewSelectionDidChange:(NSNotification *)aNotification;

@end

PersonController.m

#import "PersonController.h"
#import "Person.h"


@implementation PersonController

- (id)init
{
    self = [super init];
    if (self) {
        personsList = [[NSMutableArray alloc] init];
        Person *person = [[Person alloc] init];

        // Create person 1
        person.name = @"Bob";
        person.gender = @"male";

        // Append to array
        [personsList addObject:person];
        [person release];

        // Create person 2
        person = [[Person alloc] init];
        person.name = @"Fred";
        person.gender = @"Unknown";

        // Append to array
        [personsList addObject:person];
        [person release];

        [personsTable reloadData];
    }

    return self;
}

- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
    return [personsList count];
}

- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
    Person *person = [personsList objectAtIndex:row];
    NSString *identifier = [tableColumn identifier];

    return [person valueForKey:identifier];
}

- (void)tableViewSelectionDidChange:(NSNotification *)aNotification
{
    NSInteger selectedRow = [personsTable selectedRow];
    if (selectedRow == -1)
    {
        // these should be localized, but use string constants here for clarity
        [selectedPersonName setStringValue:@"No selection"];
        [selectedPersonGender setStringValue:@"No selection"];
    }
    else
    {
        Person *selectedPerson = [personCollection objectAtIndex:selectedRow];

        [selectedPersonName setStringValue:[selectedPerson name]];
        [selectedPersonGender setStringValue:[selectedPerson gender]];
    }
}

- (void)dealloc
{
    [super dealloc];
}

@end

Ответы

Ответ 1

Итак, проблема заключалась в том, что я пытался использовать tableViewSelectionChange для запуска события, когда была нажата строка в NSTableColumn. Поскольку я не мог получить эту работу, я сделал другой подход, который должен был создать IBAction и связать это с NSTableView, и я нашел, что это хорошо работает.

Чтобы сделать это, я сделал следующее:

  • Удалить - (void)tableViewSelectionDidChange
  • Создать IBAction
  • В XIB файле создайте ссылку Received Actions между IBAction и NSTableView, в инспекторе соединений NSTableView в разделе "отправленное действие" есть действие "селектора" "подключите этот" селектор "к этому IBAction, который вы хотите вызвать.

Это IBAction в PersonController.m

- (IBAction)columnChangeSelected:(id)sender
{
    NSInteger selectedRow = [personsTable selectedRow];

    if (selectedRow != -1) {
        NSLog(@"Do something with selectedRow!");
    }
    else {
        // No row was selected
    }
}

Ответ 2

Убедитесь, что экземпляр PersonController подключен к personTable как делегат. Я не знаю, как вы создали NSTableView, но если вы используете Nibs, вы можете установить делегат в Interface Builder. Если нет, вы можете добавить [personsTable setDelgate:self] в метод init и [personsTable setDelegate:nil] в методе dealloc.

Кроме того, вы утечка peopleList. Добавьте [personsList release] к вашему методу делегата.

Ответ 3

Для других, кто сталкивается с этой проблемой: другая причина, по которой этот делегат не вызывается, может быть вызвана тем, что строка уже выбрана. Поэтому он не будет уведомлять, если не будет сделан новый выбор. Если вы все еще хотите получать уведомления при каждом нажатии, отмените выбор всех строк после получения уведомления.

Теперь это сделает 2 обращения к вашему делегату, один для получения выбранного и другого для получения отмены. Второй вызов не нужен, поэтому добавьте условие сверху, чтобы проверить [tableView selectedRow], это вернет -1, когда не будут выбраны строки.

Ответ 4

Чтобы расширить ответ Coderama, эквивалент в коде:

tableView.target = self;
tableView.action = @selector(tableViewClicked:);

затем реализовать метод в том же классе:

- (void)tableViewClicked:(id)sender {
    // This will return -1 if the click did not land on a row
    NSLog(@"tableView.clickedRow = %ld", tableView.clickedRow);

    // This will return -1 if there is no row selected.
    NSLog(@"tableView.selectedRow = %ld", tableView.selectedRow);
}

В представлении таблицы будет вызываться его метод действия для цели, которую вы устанавливаете каждый раз при нажатии на просмотр. Это позволит вам знать каждый раз, когда выбирается строка, даже если она уже выбрана.

Ответ 5

Решение в Swift 3 для большинства событий:

Внутри контроллера просмотра табличного представления:

override func viewDidLoad() {
    super.viewDidLoad()

    tableView.target = self
    tableView.action = #selector(tableViewDidClick)
}

func tableViewDidClick(){
    let row = tableView.clickedRow
    let column = tableView.clickedColumn
    let unselected = -1

    if row == unselected && column == unselected{
        tableViewDidDeselectRow()
        return
    }else if row != unselected && column != unselected{
        tableViewDidSelectRow(row)
        return
    }else if column != unselected && row == unselected{
        tableviewDidSelectHeader(column)
    }
}

private func tableViewDidDeselectRow() {
    // clicked outside row
}

private func tableViewDidSelectRow(_ row : Int){
    // row did select
}

private func tableviewDidSelectHeader(_ column : Int){
    // header did select
}