Swift StatusBarItem,使按钮支持拖放
Swift NStatusBarItem, make button support drag&drop
我知道有很多类似的问题,但它们都已经过时了,基本上我有一个 statusBarItem
我想让它响应拖放文件,这里是一些我试过的代码:
extension NSStatusBarButton {
open override func prepareForDragOperation(_ sender: NSDraggingInfo) -> Bool {
true
}
open override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
print("dragging entered")
return .copy
}
open override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
print("Something was dragged!")
return true
}
open override func draggingEnded(_ sender: NSDraggingInfo) {
print("Draging ended")
}
}
class DragAndDropButton: NSStatusBarButton {
open override func prepareForDragOperation(_ sender: NSDraggingInfo) -> Bool {
true
}
open override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
print("dragging entered")
return .copy
}
open override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
print("Something was dragged!")
return true
}
open override func draggingEnded(_ sender: NSDraggingInfo) {
print("Draging ended")
}
}
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
var window: NSWindow!
var popover: NSPopover!
var statusBarItem: NSStatusItem!
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Create the SwiftUI view and set the context as the value for the managedObjectContext environment keyPath.
// Add `@Environment(\.managedObjectContext)` in the views that will need the context.
let popoverView = PopoverView()
popover = NSPopover()
popover.contentSize = NSSize(width: AppConstants.popoverWidth, height: AppConstants.popoverHeight)
popover.animates = true
popover.behavior = .transient
popover.contentViewController = NSHostingController(rootView: popoverView)
statusBarItem = NSStatusBar.system.statusItem(withLength: CGFloat(NSStatusItem.variableLength))
let dropSubview = DragAndDropButton()
dropSubview.registerForDraggedTypes([.png])
dropSubview.image = NSImage(named: "CognitionSmall")
statusBarItem.button = drop
// statusBarItem.view = dropSubview
// statusBarItem.title = "Test"
if let button = self.statusBarItem.button {
// button.view
// button.registerForDraggedTypes([.multipleTextSelection])
button.addSubview(dropSubview)
button.imagePosition = NSControl.ImagePosition.imageLeft
button.image = NSImage(named: "CognitionSmall")
button.action = #selector(togglePopover(_:))
// button.window!.delegate = self
// button.addSubview(cognitoSubview)
// button.performDragOperation = #selector(onDrag(_:))
}
}
如您所见,我已尝试扩展和覆盖默认的 NSStatusBarButton
行为,并将其替换为我自己的 NSView
并向按钮添加子视图,但似乎没有任何效果工作,有人知道如何让它工作吗?
这适用于我使用 CommandLine 的系统(尚未在 Xcode 中尝试过)
import Cocoa
class CustomView:NSView {
var filePaths : [String] = []
override init(frame frameRect: NSRect) {
super.init(frame:frameRect)
self.registerForDraggedTypes([NSPasteboard.PasteboardType.fileURL])
}
required init?(coder aDecoder : NSCoder) {
super.init(coder: aDecoder)
}
override func draw(_ rect: NSRect) {
super.draw(rect)
let bkgrnd = NSBezierPath(rect:rect)
NSColor.red.set()
bkgrnd.fill()
NSColor.black.set()
let str = String("DND")
let font = NSFont.init(name: "Menlo", size:14.0)
let style = NSMutableParagraphStyle()
style.alignment = NSTextAlignment.center
let attrText = NSAttributedString(string:str, attributes: [.paragraphStyle: style, .font:font!])
attrText.draw(in: rect)
}
override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
print("draggingEntered")
return .copy
}
override func draggingUpdated(_ sender: NSDraggingInfo) -> NSDragOperation {
print("draggingUpdated")
return .copy
}
override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
let board = sender.draggingPasteboard.propertyList(forType: NSPasteboard.PasteboardType(rawValue: "NSFilenamesPboardType")) as? NSArray
var draggedFilePath : String
draggedFilePath = board![0] as! String
print("draggedFilePath = \(draggedFilePath)")
return true
}
}
// **** main.swift **** //
let app = NSApplication.shared
app.setActivationPolicy(NSApplication.ActivationPolicy.regular)
let statusItem = NSStatusBar.system.statusItem(withLength: 100)
var view : CustomView!
view = CustomView(frame:NSMakeRect(0, 0, 100, 40))
statusItem.button?.addSubview(view)
app.run()
原来我对 NSStatusBarButton 做的扩展很好,除了我没有正确测试它,如果你声明更多的注册类型它工作得很好:
extension NSStatusBarButton {
open override func prepareForDragOperation(_ sender: NSDraggingInfo) -> Bool {
true
}
open override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
print("dragging entered")
return .copy
}
open override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
print("Something was dragged!")
return true
}
open override func draggingEnded(_ sender: NSDraggingInfo) {
print("Draging ended")
}
}
... more initialization code
button.registerForDraggedTypes([.fileURL, .multipleTextSelection, .png])
@Oscar - 我修改了你原来的 post 并且可以确认以下代码将通过使用扩展将拖放功能添加到 NSStatusBarButton 并且它消除了对 NSView 子视图的需要。谢谢
import Cocoa
extension NSStatusBarButton {
open override func prepareForDragOperation(_ sender: NSDraggingInfo) -> Bool {
true
}
open override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
print("Dragging entered.")
return .copy
}
open override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
print("Something was dragged!")
return true
}
open override func draggingEnded(_ sender: NSDraggingInfo) {
print("Dragging ended.")
}
}
class AppDelegate: NSObject, NSApplicationDelegate {
var window: NSWindow!
var statusItem: NSStatusItem!
func applicationDidFinishLaunching(_ aNotification: Notification) {
statusItem = NSStatusBar.system.statusItem(withLength: 100)
statusItem.button!.title = "DND Test"
statusItem.button!.registerForDraggedTypes([.fileURL])
}
}
let appDelegate = AppDelegate()
// **** main.swift **** //
let app = NSApplication.shared
app.setActivationPolicy(.regular)
app.delegate = appDelegate
app.activate(ignoringOtherApps:true)
app.run()
如果文件保存为 statusItem.swift,它可能是来自终端的 运行 使用:
swiftc statusItem.swift -framework Cocoa -o statusItem && ./statusItem
我知道有很多类似的问题,但它们都已经过时了,基本上我有一个 statusBarItem
我想让它响应拖放文件,这里是一些我试过的代码:
extension NSStatusBarButton {
open override func prepareForDragOperation(_ sender: NSDraggingInfo) -> Bool {
true
}
open override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
print("dragging entered")
return .copy
}
open override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
print("Something was dragged!")
return true
}
open override func draggingEnded(_ sender: NSDraggingInfo) {
print("Draging ended")
}
}
class DragAndDropButton: NSStatusBarButton {
open override func prepareForDragOperation(_ sender: NSDraggingInfo) -> Bool {
true
}
open override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
print("dragging entered")
return .copy
}
open override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
print("Something was dragged!")
return true
}
open override func draggingEnded(_ sender: NSDraggingInfo) {
print("Draging ended")
}
}
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
var window: NSWindow!
var popover: NSPopover!
var statusBarItem: NSStatusItem!
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Create the SwiftUI view and set the context as the value for the managedObjectContext environment keyPath.
// Add `@Environment(\.managedObjectContext)` in the views that will need the context.
let popoverView = PopoverView()
popover = NSPopover()
popover.contentSize = NSSize(width: AppConstants.popoverWidth, height: AppConstants.popoverHeight)
popover.animates = true
popover.behavior = .transient
popover.contentViewController = NSHostingController(rootView: popoverView)
statusBarItem = NSStatusBar.system.statusItem(withLength: CGFloat(NSStatusItem.variableLength))
let dropSubview = DragAndDropButton()
dropSubview.registerForDraggedTypes([.png])
dropSubview.image = NSImage(named: "CognitionSmall")
statusBarItem.button = drop
// statusBarItem.view = dropSubview
// statusBarItem.title = "Test"
if let button = self.statusBarItem.button {
// button.view
// button.registerForDraggedTypes([.multipleTextSelection])
button.addSubview(dropSubview)
button.imagePosition = NSControl.ImagePosition.imageLeft
button.image = NSImage(named: "CognitionSmall")
button.action = #selector(togglePopover(_:))
// button.window!.delegate = self
// button.addSubview(cognitoSubview)
// button.performDragOperation = #selector(onDrag(_:))
}
}
如您所见,我已尝试扩展和覆盖默认的 NSStatusBarButton
行为,并将其替换为我自己的 NSView
并向按钮添加子视图,但似乎没有任何效果工作,有人知道如何让它工作吗?
这适用于我使用 CommandLine 的系统(尚未在 Xcode 中尝试过)
import Cocoa
class CustomView:NSView {
var filePaths : [String] = []
override init(frame frameRect: NSRect) {
super.init(frame:frameRect)
self.registerForDraggedTypes([NSPasteboard.PasteboardType.fileURL])
}
required init?(coder aDecoder : NSCoder) {
super.init(coder: aDecoder)
}
override func draw(_ rect: NSRect) {
super.draw(rect)
let bkgrnd = NSBezierPath(rect:rect)
NSColor.red.set()
bkgrnd.fill()
NSColor.black.set()
let str = String("DND")
let font = NSFont.init(name: "Menlo", size:14.0)
let style = NSMutableParagraphStyle()
style.alignment = NSTextAlignment.center
let attrText = NSAttributedString(string:str, attributes: [.paragraphStyle: style, .font:font!])
attrText.draw(in: rect)
}
override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
print("draggingEntered")
return .copy
}
override func draggingUpdated(_ sender: NSDraggingInfo) -> NSDragOperation {
print("draggingUpdated")
return .copy
}
override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
let board = sender.draggingPasteboard.propertyList(forType: NSPasteboard.PasteboardType(rawValue: "NSFilenamesPboardType")) as? NSArray
var draggedFilePath : String
draggedFilePath = board![0] as! String
print("draggedFilePath = \(draggedFilePath)")
return true
}
}
// **** main.swift **** //
let app = NSApplication.shared
app.setActivationPolicy(NSApplication.ActivationPolicy.regular)
let statusItem = NSStatusBar.system.statusItem(withLength: 100)
var view : CustomView!
view = CustomView(frame:NSMakeRect(0, 0, 100, 40))
statusItem.button?.addSubview(view)
app.run()
原来我对 NSStatusBarButton 做的扩展很好,除了我没有正确测试它,如果你声明更多的注册类型它工作得很好:
extension NSStatusBarButton {
open override func prepareForDragOperation(_ sender: NSDraggingInfo) -> Bool {
true
}
open override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
print("dragging entered")
return .copy
}
open override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
print("Something was dragged!")
return true
}
open override func draggingEnded(_ sender: NSDraggingInfo) {
print("Draging ended")
}
}
... more initialization code
button.registerForDraggedTypes([.fileURL, .multipleTextSelection, .png])
@Oscar - 我修改了你原来的 post 并且可以确认以下代码将通过使用扩展将拖放功能添加到 NSStatusBarButton 并且它消除了对 NSView 子视图的需要。谢谢
import Cocoa
extension NSStatusBarButton {
open override func prepareForDragOperation(_ sender: NSDraggingInfo) -> Bool {
true
}
open override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
print("Dragging entered.")
return .copy
}
open override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
print("Something was dragged!")
return true
}
open override func draggingEnded(_ sender: NSDraggingInfo) {
print("Dragging ended.")
}
}
class AppDelegate: NSObject, NSApplicationDelegate {
var window: NSWindow!
var statusItem: NSStatusItem!
func applicationDidFinishLaunching(_ aNotification: Notification) {
statusItem = NSStatusBar.system.statusItem(withLength: 100)
statusItem.button!.title = "DND Test"
statusItem.button!.registerForDraggedTypes([.fileURL])
}
}
let appDelegate = AppDelegate()
// **** main.swift **** //
let app = NSApplication.shared
app.setActivationPolicy(.regular)
app.delegate = appDelegate
app.activate(ignoringOtherApps:true)
app.run()
如果文件保存为 statusItem.swift,它可能是来自终端的 运行 使用:
swiftc statusItem.swift -framework Cocoa -o statusItem && ./statusItem