Проблема с отслеживанием события мыши при прокрутке в NSTableCellView
У меня есть поповерные кнопки в пользовательском представлении ячейки таблицы, и когда курсор мыши перемещается над одной ячейкой, эти кнопки ячейки будут отображаться, и только эта ячейка должна отображать кнопки. Если я медленно перемещаю курсор мыши, все работает правильно, но когда я прокручиваю табличное представление с помощью средней мыши, быстрее появляется слишком много ячеек с попсовыми кнопками, чего на самом деле следует избегать. Каким-то образом событие мыши не отслеживается правильно при прокрутке. Я получил этот код отслеживания из библиотеки примеров Apple. Не могли бы вы дать предложение по этому вопросу?
#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
3 ответа
Вот быстрая версия кода, необходимого для настройки области отслеживания:
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];
Все остальное настраивается с помощью нескольких решений: например, использование NSScrollViewWillStartLiveScrollNotification + NSScrollViewDidEndLiveScrollNotification в вашем контроллере или переопределение метода scrollWheel и запуск событий мыши, как вам нужно:
CustomScrollView - это тот, который отправляет mouseEvents в CustomTableRowView, а 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
CustomTableRowView:
- (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
Этот код делает именно то, что вы хотите в приложении Apple для напоминаний. Если внимательно посмотреть в приложении "Напоминания", они задерживают, прежде чем сделать кнопку видимой. Я добавляю много строк в таблицу и тестирую при прокрутке.
#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