NSTableView: detecting a mouse click together with the row and column

对着背影说爱祢 提交于 2019-12-28 09:18:19

问题


I'm trying to detect when a mouse click occurs in an NSTableView, and when it does, to determine the row and column of the cell that was clicked.

So far I've tried to use NSTableViewSelectionDidChangeNotification, but there are two problems:

  1. It only triggers when the selection changes, whereas I want every mouse click, even if it is on the currently selected row.
  2. The clickedRow and clickedColumn properties of NSTableView are both -1 when my delegate is called.

Is there a better (and correct) way of doing this?


回答1:


To catch the user clicking a row (only, when the user clicks a row, not when it is selected programmatically) :

Subclass your NSTableView and declare a protocol

MyTableView.h

@protocol ExtendedTableViewDelegate <NSObject>

- (void)tableView:(NSTableView *)tableView didClickedRow:(NSInteger)row;

@end

@interface MyTableView : NSTableView

@property (nonatomic, weak) id<ExtendedTableViewDelegate> extendedDelegate;

@end

MyTableView.m

Handle the mouse down event (note, the delegate callback is not called when the user clicks outside, maybe you want to handle that too, in that case, just comment out the condition "if (clickedRow != -1)")

- (void)mouseDown:(NSEvent *)theEvent {

    NSPoint globalLocation = [theEvent locationInWindow];
    NSPoint localLocation = [self convertPoint:globalLocation fromView:nil];
    NSInteger clickedRow = [self rowAtPoint:localLocation];

    [super mouseDown:theEvent];

    if (clickedRow != -1) {
        [self.extendedDelegate tableView:self didClickedRow:clickedRow];
    }
}

Make your WC, VC conform to ExtendedTableViewDelegate.

@interface MyViewController : DocumentBaseViewController<ExtendedTableViewDelegate, NSTableViewDelegate,  NSTableViewDataSource>

set the extendedDelegate of the MyTableView to your WC, VC (MyViewController)

somewhere in MyTableView.m

self.myTableView.extendedDelegate = self

Implement the callback in delegate (MyViewController.m)

- (void)tableView:(NSTableView *)tableView didClickedRow:(NSInteger)row {
    // have fun
}



回答2:


There is a simple way.

Tested with Swift 3.0.2 on macOS 10.12.2 and Xcode 8.2.1

Let

tableView.action = #selector(onItemClicked)

Then

@objc private func onItemClicked() {
    print("row \(tableView.clickedRow), col \(tableView.clickedColumn) clicked")
}



回答3:


I would prefer doing as follows.

Override

-(BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row;

Provide super implementation;

RequiredRow = row;
RequiredColumn = [tableView clickedColumn];

Hope this helps.




回答4:


If someone is looking for a Swift 3 version of Peter Lapisu's answer.

Add an extension for the NSTableView (NSTableView+Clickable.swift):

import Foundation
import Cocoa

extension NSTableView {
    open override func mouseDown(with event: NSEvent) {
        let globalLocation = event.locationInWindow
        let localLocation = self.convert(globalLocation, to: nil)
        let clickedRow = self.row(at: localLocation)

        super.mouseDown(with: event)

        if (clickedRow != -1) {
            (self.delegate as? NSTableViewClickableDelegate)?.tableView(self, didClickRow: clickedRow)
        }
    }
}

protocol NSTableViewClickableDelegate: NSTableViewDelegate {
    func tableView(_ tableView: NSTableView, didClickRow row: Int)
}

Then to use it, make sure you implement the new delegate protocol:

extension MyViewController: NSTableViewClickableDelegate {
    @nonobjc func tableView(_ tableView: NSTableView, didClickRow row: Int) {
        Swift.print("Clicked row \(row)")
    }
}

The @nonobjc attribute silences the warning about it being close to didClick.




回答5:


Just in case someone was looking for it in SWIFT and / or for NSOutlineView.

Based on @Peter Lapisu instructions.

class MYOutlineViewDelegate: NSOutlineView, NSOutlineViewDelegate,NSOutlineViewDataSource{
//....
}    
extension MYOutlineViewDelegate{
    func outlineView(outlineView: NSOutlineView, didClickTableRow item: AnyObject?) {
        //Click stuff
    }

    override func mouseDown(theEvent: NSEvent) {
        let globalLocation:NSPoint  = theEvent.locationInWindow
        let localLocation:NSPoint  = self.convertPoint(globalLocation, fromView: nil)
        let clickedRow:Int = self.rowAtPoint(localLocation)

        super.mouseDown(theEvent)

        if (clickedRow != -1) {
            self.outlineView(self, didClickTableRow: self.itemAtRow(clickedRow))
        }
    }}



回答6:


see the tableViewSelectionIsChanging notification, here are the the comments from NSTableView.h

/* Optional - Called when the selection is about to be changed, but note, tableViewSelectionIsChanging: is only called when mouse events are changing the selection and not keyboard events. */

I concede that this might not be the surest way to correlate your mouse clicks, but it is another area to investigate, seeing that you are interested in mouse clicks.



来源:https://stackoverflow.com/questions/18560509/nstableview-detecting-a-mouse-click-together-with-the-row-and-column

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!