Как я могу сделать кнопку внутри NSTableViewRow реагировать на представленный объект
Я уже давно борюсь с этой проблемой. Я работаю над модулем диспетчера копирования файлов, и пока мне удалось заставить все работать идеально, за исключением кнопки отмены. По какой-то причине, когда я нажимаю кнопку отмены для определенной строки, действие кнопки предназначается для нескольких строк одновременно.
После нескольких дней исследования проблемы я смог заставить объект отменить операцию, представленную строкой, успешно используя:
-(IBAction)btnCancelOperationClick:(id)sender {
NSInteger row = [_tableView rowForView:sender];
if (row != -1) {
FileCopyOperation *opr = [_fileCopyOperations objectAtIndex:row];
[opr cancel];
[_fileCopyOperations removeObjectAtIndex:row];
[_tableView removeRowsAtIndexes:[NSIndexSet indexSetWithIndex:row] withAnimation:NSTableViewAnimationEffectFade];
}
}
Это хорошо работает, я могу отменить операцию и соответственно обновить свою таблицу. Все остальное работает как задумано, но должно быть что-то не так с моим кодом или привязками. Я загружаю эту ячейку из кончика, затем я регистрирую этот кончик, используя:
[_tableView registerNib:[[NSNib alloc]initWithNibNamed:@"FileCopyCell" bundle:nil] forIdentifier:@"FileCopyCell"];
Я сделал QueueController владельцем файла и подключил все так:
Я был бы очень признателен, если бы кто-то мог указать мне правильное направление, чтобы эта штука работала правильно Заранее спасибо!
Изменить, чтобы добавить больше образца кода.
-(NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
FileCopyCell *cell = [tableView makeViewWithIdentifier:@"FileCopyCell" owner:self];
FileCopyOperation *opr = [_fileCopyOperations objectAtIndex:row];
[cell.fileName setStringValue:[NSString stringWithFormat:@"Copying \"%@\"",opr.fName]];
[cell.progressBar setDoubleValue:((opr.bWritten.doubleValue / opr.fSize.doubleValue) * 100)];
[cell.totalBytes setStringValue:[NSString stringWithFormat:@"of %@",[NSByteCountFormatter stringFromByteCount:opr.fSize.longLongValue countStyle:NSByteCountFormatterCountStyleFile]]];
[cell.status setStringValue:[NSString stringWithFormat:@"%@",[NSByteCountFormatter stringFromByteCount:opr.bWritten.longLongValue countStyle:NSByteCountFormatterCountStyleFile]]];
[cell.icon setImage:[[NSWorkspace sharedWorkspace]iconForFile:opr.srcURL.path]];
[cell.cancelButton setTarget:self];
return cell;
}
-(void)windowDidLoad {
[super windowDidLoad];
_fileCopyOperations = [NSMutableArray new];
windowFrame = [self.window frame];
rows = 0;
[_tableView registerNib:[[NSNib alloc]initWithNibNamed:@"FileCopyCell" bundle:nil] forIdentifier:@"FileCopyCell"];
if (!fileCopyManager) {
fileCopyManager = [FileCopyManager sharedFileCopyManager];
[fileCopyManager.fileCopyQueue addObserver:self forKeyPath:@"operationCount" options:NSKeyValueObservingOptionNew context:(void*)fileCopyManager];
}
[_scrollView setHasHorizontalScroller:NO];
[_scrollView setHasVerticalScroller:NO];
}
2 ответа
Лучший подход состоит в том, чтобы подкласс NSTableCellView
и пусть он обрабатывает свои собственные действия и представленный объект. Например, ячейка, представляющая Foo
Экземпляр может иметь два свойства: foo
а также fooController
, Когда (nonatomic
) foo
сеттер вызывается, ячейка может обновить свой собственный интерфейс для представления переданного Foo
, Когда Foo
Контроллер создает ячейку таблицы, он может создавать FooCell
экземпляр, установите себя как fooController
и назначить Foo
экземпляр и пусть клетка обрабатывает сама. Целью кнопки отмены может быть ее собственная ячейка, и когда -cancel:
действие называется, оно может сказать fooController
что делать (так как Foo
контроллер отвечает за обновление очереди и табличного представления) и так как он имеет ссылку на его foo
, это может передать это контроллеру через некоторые -cancelFoo:(Foo *)theFoo
метод, не полагающийся на контроллер для поиска его индекса (который может быть неточным, если вы анимируете появление и исчезновение строк или пользователь быстро отменяет связку в ряду, но их удаление задерживается и обновляется асинхронно).
Красиво и чисто. Аккуратное и организованное сдерживание / разделение обязанностей. Ячейка обрабатывает свое собственное обновление пользовательского интерфейса и действия и знает свой собственный foo; Контроллер foo управляет своей коллекцией foo, ее табличным представлением и назначением foos для ячеек foo.
Благодаря Джошуа Ноцци, следуя его рекомендации, я перенес действие кнопки с контроллера на класс ячеек. В классе я использовал нижеприведенный метод для доступа к представленному объекту и отправки [operation cancel]
сообщение.
-(IBAction)cancelOpr:(id)sender {
NSButton *button = (NSButton*)sender;
FileCopyOperation *opr = [(NSTableCellView*)[button superview]objectValue];
[opr cancel];
// This code calls the controller [removeObject:] method that takes care of cleaning everything out and updates the GUI accordingly.
AppDelegate *ad = (AppDelegate*)[[NSApplication sharedApplication]delegate];
QueueWindowController *qc = [ad getQueueController];
[qc.fileCopyOperations performSelectorOnMainThread:@selector(removeObject:) withObject:opr waitUntilDone:YES];
}
Вы можете получить полный проект здесь.