Swift NStatusBarItem, кнопка поддерживает перетаскивание

Я знаю, что есть куча подобных вопросов, но все они очень устарели, в основном у меня есть 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 и добавить подвид к кнопке, но, похоже, ничего не работает, кто-нибудь знает, как это сделать? ?


person Oscar Franco    schedule 08.05.2020    source источник
comment
Вы пытались зарегистрировать тип URL-адреса файла? .png — данные изображения в формате PNG.   -  person Willeke    schedule 09.05.2020
comment
а, я этого не знал, я думал, что это тип файла, я попробую   -  person Oscar Franco    schedule 09.05.2020


Ответы (3)


Это работает в моей системе с использованием 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()

person apodidae    schedule 08.05.2020
comment
Я заставил это работать благодаря вам, расширение, которое я пробовал, на самом деле работает, нет необходимости рисовать подвид, это были только данные, которые не были объявлены должным образом. - person Oscar Franco; 09.05.2020

@Oscar - я пересмотрел ваш исходный пост и могу подтвердить, что следующий код добавит возможность перетаскивания в 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

person apodidae    schedule 09.05.2020
comment
Работает и для NSButton. - person apodidae; 09.05.2020

Оказывается, расширение, которое я сделал для 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])
person Oscar Franco    schedule 09.05.2020