10

我在QuickLookNSView. 有限的文档QuickLook真的没有任何帮助。

在阅读了Apple Docs(主要针对自定义生成器和插件)后,我最终查看了QuickLookDownloader 示例代码。此代码基于基于文档的应用程序,但对我来说似乎是正确的方法(毕竟它是 Apple 的代码,并且在他们的项目中确实有效)。

在我的实现中,我可以QuickLook panel很好地显示它,并且我可以很容易地忽略它。但是,面板本身从不从 my 中调用委托方法NSViewController。结果,我什至从来没有显示对象,只是“未选择项目”的措辞。我很难过。

我尝试调用 a setDelegate,但如果我继续沿着那条路线前进,则会收到关于即将到来的厄运的警告......

[QL] QLError(): -[QLPreviewPanel setDelegate:] 在面板没有控制器时调用 - 修复此问题,否则此问题将很快引发。请参阅 QLPreviewPanel.h 中有关 -acceptsPreviewPanelControl:/-beginPreviewPanelControl:/-endPreviewPanelControl: 的注释。

然后在尝试响应委托方法之一时,无论如何都会发生厄运。

是的,我确实阅读了标题,确认我应该在赢得面板后设置委托(参见下面的代码)。

所以这是我的代码,它与示例代码几乎匹配,除了 a) 我从哪里获取数据(我从 a 获取它NSArrayController)和 b) 我从哪里获取我的预览项目(我的直接来自我的模型对象- 或者无论如何应该)

@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];

工作完成:-) 谢谢彼得。

4

2 回答 2

7

如果您(还不是)它的代表,您为什么希望它向您发送委托消息?如果您希望它向您发送委托消息,那么您需要将自己设置为其委托。

我尝试调用 a setDelegate,但如果我继续沿着那条路线前进,则会收到关于即将到来的厄运的警告......

[QL] QLError()-[QLPreviewPanel setDelegate:]在面板没有控制器时调用 - 修复此问题,否则此问题将很快引发。请参阅 QLPreviewPanel.h 中的注释以获取-acceptsPreviewPanelControl:/ -beginPreviewPanelControl:/ -endPreviewPanelControl:

“没有控制器”,它说。所以,你需要它有一个控制器。

对该标题的注释,特别是关于acceptsPreviewPanelControl:QLPreviewPanel 实例方法的注释updateController,表明面板的控制器(如果有)是响应者链中的一个对象。因此,如果您的控制器没有成为面板的控制器,那是因为您的控制器不在响应者链中。

所以,修复它,然后它会工作。

我想你的视图控制器应该在响应者链中,只要它的视图或其任何子视图在响应者链中,但也许情况并非如此。文档没有说。如果一切都失败了,请将自己明确设置为某个视图的下一个响应者(并将其先前的下一个响应者作为您的下一个响应者),然后向预览面板发送一条updateController消息。

于 2010-10-01T15:17:29.160 回答
1

经过这么多年,在 swift 世界中,我发现这行代码也可以。无需重新排列默认响应链,只需“推动”您的视图控制器成为窗口中的第一个响应者。我不确定它是否适用于所有场景:

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
}
于 2020-09-08T00:52:31.907 回答