【问题标题】:Xcode Swift MacOS App, drag and drop file into NSTextFieldXcode Swift MacOS App,将文件拖放到 NSTextField
【发布时间】:2021-05-22 15:36:33
【问题描述】:

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

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

谢谢!

【问题讨论】:

  • 文本字段必须是可编辑的,用户才能将内容放入其中 - 你的 B 计划是什么?
  • 你可以继承NSTextField并实现NSDraggingDestination方法

标签: swift xcode macos cocoa drag-and-drop


【解决方案1】:

首先,你需要阅读这个guide

其次,我在这里发布一些代码,用于执行与您所要求的类似的事情。

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

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

您可以通过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
}

}

【讨论】:

  • 非常感谢!一切正常!
  • 弗拉德我可以帮忙。 :)
  • 是否可以在您的解决方案中同时添加双击事件和 cmd+r?如果用户在 NSBox 内双击并清除 TextFIeld 内容,例如用户在应用程序上应用 cmd+r,我想添加打开打开文件对话框的可能性
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-21
  • 1970-01-01
  • 2013-04-21
相关资源
最近更新 更多