ごんれのラボ

iOS、Android、Adobe系ソフトの自動化スクリプトのことを書き連ねています。

Drag&Drop したファイルのファイルパスを NSTextFeild に表示する方法

概要

Window 内に Finder 経由でファイルを Drag&Drop したら、ファイルパスを改行で区切って NSTextFeild に表示する。

使い方

  1. 起動する
    f:id:macneko-ayu:20170426131000p:plain  
     
  2. Drag&Drop
    f:id:macneko-ayu:20170426131015p:plain
     
  3. 表示される
    f:id:macneko-ayu:20170426131910p:plain

実装方法

  1. NSView を継承した FileDragDropView クラスを作成して、そこに一連の処理を書く
  2. Storyboard の NSViewController に NSView を配置して、クラスを FileDragDropView にする
  3. ビルドしたら完成

ソースコード

FileDragDropView クラスだけ抽出。

import Cocoa

class FileDragDropView: NSView {

    var acceptableTypes: Set<String> {
        return [NSURLPboardType]
    }
    var nonURLTypes: Set<String>  {
        return [String(kUTTypeText)]
    }
    let filteringOptions = [NSPasteboardURLReadingContentsConformToTypesKey:["public.text"]]
    var label: NSTextField?

    override func draw(_ dirtyRect: NSRect) {
        super.draw(dirtyRect)
    }

    override init(frame frameRect: NSRect) {
        super.init(frame: frameRect)
        setup()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setup()
    }
    
    override func awakeFromNib() {
        super.awakeFromNib()
        label = NSTextField(frame: NSRect(x: 20, y: 20, width: self.frame.width - 40, height: 40))
        label?.stringValue = ""
        label?.textColor = NSColor.black
        self.addSubview(label!)
    }
    
    func setup() {
        self.register(forDraggedTypes: Array(acceptableTypes))
    }
    
    func shouldAllowDrag(_ draggingInfo: NSDraggingInfo) -> Bool {
        var canAccept = false
        let pasteBoard = draggingInfo.draggingPasteboard()
        if pasteBoard.canReadObject(forClasses: [NSURL.self], options: filteringOptions) {
            canAccept = true
        } else if let types = pasteBoard.types, nonURLTypes.intersection(types).count > 0 {
            canAccept = true
        }
        return canAccept
    }
    
    override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
        let allow = shouldAllowDrag(sender)
        return allow ? .copy : NSDragOperation()
    }
    
    override func prepareForDragOperation(_ sender: NSDraggingInfo) -> Bool {
        let allow = shouldAllowDrag(sender)
        return allow
    }
    
    override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
        let pasteBoard = sender.draggingPasteboard() as NSPasteboard
        if let urls = pasteBoard.readObjects(forClasses: [NSURL.self], options: filteringOptions) as? [URL], urls.count > 0 {
            label?.stringValue = ""
            let files = pasteBoard.propertyList(forType: NSFilenamesPboardType) as! [String]
            for file in files {
                label?.stringValue += file + "\n"
            }
            return true
        }
        else if let types = pasteBoard.types, types.contains(NSFilenamesPboardType) {
            label?.stringValue = ""
            let files = pasteBoard.propertyList(forType: NSFilenamesPboardType) as! [String]
            for file in files {
                label?.stringValue += file + "\n"
            }
            return true
        }
        return false
    }
}

更新履歴

2017/4/27 テキスト形式のファイルのみ Drag&Drop できるようにフィルタリング処理を追加
2017/4/26 初版

参考

[macOS] [Swift3.0] Drag & Dropでファイルパスを取得
Drag and Drop Tutorial for macOS