Получить объект документа с текущим фокусом из NSCollectionView

У меня есть открытый NSCollectionView (подкласс), содержащий несколько текстовых представлений. Каждое из текстовых представлений сопоставляется с (подклассом) объектом NSDocument. (Идея состоит в том, чтобы использовать функции сохранения архитектуры документа, но не ее оконные функции, потому что мне нужно несколько документов в одном окне, а традиционная архитектура документа этого не позволяет.)

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


person Displaced Hoser    schedule 04.08.2016    source источник


Ответы (1)


Это то, что цепочка ответчиков предназначена для.

Поскольку вы используете NSCollectionView, у вас, вероятно, уже есть подкласс NSCollectionViewItem. Если нет, создайте его. Реализуйте свой метод действия в этом подклассе. Пример:

class DocumentItem: NSCollectionViewItem {

    var document: MyDocument? {
        return representedObject as? MyDocument
    }

    @IBAction func doThatThing(sender: AnyObject?) {
        Swift.print("This is where I do that thing to \(document)")
    }

    // @IBOutlets and whatnot here...

}

Возможно, вам придется установить это как пользовательский класс вашего NSCollectionViewItem в вашем xib или раскадровке.

Затем, если представление вашей ячейки (представление, принадлежащее вашему NSCollectionViewItem) еще не является настраиваемым подклассом NSView, вы должны сделать его настраиваемым подклассом. Вы должны переопределить acceptsFirstResponder, чтобы вернуть true:

class DocumentCellView: NSView {

    override var acceptsFirstResponder: Bool { return true }

    // @IBOutlets and whatnot here...

}

Убедитесь, что вы установили это как настраиваемый класс вашего представления ячейки в раскадровке или xib.

Наконец, свяжите действие вашего пункта меню с doThatThing: в программе быстрого реагирования:

элемент меню подключения к первому ответчику

Вот как это работает:

Поскольку представление ячеек теперь возвращает true для acceptsFirstResponder, когда пользователь щелкает представление ячеек в представлении коллекции, система делает его первым ответчиком (начало цепочки ответчиков).

Когда представление имеет контроллер представления, оно делает этот контроллер представления следующим респондентом после себя в цепочке респондентов (если вы используете OS X 10.10 Yosemite или более позднюю версию). В представлении вашей ячейки есть контроллер представления: объект элемента, который вы возвращаете из outlineView:itemForRepresentedObjectAtIndexPath:. (NSCollectionViewItem является подклассом NSViewController, поэтому ваш пользовательский элемент является контроллером представления.)

Когда пользователь щелкает пункт меню, пункт меню просит NSApplication отправить свое действие по цепочке респондентов, начиная с первого респондента. Первым респондентом является представление ячейки, но оно не отвечает на сообщение doThatThing:. Итак, NSApplication запрашивает у представления свой nextResponder, который является экземпляром вашего подкласса NSCollectionViewItem. Этот объект действительно отвечает на doThatThing:, поэтому NSApplication отправляет doThatThing: вашему объекту элемента (с объектом NSMenuItem в качестве аргумента sender) и не проверяет остальную часть цепочки респондента.

person rob mayoff    schedule 05.08.2016
comment
Великолепно! Отличная работа! В моем случае ответ был еще проще. NSTextViews уже были настроены для приема первого ответчика, поэтому мне не нужно было создавать их подклассы. Мне просто нужно было создать @IBAction в моем подклассе CollectionViewItem и подключить к нему пункт меню в First Responder. Но сам бы я до этого не додумался. Основные реквизиты не только для того, чтобы найти простой ответ, который хорошо сработал для меня, но и для публикации более сложного варианта, который принесет пользу будущим читателям этого вопроса. - person Displaced Hoser; 06.08.2016