Потребитель QuickLook в качестве делегата от NSViewController
У меня возникли проблемы с реализацией QuickLook
функциональность из таблицы в NSView
, Ограниченная документация по QuickLook
действительно не помогает вообще.
Прочитав Apple Docs (которые в значительной степени ориентированы на собственные генераторы и плагины), я остановился на примере кода QuickLookDownloader. Этот код основан на приложении, основанном на документе, но мне кажется, что это правильный метод (в конце концов, это код Apple, и он работает в их проекте).
В моей реализации я могу получить QuickLook panel
показывать просто отлично, и я могу просто так отмахнуться. Однако сама панель никогда не вызывает методы делегата из моего NSViewController
, В результате я даже не дошел до отображения объектов, а только с формулировкой "Нет выбранных элементов". И я в тупике.
Я пытался позвонить setDelegate
, но будьте предупреждены о надвигающейся гибели, если я продолжу идти по этому маршруту...
[QL] QLError (): - [QLPreviewPanel setDelegate:] вызывается, когда на панели нет контроллера - Исправьте это, или это скоро повысится. Смотрите комментарии в QLPreviewPanel.h для -acceptsPreviewPanelControl:/-beginPreviewPanelControl:/-endPreviewPanelControl:.
И затем в любом случае происходит doom с dealloc при попытке ответить на один из методов делегата.
И да, я прочитал заголовок, который подтверждает, что я должен установить делегата после того, как выиграл панель (см. Код ниже).
Итак, вот мой код, который в значительной степени соответствует примеру кода, за исключением: а) откуда я получаю свои данные (я получаю их из NSArrayController
) и б) откуда я получаю свой элемент предварительного просмотра (мой приходит прямо из моего модельного объекта - или должен в любом случае)
@interface MyViewController : NSViewController
<QLPreviewPanelDataSource, QLPreviewPanelDelegate> {
QLPreviewPanel * previewPanel;
NSArrayController * myArrayController;
NSTableView * myTable;
// [...] Other instance vars
}
@implementation MyViewController
// [...] all the other methods, init, dealloc etc...
-(IBAction)togglePreviewPanel:(id)previewPanel {
if ([QLPreviewPanel sharedPreviewPanelExists] &&
[[QLPreviewPanel sharedPreviewPanel] isVisible])
{
[[QLPreviewPanel sharedPreviewPanel] orderOut:nil];
}
else
{
[[QLPreviewPanel sharedPreviewPanel] makeKeyAndOrderFront:nil];
}
}
-(BOOL)acceptsPreviewPanelControl:(QLPreviewPanel *)panel
{
return YES;
}
// This document is now responsible of the preview panel.
// It is allowed to set the delegate, data source and refresh panel.
-(void)beginPreviewPanelControl:(QLPreviewPanel *)panel
{
if (DEBUG) NSLog(@"QuickLook panel control did BEGIN");
previewPanel = [panel retain];
panel.delegate = self;
panel.dataSource = self;
}
// This document loses its responsisibility on the preview panel.
// Until the next call to -beginPreviewPanelControl: it must not change
// the panel's delegate, data source or refresh it.
-(void)endPreviewPanelControl:(QLPreviewPanel *)panel
{
[previewPanel release];
previewPanel = nil;
if (DEBUG) NSLog(@"QuickLook panel control did END");
}
// Quick Look panel data source
-(NSInteger)numberOfPreviewItemsInPreviewPanel:(QLPreviewPanel *)panel
{
if (DEBUG) NSLog(@"QuickLook preview count called");
return [[myArrayController selectedObjects] count];
}
-(id <QLPreviewItem>)previewPanel:(QLPreviewPanel *)panel
previewItemAtIndex:(NSInteger)index
{
if (DEBUG) NSLog(@"QuickLook preview selection of item called");
return [[displayAC selectedObjects] objectAtIndex:index];
}
-(BOOL)previewPanel:(QLPreviewPanel *)panel handleEvent:(NSEvent *)event {
if (DEBUG) NSLog(@"QuickLook panel error handler called");
// redirect all key down events to the table view
if ([event type] == NSKeyDown) {
[myTable keyDown:event];
return YES;
}
return NO;
}
Проблема в том, что acceptsPreviewPanelControl
никогда не вызывается, поэтому делегаты никогда не привыкнут (они определенно никогда не будут вызваны).
Я уверен, что это простой шаг, который я пропускаю, но после разбора примера кода и просмотра документов я не вижу ответа.
Это потому, что это все изнутри NSViewController (хотя я не вижу причин, почему это должно войти в уравнение)?
Любая помощь очень ценится.
РЕШЕНИЕ ОБНОВЛЕНИЕ
Благодаря наблюдению Питера, решение было быстрым. Разве вы не ненавидите, когда сообщение об ошибке в отладчике означает, что оно говорит?:-)
В моем классе, который загружен MyViewController
Мне просто нужно было добавить три строки кода, чтобы решить проблему.
// mainWindow is an IBOutlet to my window because the calling class
// is a simple object and not an NSWindowController otherwise I could
// have used `self` instead of `mainWindow`
NSResponder * aNextResponder = [mainWindow nextResponder];
[mainWindow setNextResponder:myViewControllerInstance];
[myViewControllerInstance setNextResponder:aNextResponder];
Работа сделана:-) Спасибо, Питер.
1 ответ
Почему вы ожидаете, что он отправит вам сообщения делегата, если вы еще не являетесь его делегатом? Если вы хотите, чтобы он отправлял вам сообщения делегата, то вам нужно установить себя в качестве его делегата.
Я пытался позвонить
setDelegate
, но будьте предупреждены о надвигающейся гибели, если я продолжу идти по этому маршруту...[QL]
QLError()
:-[QLPreviewPanel setDelegate:]
вызывается, пока на панели нет контроллера - исправьте это или это скоро повысится. Смотрите комментарии в QLPreviewPanel.h для-acceptsPreviewPanelControl:
/-beginPreviewPanelControl:
/-endPreviewPanelControl:
,
"Нет контроллера", говорит он. Итак, вам нужно иметь контроллер.
Комментарии к этому заголовку, особенно acceptsPreviewPanelControl:
и метод экземпляра QLPreviewPanel updateController
, предположите, что контроллер панели, если он есть, является объектом, который находится в цепочке респондента. Поэтому, если ваш контроллер не становится контроллером панели, это потому, что ваш контроллер не входит в цепочку респондента.
Итак, исправьте это, и тогда это сработает.
Я полагаю, что ваш контроллер представления должен быть в цепочке респондента всякий раз, когда его представление или какое-либо его подпредставление находится в цепочке респондента, но, возможно, это не так. В документации не сказано. Если все остальное терпит неудачу, установите себя в качестве следующего респондента представления в явном виде (и его предыдущего следующего респондента в качестве следующего респондента), а затем отправьте панель предварительного просмотра updateController
сообщение.
Спустя столько лет в быстром мире я обнаружил, что эта строка кода также работает. Не меняя цепочку ответов по умолчанию, просто "подтолкните" ваш контроллер представления, чтобы он стал первым респондентом в окне. Я не уверен, работает ли это для каждого сценария:
view.window?.makeFirstResponder(self)
И настройки объекта такие же:
override func acceptsPreviewPanelControl(_ panel: QLPreviewPanel!) -> Bool {
return true
}
override func beginPreviewPanelControl(_ panel: QLPreviewPanel!) {
panel.dataSource = self
panel.delegate = self
panel.currentPreviewItemIndex = //your initial index
}
override func endPreviewPanelControl(_ panel: QLPreviewPanel!) {
panel.dataSource = nil
panel.delegate = nil
}