如何通过从NSTableView中选择行来创建操作

时间:2012-02-04 08:19:11

标签: objective-c cocoa 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

5 个答案:

答案 0 :(得分:27)

所以这里的问题是当我点击NSTableColumn中的一行时,我试图使用tableViewSelectionChange来触发事件。由于我无法完成这项工作,我采取了另一种方法,即创建一个IBAction并将其链接到NSTableView,我发现这很好用。

为了做到这一点,我做了以下几点:

  1. 删除- (void)tableViewSelectionDidChange
  2. 创建IBAction
  3. 在XIB文件中,在IBAction和NSTableView之间创建Received Actions链接,在“发送操作”下的NSTableView连接检查器中,将“选择器”操作“连接此”选择器“与要触发的IBAction”
  4. 这是PersonController.m中的IBAction

    - (IBAction)columnChangeSelected:(id)sender
    {
        NSInteger selectedRow = [personsTable selectedRow];
    
        if (selectedRow != -1) {
            NSLog(@"Do something with selectedRow!");
        }
        else {
            // No row was selected
        }
    }
    

答案 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);
}

每次单击视图时,表视图将在您设置的目标上调用其action方法。这将允许您在每次选择行时都知道,即​​使它已被选中。

答案 2 :(得分:2)

确保PersonController的实例作为委托连接到personsTable。我不知道你是如何创建NSTableView的,但如果你正在使用Nib,你可以在Interface Builder中设置委托。如果没有,您可以在 init 方法中添加[personsTable setDelgate:self],在 dealloc 方法中添加[personsTable setDelegate:nil]

此外,您泄漏 personsList。将[personsList release]添加到您的委托方法。

答案 3 :(得分:2)

对于遇到此问题的其他人:未调用此委托的其他原因可能是因为该行已被选中。所以除非做出新的选择,否则它不会通知。如果您仍希望能够在每次点击时收到通知,请在收到通知后取消选择所有行。

现在,这将对您的委托进行2次调用,一次用于选择,另一次用于取消选择。不需要第二次调用,因此在顶部添加条件以检查[tableView selectedRow]当没有选择行时,这将返回-1

答案 4 :(得分:1)

大多数活动的Swift 3解决方案:

在tableview视图控制器中:

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
}