Отслеживание мыши и события обновления курсора

Когда указатель мыши (без нажимаемой кнопки мыши) вводит и выходит из области окна, отслеживающие мышь сообщения отправляются в объект. Эта область известна как прямоугольник отслеживания или отслеживание области. Отслеживание мыши позволяет представлению, владеющему областью ответить, например, путем рисования цвета подсветки или отображения подсказки. События обновления курсора являются специальным видом отслеживающего мышь события, которое Набор Приложения обрабатывает автоматически. Когда указатель мыши вводит прямоугольник курсора, Набор Приложения выводит на экран изображение курсора, надлежащее типу представления под прямоугольником; например, когда указатель мыши вводит текстовое представление, курсор I-луча выведен на экран вместо этого.

Разделы в этой главе описывают, как Вы устанавливаете прямоугольники отслеживания и реагируете на отслеживающие мышь события. Они также обсуждают, как указать и управлять прямоугольниками для событий обновления курсора.

Обработка отслеживающих мышь событий

Область представления, установленного для отслеживания движения мыши, известна как прямоугольник отслеживания. Когда курсор мыши вводит прямоугольник отслеживания, Набор Приложения отправляет вводимые в мышь события (тип NSMouseEntered) к объекту, владеющему прямоугольником (который является не обязательно самим представлением); когда курсор оставляет прямоугольник, Набор Приложения отправляет объекту вышедшие мышью события (тип NSMouseExited). Эти события соответствуют mouseEntered: и mouseExited: методы, соответственно, NSResponder. Отслеживание мыши может быть полезно для таких задач как отображение контекстно-зависимых сообщений или выделение графических элементов под курсором. NSView объект может иметь любое число отслеживания прямоугольников, которые могут наложиться или быть вложены один в другом; NSEvent объекты, сгенерированные для представления отслеживающих мышь событий, включают тег (получил доступ через trackingNumber метод), который идентифицирует прямоугольник, связанный с событием.

Для создания прямоугольника отслеживания отправьте a addTrackingRect:owner:userData:assumeInside: обменивайтесь сообщениями к NSView объект связался с прямоугольником, как показано в Управлении Объектом области отслеживания. Этот метод регистрирует владельца для прямоугольника отслеживания, так, чтобы владелец получил сообщения о событиях отслеживания. Владелец обычно является самим объектом представления, но не должен быть. Метод возвращает тег прямоугольника отслеживания так, чтобы можно было сохранить его для дальнейшего использования в методах обработки событий mouseEntered: и mouseExited:. Для удаления прямоугольника отслеживания используйте removeTrackingRect: метод, берущий в качестве параметра тег прямоугольника отслеживания для удаления.

Перечисление a-1  , Добавляющее прямоугольник отслеживания к области представления

- (void)viewDidMoveToWindow {
    // trackingRect is an NSTrackingRectTag instance variable
    // eyeBox is a region of the view (instance variable)
    trackingRect = [self addTrackingRect:eyeBox owner:self userData:NULL assumeInside:NO];
}

В вышеупомянутом примере пользовательское представление включает прямоугольник отслеживания viewDidMoveToWindow метод вместо initWithFrame:. Несмотря на то, что NSView реализации addTrackingRect:owner:userData:assumeInside: метод, окно представления ведет список отслеживания прямоугольников. Когда представление initWithFrame: инициализатор вызывается, представление еще не связано с окном, таким образом, прямоугольник отслеживания еще не может быть добавлен к списку окна. Таким образом лучшее место для добавления прямоугольников отслеживания первоначально находится в viewDidMoveToWindow метод.

Отслеживающие прямоугольные границы являются содержащими для главных и левых краев, но не для базовых и правых краев. Таким образом, если у Вас есть незеркально отраженное представление с прямоугольником отслеживания, покрывающим его границы, и кадр представления имеет геометрию frame.origin = (100, 100), frame.size = (200, 200), тогда область, для которой прямоугольник отслеживания активен, frame.origin = (100, 101), frame.size = (199, 199), в координатах кадра.

Отслеживание прямоугольников может также использоваться для обеспечения NSMouseMoved события к представлениям в mouseMoved: метод. Для представления для получения NSMouseMoved события, однако, две вещи должны произойти:

Как отмечено в Объектах-событиях и Типах и Обрабатывающий События от нажатия мыши, NSWindow объект по умолчанию не получает NSMouseMoved события, потому что они могут легко лавинно разослать очередь событий. Если Вы только хотите получить перемещенные в мышь сообщения, в то время как мышь по Вашему представлению, необходимо выключить их снова, когда завершается отслеживающий мышь сеанс.

Вы обычно отправляете setAcceptsMouseMovedEvents: сообщение (с параметром YES) в Вашей реализации mouseEntered:. Если Вы хотите выключить их после того, как сеанс отслеживания заканчивается, можно отправить сообщение снова с параметром NO в Вашей реализации mouseExited:. Однако необходимо также задержать статус окна к тому, чем это было перед включением перемещенных в мышь событий, чтобы гарантировать, что окно не прекращает получать перемещенные в мышь события, если это хочет их для других целей.

Код отслеживания в Перечислении 6-2 используется в том, чтобы заставлять «глазное яблоко» следовать за перемещением указателя мыши, когда это вводит прямоугольник отслеживания. Обратите внимание на то, что mouseEntered: реализация использует wasAcceptingMouseEvents переменная экземпляра для получения текущего состояния окна в отношении перемещенных в мышь событий перед этими событиями включена для текущего сеанса отслеживания; позже, в mouseExited:, значение этой переменной экземпляра используется в качестве параметра setAcceptsMouseMovedEvents:, таким образом, сбрасывающий статус окна.

  Обработка перечисления a-2 вводимые в мышь, перемещенные в мышь, и вышедшие мышью события

- (void)mouseEntered:(NSEvent *)theEvent {
    wasAcceptingMouseEvents = [[self window] acceptsMouseMovedEvents];
    [[self window] setAcceptsMouseMovedEvents:YES];
    [[self window] makeFirstResponder:self];
    NSPoint eyeCenter = [self convertPoint:[theEvent locationInWindow] fromView:nil];
    eyeBox = NSMakeRect((eyeCenter.x-10.0), (eyeCenter.y-10.0), 20.0, 20.0);
    [self setNeedsDisplayInRect:eyeBox];
    [self displayIfNeeded];
}
 
- (void)mouseMoved:(NSEvent *)theEvent {
    NSPoint eyeCenter = [self convertPoint:[theEvent locationInWindow] fromView:nil];
    eyeBox = NSMakeRect((eyeCenter.x-10.0), (eyeCenter.y-10.0), 20.0, 20.0);
    [self setNeedsDisplayInRect:eyeBox];
    [self displayIfNeeded];
}
 
- (void)mouseExited:(NSEvent *)theEvent {
    [[self window] setAcceptsMouseMovedEvents:wasAcceptingMouseEvents];
    [self resetEye];
    [self setNeedsDisplayInRect:eyeBox];
    [self displayIfNeeded];
}

Поскольку отслеживающие прямоугольники сохраняются NSWindow объекты, прямоугольник отслеживания является статическим объектом; это не перемещает или изменяет свой размер когда NSView объект делает. При использовании прямоугольников отслеживания, несомненно, необходимо будет удалить и восстановить их при изменении прямоугольника кадра объекта представления, содержащего их. Если Вы создаете пользовательский подкласс NSView, можно переопределить setFrame: и setBounds: методы, чтобы сделать это, как показано в Проблемах совместимости. Если Ваш класс не является пользовательским классом представления, можно зарегистрировать экземпляр класса как наблюдатель для уведомление NSViewFrameDidChangeNotification и имейте его, восстанавливают прямоугольники отслеживания при получении уведомления.

Перечисление a-3  , Сбрасывающее прямоугольник отслеживания

- (void)setFrame:(NSRect)frame {
    [super setFrame:frame];
    [self removeTrackingRect:trackingRect];
    [self resetEye];
    trackingRect = [self addTrackingRect:eyeBox owner:self userData:NULL assumeInside:NO];
}
 
- (void)setBounds:(NSRect)bounds {
    [super setBounds:bounds];
    [self removeTrackingRect:trackingRect];
    [self resetEye];
    trackingRect = [self addTrackingRect:eyeBox owner:self userData:NULL assumeInside:NO];
}

Необходимо также удалить прямоугольник отслеживания, когда представление удалено из его окна, которое может произойти или потому что представление перемещено в различное окно, или потому что представление удалено как часть освобождения. Одно место, чтобы сделать это viewWillMoveToWindow: метод, как показано в Проблемах совместимости.

Перечисление a-4  , Удаляющее прямоугольник отслеживания, когда представление удалено из его окна

- (void)viewWillMoveToWindow:(NSWindow *)newWindow {
    if ( [self window] && trackingRect ) {
        [self removeTrackingRect:trackingRect];
    }
}

Управление событиями обновления курсора

Одно общее использование отслеживания прямоугольников должно изменить изображение курсора по различным типам графических элементов. Текст, например, обычно требует курсора I-луча. Изменение курсора является такой общей работой это NSView определяет несколько удобных методов упростить процесс. Прямоугольник отслеживания, сгенерированный этими методами, вызывают прямоугольником курсора. Сам Набор Приложения принимает владение прямоугольников курсора, так, чтобы, когда пользователь перемещает мышь через прямоугольник, курсор автоматически изменился на надлежащее изображение. В отличие от общих прямоугольников отслеживания, могут не частично наложиться прямоугольники курсора. Они могут, однако, быть полностью вложены, один в другом.

Поскольку прямоугольники курсора должны часто сбрасываться как размер представления и графическое изменение элементов, NSView определяет отдельный метод, resetCursorRects, это вызвало любое время, его прямоугольники курсора должны быть восстановлены. Конкретный подкласс переопределяет этот метод, вызывая addCursorRect:cursor: для каждого прямоугольника курсора это хочет установить (как проиллюстрировано в Перечислении a-5). После того прямоугольники курсора представления могут быть восстановлены путем вызова NSWindow метод invalidateCursorRectsForView:. Прежде resetCursorRects вызывается, представление владения автоматически отправляется a disableCursorRects сообщение для удаления существующих прямоугольников курсора.

Перечисление 6-4 показывает реализацию resetCursorRects.

Перечисление a-5  , Сбрасывающее прямоугольник курсора

-(void)resetCursorRects
{
    [self addCursorRect:[self calculatedItemBounds] cursor:[NSCursor openHandCursor]];
 
}

Несмотря на то, что можно временно удалить единственный прямоугольник курсора с removeCursorRect:cursor:, необходимо редко должны быть сделать так. Каждый раз, когда прямоугольники курсора должны быть восстановлены, NSView вызывает resetCursorRects так, чтобы можно было установить только необходимые прямоугольники курсора. Если Вы реализуете resetCursorRects таким образом можно тогда просто изменить состояние этот метод использование, чтобы создать его прямоугольники курсора и затем вызвать NSWindow метод invalidateCursorRectsForView:.

NSView прямоугольники курсора объекта автоматически сбрасываются каждый раз, когда:

Можно временно отключить все прямоугольники курсора в окне с помощью NSWindow метод disableCursorRects и включите им снова с enableCursorRects метод. areCursorRectsEnabled метод NSWindow говорит Вам, включают ли им в настоящее время.