簡體   English   中英

QuickLook 消費者作為 NSViewController 的委托

[英]QuickLook consumer as a delegate from an NSViewController

我在從NSView的表中實現QuickLook功能時遇到了一些問題。 QuickLook上的有限文檔真的一點幫助都沒有。

在閱讀了Apple Docs (主要針對自定義生成器和插件)后,我最終查看了QuickLookDownloader 示例代碼 這段代碼基於一個基於文檔的應用程序,但對我來說似乎是正確的方法(畢竟它是 Apple 的代碼並且它確實在他們的項目中工作)。

在我的實現中,我可以讓QuickLook panel顯示得很好,我也可以很容易地關閉它。 但是,面板本身從不從我的NSViewController調用委托方法。 結果我什至從來沒有顯示對象,只是“沒有選擇項目”這個詞。 我很難過。

我嘗試調用setDelegate ,但是如果我繼續沿着這條路setDelegate ,就會收到即將到來的厄運的警告......

[QL] QLError(): -[QLPreviewPanel setDelegate:] 在面板沒有控制器時調用 - 修復此問題,否則很快就會引發此問題。 請參閱 QLPreviewPanel.h 中關於 -acceptsPreviewPanelControl:/-beginPreviewPanelControl:/-endPreviewPanelControl: 的注釋。

然后在嘗試響應委托方法之一時,dealloc 無論如何都會發生厄運。

是的,我確實閱讀了標題,確認我應該在贏得小組后設置委托(請參閱下面的代碼)。

所以這是我的代碼,它幾乎與示例代碼匹配,除了 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];

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

如果您(還)不是它的委托人,為什么您希望它向您發送委托消息? 如果您希望它向您發送委托消息,那么您需要將自己設置為它的委托人。

我嘗試調用setDelegate ,但是如果我繼續沿着這條路setDelegate ,就會收到即將到來的厄運的警告......

[QL] QLError() : -[QLPreviewPanel setDelegate:]在面板沒有控制器時調用 - 修復此問題,否則將很快引發此問題。 請參閱 QLPreviewPanel.h 中關於-acceptsPreviewPanelControl: / -beginPreviewPanelControl: / -endPreviewPanelControl:

“沒有控制器”,它說。 所以,你需要它有一個控制器。

對該標頭的評論,尤其是acceptsPreviewPanelControl:和 QLPreviewPanel 實例方法updateController ,表明面板的控制器(如果有)是響應者鏈中的一個對象。 因此,如果您的控制器沒有成為面板的控制器,那是因為您的控制器不在響應者鏈中。

所以,解決這個問題,然后它就會起作用。

我想,只要您的視圖或其任何子視圖在響應者鏈中,您的視圖控制器就應該在響應者鏈中,但事實並非如此。 文檔沒有說。 如果所有其他方法都失敗了,請將自己明確設置為某個視圖的下一個響應者(並將其上一個下一個響應者設置為您的下一個響應者),然后向預覽面板發送一條updateController消息。

這么多年之后,在 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
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM