Use Quick Look inside a Swift cocoa application to preview audio files
This turned out to be pretty simple actually. All the APIs are public. I do think things got simpler with OS X 10.10, just not super well documented maybe?
Here is an example of a ViewController that has a single button that triggers the standard Quick Look Panel with two items that can be found on the filesystem.
class ViewController: NSViewController {
@IBAction func showQuickLookPanel(sender: AnyObject) {
if let panel = QLPreviewPanel.sharedPreviewPanel() {
panel.dataSource = self
panel.makeKeyAndOrderFront(self)
}
}
}
extension ViewController: QLPreviewPanelDataSource {
func numberOfPreviewItemsInPreviewPanel(panel: QLPreviewPanel!) -> Int {
return 2
}
func previewPanel(panel: QLPreviewPanel!, previewItemAtIndex index: Int) -> QLPreviewItem! {
if index == 0 {
return NSURL(fileURLWithPath: "/Library/Desktop Pictures/Beach.jpg")
} else {
return NSURL(fileURLWithPath: "/System/Library/Compositions/Rollercoaster.mov")
}
}
}
There are three parts to this.
First, to open the standard Quick Look window just call makeKeyAndOrderFront
on the shared panel.
The panel knows what to show because it talks to it's datasource, which is implemented via QLPreviewPanelDataSource
. As you can see in my example it simply returns a count of 2
and it can be asked to return an object that implements QLPreviewItem
.
For my demo I simply returns NSURL
instances to two resources that are included in the system by default. Turns out that NSURL
already implements the QLPreviewItem
protocol so there is nothing extra to do.
If the items that you want to preview do not easily translate to URLs (files) on the filesystem then you will need to do a more complicated implementation of a QLPreviewItem
object.
I bet that pointing to MP3 files will just work fine.
Implementation of NSURL/File QuickLook Preview & NSURL/File dragging
For "selecting" a view, you should have the view accept first responder, and draw a focus ring (or whatever highlight is appropriate for you) when the view is first responder. Override acceptsFirstResponder
(return true), becomeFirstResponder
and resignFirstResponder
(keep a flag for whether the view is first responder, and trigger drawing with setNeedsDisplay
or whatever is appropriate), and the drawing mechanism (drawRect
or whatever is approproiate if you're using CALayers).
Override keyDown
for handling the spacebar.
Override mouseDragged
and initiate a drag session, and simply create an NSDraggingItem
with the pasteboardWriter
being the NSURL
itself.
For displaying QuickLook: QLPreviewPanel
https://developer.apple.com/documentation/quartz/qlpreviewpanel
Swift Mac Quick Look get image displayed
According to this: How to put the QLPreviewPanel show as a popover in cocoa?
I created a view in IB.
Created a class.
class MAQuickLookItem: NSObject, QLPreviewItem {
var previewItemURL: URL?
var previewItemTitle: String?
}
and then
let view = QLPreviewView(frame: NSMakeRect(0, 0, previewView.frame.size.width, previewView.frame.size.height), style: .normal)
previewView.addSubview(view!)
let item = MAQuickLookItem()
item.previewItemTitle = self.previewFiles?[0].widePath
item.previewItemURL = URL(fileURLWithPath: (self.previewFiles?[0].widePath)!)
view?.previewItem = item
Now you can simply do a screenshot of the view.
How to use SpaceBar button inside an application to invoke quick look
On your view, do this:
- (void)keyDown:(NSEvent *)event
{
unichar firstChar = 0;
if ([[event charactersIgnoringModifiers] length] > 0)
firstChar = [[event charactersIgnoringModifiers] characterAtIndex:0];
if (firstChar == ' ')
{
if ([QLPreviewPanel sharedPreviewPanelExists]
&& [[QLPreviewPanel sharedPreviewPanel] isVisible])
{
[[QLPreviewPanel sharedPreviewPanel] orderOut:nil];
}
else
{
[[QLPreviewPanel sharedPreviewPanel] makeKeyAndOrderFront:nil];
[[NSApp mainWindow] makeKeyWindow];
}
}
else if (firstChar == NSRightArrowFunctionKey)
{
if ([QLPreviewPanel sharedPreviewPanelExists]
&& [[QLPreviewPanel sharedPreviewPanel] isVisible])
{
[[QLPreviewPanel sharedPreviewPanel] selectNextItem];
return;
}
}
else if (firstChar == NSLeftArrowFunctionKey)
{
if ([QLPreviewPanel sharedPreviewPanelExists]
&& [[QLPreviewPanel sharedPreviewPanel] isVisible])
{
[[QLPreviewPanel sharedPreviewPanel] selectPreviousItem];
return;
}
}
else
[super keyDown:event];
}
Then, I do this in my app's delegate (AppDelegate.m):
- (BOOL)acceptsPreviewPanelControl:(QLPreviewPanel *)panel
{
//note that this methods indeed gets called because NSApp's
//delegate is in the responder chain.
return YES;
}
- (void)beginPreviewPanelControl:(QLPreviewPanel *)panel
{
previewPanel = panel; //set an ivar
[panel setDataSource:self];
}
- (void)endPreviewPanelControl:(QLPreviewPanel *)panel
{
previewPanel = nil;
}
- (NSInteger)numberOfPreviewItemsInPreviewPanel:(QLPreviewPanel *)panel
{
//return a number of your choice (depends on your own app)
}
- (id <QLPreviewItem>)previewPanel:(QLPreviewPanel *)panel
previewItemAtIndex:(NSInteger)index
{
//return an object of your choice (depends on your app)
}
- (void)handleCurrentFileItemsSelectionChange:(NSNotification *)note
{
[previewPanel reloadData]; //referring to the ivar
}
Related Topics
How to Store Data from a Picker View in a Variable When a Button Is Pressed
Allocating Ekeventstore Throws Warnings
How to Resolve Rctpromiseresolveblock After Bftask
Applescript Used in My Cocoa MAC App, Stopped Working in Osx 10.14
Generic Vector with Cardinality Type Safety
Customize Mglpolyline Using Mapbox
Open Attachment from Mail Using iOS 8 App [Swift]
Swift 4 Base64 String to Data Not Working Due to String Containing "Incomplete" Emoji
Touch Sprite, Make It Jump Up Then Fall Down Again(Repeat as Many Times as Spritenode Is Tapped.)
In Swift Can You Trap "Fatal Error Unexpectedly Found Nil While Unwrapping an Optional Value"
Swift Nstimer Dynamically Changing Interval
Mkpolyline Broken When Using Type Satelliteflyover
Include Inheritance Constraint in Swift Generic Types
Swift Displaying The Time or Date Based on Timestamp
How to Constrain Second Nsviewcontroller Minimum Size in Os X App
Msmessagelivelayout Freeze/Crash in Transcript When Info.Plist Contains Privacy Request