NSTableView:检测鼠标点击以及行和列

Posted

技术标签:

【中文标题】NSTableView:检测鼠标点击以及行和列【英文标题】:NSTableView: detecting a mouse click together with the row and column 【发布时间】:2013-09-04 19:30:04 【问题描述】:

我试图检测何时在 NSTableView 中发生鼠标点击,以及何时发生,以确定被点击的单元格的行和列。

到目前为止我已经尝试过使用NSTableViewSelectionDidChangeNotification,但是有两个问题:

    它仅在选择更改时触发,而我希望每次鼠标点击,即使它在当前选定的行上。 调用我的委托时,NSTableView 的 clickedRow 和 clickedColumn 属性均为 -1。

有没有更好(和正确)的方法?

【问题讨论】:

【参考方案1】:

有一个简单的方法。

在 macOS 10.12.2 和 Xcode 8.2.1 上使用 Swift 3.0.2 测试

tableView.action = #selector(onItemClicked)

然后

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

【讨论】:

似乎是最好的答案。 一定要设置tableView.target 太棒了!这确实是最好的答案 如果你声明像@IBAction private func tableRowWasClicked(_ tableView: NSTableView)这样的方法,那么在你的XIB或故事板中,你可以将表格视图的action出口连接到方法而不是设置targetaction代码。 似乎这不仅是一个很好的答案,而且是它应该工作的方式。因为实现 mouseDown 和类似的方法必须处理当表格放置在 NSScrollView 内时发生移动的大量坐标。【参考方案2】:

捕捉用户点击一行(仅当用户点击一行时,而不是在以编程方式选择它时):

继承您的 NSTableView 并声明协议

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

处理鼠标按下事件(注意,当用户点击外部时不会调用委托回调,也许你也想处理,在这种情况下,只需注释掉条件“@987654322 @")

- (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];
    

让你的WC、VC符合ExtendedTableViewDelegate

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

将MyTableView的extendedDelegate设置为你的WC、VC(MyViewController)

MyTableView.m

中的某处
self.myTableView.extendedDelegate = self

在委托(MyViewController.m)中实现回调

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

【讨论】:

如何处理 mouseEntered & mouseExit 事件?有什么想法吗?【参考方案3】:

我更喜欢这样做。

覆盖

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

提供超级实现;

RequiredRow = row;
RequiredColumn = [tableView clickedColumn];

希望这会有所帮助。

【讨论】:

这不仅是由用户操作触发的,如问题“我试图检测何时在 NSTableView 中发生鼠标点击,以及何时发生,以确定行和列”中所述被点击的单元格”,而且每次选择以编程方式更改时 这也会在用户执行点击以外的操作时触发,例如在列表具有焦点时按空格键或键入字母键。【参考方案4】:

如果有人正在寻找 Peter Lapisu 答案的 Swift 3/4/5 版本:

为 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, from: 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)

然后要使用它,请确保实现新的委托协议:

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

@nonobjc 属性使关于它接近 didClick 的警告静音。

【讨论】:

它可以工作,但是当点击项目时,没有选择任何内容【参考方案5】:

以防万一有人在 SWIFT 和/或 NSOutlineView 中寻找它。

基于@Peter Lapisu 的说明。

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))
        
    

【讨论】:

mouseDown 不应出现在您的MYOutlineViewDelegate【参考方案6】:

查看 tableViewSelectionIsChanging 通知,这里是来自 NSTableView.h 的 cmets

/* 可选 - 在即将更改选择时调用,但请注意,tableViewSelectionIsChanging: 仅在鼠标事件更改选择而不是键盘事件时调用。 */

我承认这可能不是关联鼠标点击的最可靠方法,但这是另一个需要调查的领域,因为您对鼠标点击感兴趣。

【讨论】:

我不认为这涵盖了以下问题的要求:“我希望每次鼠标点击,即使它在当前选定的行上。”

以上是关于NSTableView:检测鼠标点击以及行和列的主要内容,如果未能解决你的问题,请参考以下文章

delphi中获取memo鼠标所在位置的行和列(通过EM_GETRECT消息取得Rect后,自己算一下)

当鼠标点到excel单元格时,单元格所在的行和列会自动显示颜色

怎么把表格扩大?

wps表格格子怎么放大

解决 table固定行和列,导致滚动条显示

Excel中怎么进行首行冻结?