Xcode Swift MacOS App,将文件拖放到 NSTextField
Posted
技术标签:
【中文标题】Xcode Swift MacOS App,将文件拖放到 NSTextField【英文标题】:Xcode Swift MacOS App, drag and drop file into NSTextField 【发布时间】:2021-05-22 15:36:33 【问题描述】:我正在为 MacOS 实现我的第一个应用程序,用户应输入要处理的文件路径。 我的 NSViewController 应用程序上有一个 NSTextField,我想让用户只需将一个文件拖放到那里,这样我就可以获取文件路径,打开它并在 NSTextField 上放置一些带有文件信息的文本。
你能帮帮我吗?我看到如果我使 NSTextField 可编辑,我可以删除文件,但我不希望 NSTextField 是可编辑的(只能选择复制粘贴信息)
谢谢!
【问题讨论】:
文本字段必须是可编辑的,用户才能将内容放入其中 - 你的 B 计划是什么? 你可以继承NSTextField
并实现NSDraggingDestination
方法
【参考方案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,我想添加打开打开文件对话框的可能性以上是关于Xcode Swift MacOS App,将文件拖放到 NSTextField的主要内容,如果未能解决你的问题,请参考以下文章
为`swift package generate-xcodeproj`设置macOS目标?
为`swift package generate-xcodeproj`设置macOS目标?
Swift UI Canvas 未在 macOS 10.15 和 Xcode 11.1 中显示
Xcode Swift 5 MacOs 应用程序存档时为空窗口,但在从 Xcode 运行时有效
强制 Swift Playgrounds (xcode) 在不模拟 iOS 的情况下使用 MacOS SpriteKit