在NSTableCellView中滚动时跟踪鼠标事件的问题



我在自定义表格单元格视图中有弹出按钮,当鼠标光标移动到一个单元格上时,将显示该单元格的这些按钮,并且只有这一个单元格才会显示这些按钮。如果我慢慢移动鼠标光标,一切都能正常工作,但当我用鼠标中键快速滚动表格视图时,有太多的单元格显示为弹出按钮,这才是真正应该避免的。不知怎的,鼠标事件在滚动时没有被正确跟踪。我从苹果示例库中得到了这个跟踪代码。你能就这个问题提出一些建议吗?

#import "BasisCellView.h"
@implementation BasisCellView
- (void)drawRect:(NSRect)dirtyRect {
    [super drawRect:dirtyRect];
    // Drawing code here.
    [[NSImage imageNamed:@"background"] drawInRect:dirtyRect fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:0.1];
}
- (void)setBackgroundStyle:(NSBackgroundStyle)backgroundStyle {
    [super setBackgroundStyle: NSBackgroundStyleLight];
}
- (void)setMouseInside:(BOOL)value {
    if (mouseInside != value) {
        mouseInside = value;
        [self.deleteButton setHidden:!value];
        [self.bookmarkButton setHidden:!value];
        [self setNeedsDisplay:YES];
        NSLog(@"redrawn");
    }
}
- (BOOL)mouseInside {
    return mouseInside;
}
- (void)ensureTrackingArea {
    if (trackingArea == nil) {
        trackingArea = [[NSTrackingArea alloc] initWithRect:NSZeroRect options:NSTrackingInVisibleRect | NSTrackingActiveAlways | NSTrackingMouseEnteredAndExited owner:self userInfo:nil];
    }
}
- (void)updateTrackingAreas {
    [super updateTrackingAreas];
    [self ensureTrackingArea];
    if (![[self trackingAreas] containsObject:trackingArea]) {
        [self addTrackingArea:trackingArea];
    }
}
- (void)mouseEntered:(NSEvent *)theEvent {
    NSLog(@"1");
    self.mouseInside = YES;
}
- (void)mouseExited:(NSEvent *)theEvent {
    NSLog(@"0");
    self.mouseInside = NO;
}
@end

这是打印出来的日志:

2015-02-05 08:59:33.267 Clever[1286:25969] 1
2015-02-05 08:59:33.267 Clever[1286:25969] redrawn
2015-02-05 08:59:33.299 Clever[1286:25969] 0
2015-02-05 08:59:33.299 Clever[1286:25969] redrawn
2015-02-05 08:59:33.333 Clever[1286:25969] 1
2015-02-05 08:59:33.333 Clever[1286:25969] redrawn
2015-02-05 08:59:33.350 Clever[1286:25969] 0
2015-02-05 08:59:33.350 Clever[1286:25969] redrawn
2015-02-05 08:59:33.382 Clever[1286:25969] 1
2015-02-05 08:59:33.383 Clever[1286:25969] redrawn
2015-02-05 08:59:33.669 Clever[1286:25969] 1
2015-02-05 08:59:33.669 Clever[1286:25969] redrawn
2015-02-05 08:59:33.736 Clever[1286:25969] 1
2015-02-05 08:59:33.736 Clever[1286:25969] redrawn
2015-02-05 08:59:33.769 Clever[1286:25969] 0
2015-02-05 08:59:33.769 Clever[1286:25969] redrawn
2015-02-05 08:59:33.769 Clever[1286:25969] 1
2015-02-05 08:59:33.770 Clever[1286:25969] redrawn
2015-02-05 08:59:34.101 Clever[1286:25969] 1
2015-02-05 08:59:34.101 Clever[1286:25969] redrawn
2015-02-05 08:59:34.102 Clever[1286:25969] 0
2015-02-05 08:59:34.102 Clever[1286:25969] redrawn
2015-02-05 08:59:34.136 Clever[1286:25969] 0
2015-02-05 08:59:34.136 Clever[1286:25969] redrawn
2015-02-05 08:59:34.150 Clever[1286:25969] 1
2015-02-05 08:59:34.150 Clever[1286:25969] redrawn
2015-02-05 08:59:34.187 Clever[1286:25969] 1
2015-02-05 08:59:34.187 Clever[1286:25969] redrawn
2015-02-05 08:59:34.235 Clever[1286:25969] 1
2015-02-05 08:59:34.272 Clever[1286:25969] 0

以下是设置跟踪区域所需的代码的swift版本:

class MyCustomTableCellView: NSTableCellView {
    func setUpTrackingArea()
    {
        let trackingArea = NSTrackingArea(rect: self.frame, options: [NSTrackingAreaOptions.MouseEnteredAndExited, NSTrackingAreaOptions.ActiveAlways], owner: self, userInfo: nil)
        self.addTrackingArea(trackingArea)
    }
    override init(frame frameRect: NSRect) {
        super.init(frame: frameRect)
        setUpTrackingArea()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setUpTrackingArea()
    }
    override func mouseEntered(theEvent: NSEvent) {
        Swift.print("mouse Entered")
    }
    override func mouseExited(theEvent: NSEvent) {
        Swift.print("mouse exited")
    }
}

Reminders.app将NSTrackingArea用于cellView+控制器观察NSScrollViewWillStartLiveScrollNotification并在可见单元格中循环以隐藏按钮。

如果您不需要实时更新,并且可以立即隐藏视图/取消高亮显示,请使用NSScrollViewWillStartLiveScrollNotification

实时更新:

- (void)touchesMovedWithEvent:(NSEvent *)event;
[self setAcceptsTouchEvents:YES];

其他任何事情都可以通过多种解决方案进行自定义:例如,在控制器中使用NSCrollViewWillStartLiveScrollNotification+NSCrollView DidEndLiveScrollNotification,或者您根据需要覆盖滚动轮方法并触发鼠标事件:

CustomScrollView是向CustomTableRowView发送mouseEvents的视图,CustomTableRowView将其转发到其子视图。

#import <Cocoa/Cocoa.h>
@interface CustomScrollView : NSScrollView
@end
#import "CustomScrollView.h"
@implementation CustomScrollView
- (void)scrollWheel:(NSEvent *)theEvent
{
    NSPoint mouseLocation;
    NSInteger rowBefore = -1, rowAfter = -1;
    mouseLocation = [[self documentView] convertPoint:[theEvent locationInWindow] fromView:nil];
    rowBefore = [(NSTableView *)[self documentView] rowAtPoint:mouseLocation];
    @autoreleasepool {
        while ((theEvent = [[self window] nextEventMatchingMask:(NSScrollWheelMask)
                                                      untilDate:[NSDate distantFuture]
                                                         inMode:NSEventTrackingRunLoopMode
                                                        dequeue:YES]) &&
               !(([theEvent phase] & NSEventPhaseCancelled) || ([theEvent phase] & NSEventPhaseEnded))) {
            [super scrollWheel:theEvent];
        }
    }
    [super scrollWheel:theEvent];
    mouseLocation = [[self documentView] convertPoint:[theEvent locationInWindow] fromView:nil];
    rowAfter = [(NSTableView *)[self documentView] rowAtPoint:mouseLocation];
        if (rowBefore != -1) {
            NSTableRowView *rowViewBefore = [(NSTableView *)[self documentView] rowViewAtRow:rowBefore makeIfNecessary:NO];
            [rowViewBefore mouseExited:[NSApp currentEvent]];
        }
        if (rowAfter != -1) {
            NSTableRowView *rowViewAfter = [(NSTableView *)[self documentView] rowViewAtRow:rowAfter makeIfNecessary:NO];
            [rowViewAfter mouseEntered:[NSApp currentEvent]];
        }
}
@end

自定义表格行视图:

- (void)mouseEntered:(NSEvent *)event
{
    if (_inMouseEntered == NO) {
        _inMouseEntered = YES;
        [self setHighlighted:YES];
        for (NSView *view in [self subviews]) {
            if ([view isKindOfClass:[NSTableCellView class]]) {
                [view mouseEntered:event];
            }
        }
        [self setNeedsDisplay:YES];
        _inMouseEntered = NO;
    }
}
- (void)mouseExited:(NSEvent*)event
{
    if (_inMouseExited == NO) {
        _inMouseExited = YES;
        [self setHighlighted:NO];
        for (NSView *view in [self subviews]) {
            if ([view isKindOfClass:[NSTableCellView class]]) {
                [(NSTableCellView *)view mouseExited:event];
            }
        }
        [self setNeedsDisplay:YES];
        _inMouseExited = NO;
    }
}

不要忘记NSTrackingArea获取原始mouseEvents

这段代码可以在苹果的提醒应用程序中实现您想要的功能。如果仔细查看提醒应用程序,他们会在显示按钮之前进行一些延迟。我在表中添加了许多行,并在搜索时进行测试。

  #import "OTratingListTableCellView.h"
    @implementation OTratingListTableCellView
    @synthesize boatNameTextField,boatRatingTextField,boatStartTimeTextField,boatFinishTimeTextField,classTextField,popUpButton;
    - (void)drawRect:(NSRect)dirtyRect {
        [super drawRect:dirtyRect];

        NSTrackingArea *trackingArea = [[NSTrackingArea alloc] initWithRect:self.frame
                                                                    options: (NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow )
                                                                      owner:self userInfo:nil];
        [self addTrackingArea:trackingArea];
        // Drawing code here.
    }
    - (void)mouseEntered:(NSEvent *)theEvent
    {
        NSLog(@"mouseEntered");
        popUpButton.hidden=false;
    }
    - (void)mouseExited:(NSEvent *)theEvent
    {
        popUpButton.hidden=true;
        NSLog(@"mouseExited");  
    }
    @end

相关内容

  • 没有找到相关文章

最新更新