NSButton Subclass, который реагирует на щелчок правой
Вопрос
У меня есть подкласс NSButton, который я хотел бы сделать с нажатием на кнопку правой мыши. Просто перегрузка -rightMouseDown:
Не вырезал его, так как я хотел бы такого же поведения, как и для обычных щелчков (например, кнопка нажата, пользователь может отменить, оставив кнопку, действие отправляется при выпуске мыши и т. Д.).
То, что я пробовал до сих пор, это перегрузка -rightMouse{Down,Up,Dragged}
, изменение событий, чтобы указать на нажатие кнопки левой мыши, а затем отправить их на -mouse{Down,Up,Dragged}
. Анкет Теперь это было бы в лучшем случае взломом, и, как оказалось, Mac OS X не понравилось все это. Я могу нажать кнопку, но после выпуска кнопка остается нажатой.
Я мог бы имитировать поведение сам, что не должно быть слишком сложным. Тем не менее, я не знаю, как заставить кнопку выглядеть нажатой.
Прежде чем вы скажете: «Не так! Это нетрадиционное поведение Mac OS X, и его следует избегать»: я рассмотрел это, и щелчок правой кнопку может значительно улучшить рабочий процесс. По сути, кнопка цикла в 4 состояниях, и я хотел бы, чтобы правой щелкнули, чтобы сделать его цикла в обратном направлении. Это не важная особенность, но это было бы неплохо. Если вам все еще хочется сказать: «Не так!», Дайте мне знать ваши мысли. Я ценю это!
Спасибо!
РЕДАКТИРОВАТЬ: Это была моя попытка изменить событие (вы не можете изменить этот тип, поэтому я сделал новую, копировав всю информацию. Я имею в виду, я знаю, что это структура, явно говорит мне, что не делайте этого, но Я попробовал, как и вы):
// I've contracted all three for brevity
- (void)rightMouse{Down,Up,Dragging}:(NSEvent *)theEvent {
NSEvent *event = [NSEvent mouseEventWithType:NSLeftMouse{Down,Up,Dragging} location:[theEvent locationInWindow] modifierFlags:[theEvent modifierFlags] timestamp:[theEvent timestamp] windowNumber:[theEvent windowNumber] context:[theEvent context] eventNumber:[theEvent eventNumber] clickCount:[theEvent clickCount] pressure:[theEvent pressure]];
[self mouse{Down,Up,Dragging}:event];
}
Обновление: я заметил, что -mouseUp:
Никогда не отправляли в NSButton, и если я изменил его на NSControl, это было. Я не мог понять, почему это было, пока Фрэнсис МакГрю не указал, что он содержит свой собственный цикл обработки событий. Теперь это также имело смысл, почему, прежде чем я смог перенаправить -rightMouseDown:
, но кнопка не будет выпущена. Это связано с тем, что он сам забрал новые события, которые я не мог перехватывать и преобразовать из -за правой к левой кнопке мыши.
Решение
NSButton входит в петлю отслеживания мыши. Чтобы изменить это, вам придется подключить NSButton и создать свой собственный цикл отслеживания. Попробуйте этот код:
- (void) rightMouseDown:(NSEvent *)theEvent
{
NSEvent *newEvent = theEvent;
BOOL mouseInBounds = NO;
while (YES)
{
mouseInBounds = NSPointInRect([newEvent locationInWindow], [self convertRect:[self frame] fromView:nil]);
[self highlight:mouseInBounds];
newEvent = [[self window] nextEventMatchingMask:NSRightMouseDraggedMask | NSRightMouseUpMask];
if (NSRightMouseUp == [newEvent type])
{
break;
}
}
if (mouseInBounds) [self performClick:nil];
}
Вот как я это делаю; Надеюсь, это сработает для вас.
Другие советы
Я перевернул левую мышь, которая нажимает на щелчок в фальшивую правую мышь на контроле пути. Я не уверен, что это решит все ваши проблемы, но я обнаружил, что ключевым отличием, когда я это сделал, было изменение временной метки:
NSEvent *event = [NSEvent mouseEventWithType:NSLeftMouseDown
location:[theEvent locationInWindow]
modifierFlags:[theEvent modifierFlags]
timestamp:CFAbsoluteGetTimeCurrent()
windowNumber:[theEvent windowNumber]
context:[theEvent context]
// I was surprised to find eventNumber didn't seem to need to be faked
eventNumber:[theEvent eventNumber]
clickCount:[theEvent clickCount]
pressure:[theEvent pressure]];
Другое дело, что в зависимости от типа кнопки, его state
Может быть, значение, которое делает его появлением или нет, так что вы могли бы попытаться ковыпать это.
Обновление: я думаю, что выяснил, почему rightMouseUp:
никогда не вызывается. В соответствии с -[NSControl mouseDown:]
Документы, кнопка начинает отслеживать мышь, когда получает mouseDown
событие, а это не так остановка отслеживание, пока не получится mouseUp
. Анкет Пока он отслеживает, он не может сделать ничего другого. Я только что попробовал, например, в конце обычая mouseDown:
:
[self performSelector:@selector(mouseUp:) withObject:myFakeMouseUpEvent afterDelay:1.0];
Но это откладывается до нормального mouseUp:
Получил какой -то другой путь. Итак, если вы нажали правильную кнопку мыши, вы не можете (с мышью) отправить leftMouseUp
, таким образом, кнопка все еще отслеживается и не примет rightMouseUp
мероприятие. Я до сих пор не знаю, каково это решение, но я подумал, что это будет полезной информации.
Не так много, чтобы добавить к ответам выше, но для тех, кто работает в Swift, у вас могут возникнуть проблемы с поиском констант для маски событий, похороненных глубоко в документации, и еще больше проблем с поиском способа объединения (или) их в некотором роде что компилятор принимает, так что это может сэкономить вам некоторое время. Есть более аккуратный путь? Это идет в вашем подкласс -
var rightAction: Selector = nil
// add a new property, by analogy with action property
override func rightMouseDown(var theEvent: NSEvent!) {
var newEvent: NSEvent!
let maskUp = NSEventMask.RightMouseUpMask.rawValue
let maskDragged = NSEventMask.RightMouseDraggedMask.rawValue
let mask = Int( maskUp | maskDragged ) // cast from UInt
do {
newEvent = window!.nextEventMatchingMask(mask)
}
while newEvent.type == .RightMouseDragged
Моя петля стала доходом ... хотя, поскольку он всегда должен выполнять хотя бы один раз, и мне никогда не нравилось писать while true
, и мне не нужно ничего делать с событиями перетаскивания.
У меня были бесконечные проблемы с получением значимых результатов из Convertrect (), возможно, потому, что мои элементы управления были встроены в представление таблицы. Благодаря Густаву Ларссону выше за то, что я закончил с этим для последней части -
let whereUp = newEvent.locationInWindow
let p = convertPoint(whereUp, fromView: nil)
let mouseInBounds = NSMouseInRect(p, bounds, flipped) // bounds, not frame
if mouseInBounds {
sendAction(rightAction, to: target)
// assuming rightAction and target have been allocated
}
}