Is there any way to add mouseOver events to a tableView in cocoa?
Asked Answered
K

3

5

I want to make my tableView act like this:
When the mouse swipe over a certain row, the row will be highlighted, just like the mouseOver event of a button

Krona answered 28/4, 2014 at 3:45 Comment(1)
I'm talking about Cocoa Application on mac, not ios ): @iPatelKrona
P
1

(Ignoring the "Mouse Over is bad GUI" sermon (which you'll ignore anyway… ;-))

#import "MoTableView.h"

@implementation MoTableView
{
    NSUInteger mouseRow;
    NSRect mouseRowFrame;
}

- (id)initWithFrame:(NSRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code here.
        mouseRow = -1;
    }
    return self;
}

- (void)awakeFromNib
{
    [self.window setAcceptsMouseMovedEvents:YES];
}

- (void)drawRect:(NSRect)dirtyRect
{
    [super drawRect:dirtyRect];

    // Drawing code here.
    [[NSColor redColor] set];
    NSLogDebug(@"mouseRowFrame: %@", NSStringFromRect(mouseRowFrame));
    NSFrameRectWithWidth(mouseRowFrame, 2.);
}

- (void)mouseMoved:(NSEvent *)theEvent
{
    NSPoint mouseLocation = [theEvent locationInWindow];
    NSPoint viewLocation = [self convertPoint:mouseLocation fromView:nil] ;
    NSInteger row = [self rowAtPoint:viewLocation];
    if (row != mouseRow) {
        mouseRowFrame = [self rectOfRow:row];
        [self setNeedsDisplay];
        mouseRow = row;
    }
}

@end
Parette answered 28/4, 2014 at 16:32 Comment(2)
Don’t know what to tell you; just tried it and it worked fine for me. :(Parette
Oh, I commented here and forgot. The above works for Cell-based TableView. I tried in View based. Later I was able to do it.Quinquefid
A
13

It took me some time to work on it based on this hint.

It works for me, correct me if I'm wrong.

Tested with Swift 3.0.2 on macOS 10.12.2 and Xcode 8.2.1

//
// Created by longkai on 30/12/2016.
// Copyright (c) 2016 xiaolongtongxue.com. All rights reserved.
//

import Cocoa

class InboxTableCellView: NSTableCellView {
    // MARK: - Outlets
    @IBOutlet weak var title: NSTextField!
    @IBOutlet weak var sender: NSTextField!
    @IBOutlet weak var time: NSTextField!
    @IBOutlet weak var snippet: NSTextField!

    // MARK: - Mouse hover
    deinit {
        removeTrackingArea(trackingArea)
    }

    private var trackingArea: NSTrackingArea!

    override func awakeFromNib() {
        super.awakeFromNib()
        self.trackingArea = NSTrackingArea(
            rect: bounds,
            options: [NSTrackingAreaOptions.activeAlways, NSTrackingAreaOptions.mouseEnteredAndExited,/* NSTrackingAreaOptions.mouseMoved */],
            owner: self,
            userInfo: nil
        )
        addTrackingArea(trackingArea)
    }

    override func draw(_ dirtyRect: NSRect) {
        super.draw(dirtyRect)

        NSColor(red: 0.96, green: 0.96, blue: 0.96, alpha: 1.00).set()

        // mouse hover
        if highlight {
            let path = NSBezierPath(rect: bounds)
            path.fill()
        }

        // draw divider
        let rect = NSRect(x: 0, y: bounds.height - 2, width: bounds.width, height: bounds.height)
        let path = NSBezierPath(rect: rect)
        path.fill()
    }

    private var highlight = false {
        didSet {
            setNeedsDisplay(bounds)
        }
    }

    override func mouseEntered(with event: NSEvent) {
        super.mouseEntered(with: event)
        if !highlight {
            highlight = true
        }
    }

    override func mouseExited(with event: NSEvent) {
        super.mouseExited(with: event)
        if highlight {
            highlight = false
        }
    }
}
Aubreir answered 30/12, 2016 at 17:41 Comment(2)
Is there any way to get the row's object and highlight the entire row? This answer almost works. But it only highlights the table cell and not the entire row.Cal
Well, THAT was easy... thanks!Typo
S
2

You need to create a subclass and use tracking areas. That's what buttons do to track mouse hovering.

There's an Apple Sample Code that does exactly what you need - highlighting rows on hover:

HoverTableDemo

It's been thoroughly discussed in WWDC 2011 Session 120

Satirize answered 29/4, 2014 at 8:28 Comment(0)
P
1

(Ignoring the "Mouse Over is bad GUI" sermon (which you'll ignore anyway… ;-))

#import "MoTableView.h"

@implementation MoTableView
{
    NSUInteger mouseRow;
    NSRect mouseRowFrame;
}

- (id)initWithFrame:(NSRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code here.
        mouseRow = -1;
    }
    return self;
}

- (void)awakeFromNib
{
    [self.window setAcceptsMouseMovedEvents:YES];
}

- (void)drawRect:(NSRect)dirtyRect
{
    [super drawRect:dirtyRect];

    // Drawing code here.
    [[NSColor redColor] set];
    NSLogDebug(@"mouseRowFrame: %@", NSStringFromRect(mouseRowFrame));
    NSFrameRectWithWidth(mouseRowFrame, 2.);
}

- (void)mouseMoved:(NSEvent *)theEvent
{
    NSPoint mouseLocation = [theEvent locationInWindow];
    NSPoint viewLocation = [self convertPoint:mouseLocation fromView:nil] ;
    NSInteger row = [self rowAtPoint:viewLocation];
    if (row != mouseRow) {
        mouseRowFrame = [self rectOfRow:row];
        [self setNeedsDisplay];
        mouseRow = row;
    }
}

@end
Parette answered 28/4, 2014 at 16:32 Comment(2)
Don’t know what to tell you; just tried it and it worked fine for me. :(Parette
Oh, I commented here and forgot. The above works for Cell-based TableView. I tried in View based. Later I was able to do it.Quinquefid

© 2022 - 2024 — McMap. All rights reserved.