NSOutlineView如何在右键单击期间显示蓝色轮廓

时间:2017-07-29 03:29:09

标签: cocoa nstableview appkit nsoutlineview

每个人都讨论过如何在右键单击中摆脱蓝色轮廓......但是我。

相反,我试图显示蓝色轮廓。

当我右键单击我的大纲视图行时,我没有得到任何轮廓。菜单出现但轮廓不是。

您可以看到下图中看不到蓝色轮廓:

enter image description here


以下是我想要实现的目标。

Blue outline

更新

这是我实施NSMenu的方式。我将NSOutlineView子类化,并制定了一个新协议来覆盖NSOutlineViewDelegate

这个想法是通过让NSOutlineView为每个项目询问NSMenu来简化它,这样我们就可以为每个项目实现不同的菜单。它可以工作,但在右键单击期间,蓝色轮廓视图不会显示。

KRMenuOutlineView.swift

import Cocoa

@objc protocol KRMenuOutlineViewDelegate: NSOutlineViewDelegate {
    // This method will ask NSMenu for each item in outline view
    func outlineView(_ outlineView: KRMenuOutlineView, menuFor item: Any, event: NSEvent) -> NSMenu?
}

class KRMenuOutlineView: NSOutlineView {

    override var delegate: NSOutlineViewDelegate? {
        didSet {
            if let newValue = delegate {
                /*
                 * Swift doesn't support overriding inherited properties with different type
                 * like Objective C Does, therefore we need internal delegate.
                 */
                internalDelegate = unsafeBitCast(newValue, to: KRMenuOutlineViewDelegate.self)
            } else {
                internalDelegate = nil
            }
        }
    }

    private var internalDelegate: KRMenuOutlineViewDelegate?

    override func menu(for event: NSEvent) -> NSMenu? {
        let point = self.convert(event.locationInWindow, from: nil)
        if let item = self.item(atRow: self.row(at: point)) {
            return self.internalDelegate?.outlineView(self, menuFor: item, event: event)
        }
        return super.menu(for: event)
    }
}

然后,我在我的视图控制器中使用它:

KRTreeViewController.swift

extension KRTreeViewController: KRMenuOutlineViewDelegate {
    func outlineView(_ outlineView: KRMenuOutlineView, menuFor item: Any, event: NSEvent) -> NSMenu? {
            let menu = NSMenu(title: "Contextual Menu")
            menu.delegate = self

            let key = String(utf16CodeUnits: [unichar(NSBackspaceCharacter)], count: 1) as String
            let deleteMenuItem = menu.addItem(withTitle: "Delete",
                                              action: #selector(didClickMenuItem(_:)),
                                              keyEquivalent: key)
            deleteMenuItem.representedObject = myItem
            deleteMenuItem.target = self

            return menu
    }

    @objc fileprivate func didClickMenuItem(_ menuItem: NSMenuItem) {
        // ...
    }
}

1 个答案:

答案 0 :(得分:1)

如何正确显示上下文菜单:

如果您使用故事板创建了菜单: 首先,转到故事板并将菜单添加到包含outlineView的viewController。 然后将其设为@IBOutlet,以便稍后引用。

在像viewDidLoad()这样的方法中,通过调用

将菜单添加到outlineView
outlineView.menu = myMenu

其中myMenu可以是您在Interface Builder中创建的,也可以是代码。

您现在可以运行应用程序,并且应该看到单元格周围的蓝色轮廓。

现在的问题是您不知道用户点击了哪个单元格。 要解决此问题,请将自己设置为myMenu的委托并采用NSMenuDelegate协议。

func menuNeedsUpdate(_ menu: NSMenu) {
    let row = self.outlineView.clickedRow

    guard row != -1 else { return }
    for item in menu.items {
        item.representedObject = row
    }
}

在这里你可以做任何你需要的事情。此实现将rowIndex设置为每个菜单项的representObject。请记住,这只适用于静态outlineViews(在后台不会改变的那些)和只有一层深度的菜单。

您还可以将单元格表示的索引或对象(如果outlineView不是静态的)存储在局部变量中。

相关问题