Потребитель QuickLook в качестве делегата от NSViewController - PullRequest
9 голосов
/ 01 октября 2010

У меня возникли проблемы с реализацией функциональности 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 Ответ

6 голосов
/ 01 октября 2010

Почему вы ожидаете, что он будет отправлять вам сообщения делегата, если вы еще не являетесь его делегатом?Если вы хотите, чтобы он отправлял вам сообщения делегата, то вам нужно установить себя в качестве его делегата.

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

[QL] QLError(): -[QLPreviewPanel setDelegate:] вызывается, когда на панели нет контроллера - Исправьте это или это скоро повысится.Смотрите комментарии в QLPreviewPanel.h для -acceptsPreviewPanelControl: / -beginPreviewPanelControl: / -endPreviewPanelControl:.

«Нет контроллера», там написано.Итак, вам нужен контроллер.

Комментарии к этому заголовку, особенно к acceptsPreviewPanelControl: и методу экземпляра QLPreviewPanel updateController, указывают на то, что контроллер панели, если он у него есть, является объектомэто в цепочке респондента.Поэтому, если ваш контроллер не становится контроллером панели, это потому, что ваш контроллер не входит в цепочку респондента.

Итак, исправьте это, и тогда оно будет работать.

Я быПредставьте, что ваш контроллер представления должен быть в цепочке респондента, когда его представление или любое его подпредставление находится в цепочке респондента, но, возможно, это не так. Документация не говорит.Если все остальное терпит неудачу, установите себя в качестве следующего респондента некоторого представления явно (и его предыдущего следующего респондента как следующего респондента), затем отправьте панели предварительного просмотра сообщение updateController.

...