Xcode Swift MacOS 应用程序,将文件拖放到 NSTextField 中

Xcode Swift MacOS App, drag and drop file into NSTextField

我正在为 MacOS 实现我的第一个应用程序,用户应该输入要处理的文件路径。 我的 NSViewController 应用程序上有一个 NSTextField,我想让用户只需将一个文件拖放到那里,这样我就可以获得文件路径,打开它并在 NSTextField 上放置一些关于文件信息的文本。

你能帮帮我吗?我看到如果我使 NSTextField 可编辑,我可以删除文件,但我不希望 NSTextField 可编辑(只是可选择复制粘贴信息)

谢谢!

首先,您需要阅读这篇guide

其次,我 post 这里有一些代码,我用它来做类似于你所问的事情。

但是,我的策略不是子类化 NSTextField,而是将此字段放在我子类化的 NSBox 中。这样做的好处是可以使用聚焦环向用户提供一些视觉反馈。

注意 performDragOperation,其中字符串值是通过 window 的控制器设置的,然后将其转发到文本字段以将其字符串值设置为拖放文件的路径.

您可以通过 prepareForDragOperation 过滤您可以接受的内容。也检查一下。

class DropBox: NSBox
{
     let dragType = NSPasteboard.PasteboardType(kUTTypeFileURL as String)
     var doHighlight = false

// ---------------------------------------------------------------------------------
// awakeFromNib
// ---------------------------------------------------------------------------------
override func awakeFromNib()
{
    registerForDraggedTypes([dragType])
}

// ---------------------------------------------------------------------------------
// acceptsFirstMouse
// ---------------------------------------------------------------------------------
// Accept activation click as click in window, so source doesn't have to be the
// active window
override func acceptsFirstMouse(for event: NSEvent?) -> Bool
{
    return true
}

// ---------------------------------------------------------------------------------
// draggingEntered
// ---------------------------------------------------------------------------------
override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation
{
    let pasteboard = sender.draggingPasteboard
    let mask = sender.draggingSourceOperationMask
    
    if let types = pasteboard.types, types.contains(dragType)
    {
        if mask.contains(.link)
        {
            doHighlight = true
            needsDisplay = true
            return .link
        }
    }
    
    return []
}

// ---------------------------------------------------------------------------------
// draggingExited
// ---------------------------------------------------------------------------------
override func draggingExited(_ sender: NSDraggingInfo?)
{
    doHighlight = false
    needsDisplay = true
}

// ---------------------------------------------------------------------------------
// drawRect
// ---------------------------------------------------------------------------------
override func draw(_ dirtyRect: NSRect)
{
    super.draw(dirtyRect)
    
    if doHighlight {
        let rect = NSRect(x: dirtyRect.origin.x,
                          y: dirtyRect.origin.y,
                          width: NSWidth(dirtyRect),
                          height: NSHeight(dirtyRect) - NSHeight(titleRect) + 1.0)
        
        NSFocusRingPlacement.only.set()
        let contentRect = rect.insetBy(dx: 4, dy: 4)
        NSBezierPath(rect: contentRect).fill()
    }
}

// ---------------------------------------------------------------------------------
// performDragOperation
// ---------------------------------------------------------------------------------
// Method to handle drop data
override func performDragOperation(_ sender: NSDraggingInfo) -> Bool
{
    if let source = sender.draggingSource as? NSBox {
        if source === self {
            return false
        }
    }
    
    let pasteboard = sender.draggingPasteboard
    let options = [NSPasteboard.ReadingOptionKey.urlReadingFileURLsOnly:true]
    if let urls = pasteboard.readObjects(forClasses: [NSURL.self], options: options) as? [URL],
        let controller = self.window?.delegate as? WindowController
    {
        for url in urls {
            if SchISCoreFileUtilities.isValid(url.path) {
                controller.setApplicationPath(url.path)
                return true
            }
        }
    }
    
    return false
}

// ---------------------------------------------------------------------------------
// prepareForDragOperation
// ---------------------------------------------------------------------------------
// Method to determine if we can accept the drop (filter for urls to apps)
override func prepareForDragOperation(_ sender: NSDraggingInfo) -> Bool
{
    doHighlight = false
    needsDisplay = true
    let pasteboard = sender.draggingPasteboard
    
    if let types = pasteboard.types, types.contains(dragType)
    {
        let options = [NSPasteboard.ReadingOptionKey.urlReadingFileURLsOnly:true]
        if let urls = pasteboard.readObjects(forClasses: [NSURL.self], options: options) as? [URL]
        {
            for url in urls {
                if url.pathExtension == "app" {
                    return true
                }
            }
        }
    }
    
    return false
}

}