提问人:AirMonk 提问时间:2/20/2021 更新时间:2/21/2021 访问量:391
Xcode Swift MacOS App,将文件拖放到 NSTextField 中
Xcode Swift MacOS App, drag and drop file into NSTextField
问:
我正在为 MacOS 实现我的第一个应用程序,用户应该输入要处理的文件路径。 我的 NSViewController 应用程序上有一个 NSTextField,我想让用户只需将一个文件拖放到那里,这样我就可以获取文件路径,打开它并在 NSTextField 上放置一些带有文件信息的文本。
你能帮帮我吗?我看到如果我使 NSTextField 可编辑,我可以删除文件,但我不希望 NSTextField 是可编辑的(只能选择复制粘贴信息)
谢谢!
答:
2赞
jvarela
2/21/2021
#1
首先,您需要阅读本指南。
其次,我在这里发布一些代码,我用它们来做一些类似于你所要求的事情。
但是,我的策略不是子类化,而是将此字段放在子类中。这样做的优点是可以使用对焦环向用户提供一些视觉反馈。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
}
}
评论
0赞
AirMonk
3/7/2021
是否可以在您的解决方案中添加双击事件和 cmd+r?我想添加打开文件对话框的可能性,如果用户在 NSBox 内双击并清除 TextFIeld 内容,例如,如果用户在应用程序上应用 cmd+r
评论
NSDraggingDestination
方法NSTextField