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

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

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

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

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

【问题讨论】:

    标签: cocoa swift cell nstableview mouseclick-event


    【解决方案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: 仅在鼠标事件更改选择而不是键盘事件时调用。 */

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

    【讨论】:

    • 我不认为这涵盖了以下问题的要求:“我希望每次鼠标点击,即使它在当前选定的行上。”
    猜你喜欢
    • 2020-04-18
    • 2021-09-06
    • 2015-08-03
    相关资源
    最近更新 更多