简体   繁体   中英

NSWindow.contentView.hittest() Doesn't Reach Subviews of NSOutlineView

My app's window has a splitview with three panes; the leftmost pane hosts a view-based outline view.

When I click somewhere on that outline view, I want to determine the bottom-most subview in the hierarchy that was clicked. That is, which row, which cell, and ultimately which subview (control) of the cell was clicked.

I tried overriding mouseDown(with:) on the hosting view controller, but it isn't called; I suspected the outline view somehow is hogging the event so instead I decided to override the method directly on my NSOutlineView subclass itself. This works. However, from there I can not go any further down the hierarchy than the outline view itself:

class MyOutlineView: NSOutlineView {

override func mouseDown(with event: NSEvent) {
    if let view = self.window?.contentView?.hitTest(event.locationInWindow) {
        Swift.print("\(view.className)")
    }
}

...prints:

MyModule. MyOutlineView

The documentation for hittest() reads:

Returns the farthest descendant of the view in the view hierarchy (including itself) that contains a specified point, or nil if that point lies completely outside the view. This method is used primarily by an NSWindow object to determine which view should receive a mouse-down event. You'd rarely need to invoke this method, but you might want to override it to have a view object hide mouse-down events from its subviews. This method ignores hidden views.

How can I hit-test the topmost subviews of the outline view?

mouseDown(with:) is called on views, not on controllers. Usually the control inside the outline view handles the mouseDown.

But if you want to find the control, yes, -[NSTableView(NSTableViewRowHeaderSupport) hitTest:] messes things up. Workaround: get the row and the column, get the cell view and call hitTest on the cell view.

override func mouseDown(with event: NSEvent) {
    let localPoint = self.convert(event.locationInWindow, from: nil)
    let column = self.column(at: localPoint)
    let row = self.row(at: localPoint)
    if column >= 0 && row >= 0 {
        if let cellView = self.view(atColumn: column, row: row, makeIfNecessary: false) {
            if let cellSuperViewPoint = cellView.superview?.convert(localPoint, from: self) {
                if let view = cellView.hitTest(cellSuperViewPoint) {
                    Swift.print("\(view.className)")
                }
            }
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM