Пользовательские ячейки в NSTableView - PullRequest
1 голос
/ 13 января 2012

Какой лучший способ заполнить NSTableView пользовательскими ячейками?

Я всегда использую привязки какао при заполнении стандартных данных и всегда использую источники данных при заполнении таблиц с пользовательскими ячейками. Что мне интересно, так это то, что есть способ смешать две концепции для оптимального дизайна.

Использование Xcode 3 (и, следовательно, IBPlugins), к сожалению, не вариант.

1 Ответ

3 голосов
/ 14 января 2012

Лично я бы не стал смешивать связанные данные и источники данных. Я сталкивался только с болью, пытаясь это сделать. У меня есть пара подходов, которые могут вам помочь.

Одна вещь, которую я смог сделать, это установить пользовательский класс ячеек в IB, который является подклассом одной из ячеек, о которых знает IB, и затем переопределить все, что вам нужно для того, чтобы сделать делай что хочешь. Но сначала немного предыстории, а некоторые пропущенные попытки:

При связывании NSTableView на основе ячеек вы обычно устанавливаете привязки к самому столбцу, а не к ячейке внутри столбца. Если вы используете пользовательский подкласс NSCell в столбце таблицы, вы заметите, что привязки, такие как value, больше не доступны в столбце, в отличие от того, когда ячейка представляет собой NSTextFieldCell. Я попытался разобраться с трюком IB, задав для него привязку value, настроенную как NSTextFieldCell, а затем отключив ячейку - привязка по-прежнему отображается в инспекторе привязок, но всегда вылетает во время выполнения с этой ошибкой: [<NSTableColumn 0x10252e910> valueForUndefinedKey:]: this class is not key value coding-compliant for the key value.

Это подводит меня к подходу разделения на подклассы одной из ячеек, с которыми IB знает, как связываться. Я создал подкласс NSTextFieldCell, развернул его до «Ячейка текстового поля - текстовая ячейка» в столбце таблицы, а затем установил свой пользовательский подкласс в Инспекторе удостоверений. Я был в состоянии подтвердить, что привязки все еще работали, и IB все еще рассматривает это как NSTextFieldCell. Оттуда я мог переопределить любые методы, которые я хотел в своем пользовательском классе ячеек, и получить пользовательское поведение. У меня нет оснований полагать, что вы не могли бы сделать это и с клетками изображений. Естественно, это довольно неестественный подход, но в зависимости от того, насколько «кастомными» являются ваши пользовательские ячейки, он может не справиться с написанием множества пользовательских кодов для подключения источника данных.

В ходе дальнейших экспериментов я обнаружил, что это «проблема IB», а не проблема NSTableView / привязок. И есть еще один хороший способ обойти это.

Скажем, вы хотите использовать пользовательскую ячейку и хотите привязать ее к какому-либо произвольному объекту модели. У вас есть привязка NSTableColumn Value, привязанная к NSArrayController, который передает список объектов пользовательской модели, каждый со свойством, называем его dataForCustomCell, который возвращает все, что нужно для пользовательской ячейки, чтобы выполнить свою задачу. Вы должны установить столбец TextFieldCell (как по умолчанию в IB), затем привязать привязку value NSTableColumn к контроллеру массива> arrangedObjects и ввести путь к ключу модели dataForCustomCell. На данный момент, если предположить, что объект, возвращаемый dataForCustomCell, реализует NSCopying (если это не произойдет, ваше приложение будет аварийно завершено, но это не очень актуально прямо сейчас), что вы увидите, если запустите свое приложение, так это то, что NSTextFieldCell вызовет - (NSString*)description на объекте, возвращаемом dataForCustomCell и поместите этот текст в ячейку.

Теперь самое интересное: во время -awakeFromNib в вашем собственном объекте (NSView, NSViewController и т. Д. И т. Д.) Замените dataCell (и headerCell, если хотите), например, так:

- (void)awakeFromNib
{
    [super awakeFromNib];
    // Assuming you've got your NSTableView plugged into an IBOutlet property called table
    NSTableColumn* col = [[self.table tableColumns] objectAtIndex:0];
    col.dataCell = [[[MYCustomCell alloc] init] autorelease];
}

Поскольку привязки находятся в NSTableColumn, а не в самой ячейке, вы можете поменять ячейку, не беспокоясь о повторной привязке каких-либо привязок. В своем пользовательском классе ячеек переопределите -(void)setObjectValue:, и вы получите вызов от механизма привязок во время выполнения, нажав объект, полученный из свойства dataForCustomCell объекта модели, соответствующего текущей строке рисования Таблица. (Вы также получите вызов, передаваемый в ноль для каждой ячейки, но кажется безопасным игнорировать это или просто передать его супер.)

Одним из недостатков этого подхода является то, что вы получаете только одну привязку «Значение», которую имеет NSTextFieldCell. Обходной путь для этого заключается в том, чтобы связать привязку этого значения с большей / более высокой «гранулой» в вашей модели, а затем развернуть и развернуть несколько значений в вашей реализации -setObjectValue:, если необходимо.

Это не идеально, но это исправление «пара строк кода» вместо исправления «миллиард строк кода».

В качестве альтернативы, если вы нацеливаетесь на довольно свежие версии MacOS, вы также можете работать с NSTableView на основе представлений.Они довольно хороши и обрабатывают привязки гораздо более разумным способом, чем таблицы на основе NSCell.Это совершенно другой способ, поэтому трудно сказать, как ваша задача будет соответствовать этому.* * * * * * * * * * * * * * * *

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} * [*] * * *]} * * * * * * * * * * * * * * * * * * * * * * 10 *
...