Подведите подпредставление к верху на mouseDown: И продолжайте получать события (для перетаскивания) - PullRequest
2 голосов
/ 01 января 2011

Хорошо, в основном у меня есть представление с серией слегка перекрывающихся подпредставлений.Когда щелкается подпредставление, оно перемещается вверх (среди прочего) по-настоящему простому двухслойному режиму:

-(void)mouseDown:(NSEvent *)theEvent {
  if (_selected) { // Don't do anything this subview is already in the foreground
    return;
  }
  NSView *superview = [self superview];
  [self removeFromSuperview];
  [superview addSubview:self positioned:NSWindowAbove relativeTo:nil];
}

Это прекрасно работает и кажется «нормальным» способом сделать это.

Проблема в том, что я сейчас ввожу некоторую логику перетаскивания в представление, поэтому мне нужно ответить на -mouseDragged:.К сожалению, поскольку представление удалено из иерархии представлений и повторно добавлено в процессе, я не могу заставить представление выйти на передний план и перетаскивать его одним и тем же действием мыши.Он получает mouseDown:, но никогда не получает mouseDragged: или любые последующие события.Он тянется, только если я оставляю кнопку мыши и снова щелкаю на представлении, поскольку второй щелчок не делает никаких манипуляций с иерархией представлений.

Могу ли я что-нибудь сделать, что позволит представлению перейти кна переднем плане, как это, И продолжайте получать последующие события -mouseDragged: и -mouseUp:, которые следуют?

Я начал с мысли о том, чтобы переопределить -hitTest: в суперпредставлении и перехватывать событие mouseDown по порядку.чтобы вывести вид на передний план до , он фактически получает событие.Проблема в том, что из -hitTest: как мне определить тип события, для которого я на самом деле выполняю тест на попадание?Я не хотел бы перемещать подпредставление на передний план для других событий мыши, таких как mouseMoved и т. Д.

UPDATE |Я действительно сделал это, в своем супервизоре, но это похоже на действительно плохой запах кода, вызывающий событие с -hitTest: напрямую.

-(NSView *)hitTest:(NSPoint)aPoint {
    NSView *view = [super hitTest:aPoint];
    if ([view isKindOfClass:[EDTabView class]] && ![(EDTabView *)view isActive]) {
        // Effectively simulate two mouseDown events in sequence for this special case
        [view mouseDown:nil]; // Works because I know too much about the implementation
    }
    return view;
}

Есть две вещи, которые кажутся неправильными в этом.Самое большое - это то, что я выполняю действие до того, как -hitTest: даже вернулся, а затем выполняю как обработано AppKit после того, как -hitTest: завершено.Во-вторых, у меня нет события для передачи, поэтому я передаю ноль.В этом случае это работает, так как я знаю, что обработчик событий на самом деле не обрабатывает какие-либо данные о событиях, но он не очень хорош.Альтернативой было перенести всю логику в суперпредставление, но разделение проблем здесь кажется еще хуже.

ОБНОВЛЕНИЕ |Этот -hitTest: хак не работает ... он срабатывает, когда я не делаю щелчок мышью, например, когда я перетаскиваю что-то поверх окна просмотра.Все еще ищите хорошее решение этой проблемы.

Ответ может буквально указать, как представление может покинуть и повторно ввести свое суперпредставление во время операции перетаскивания, или (возможно, более элегантный) альтернативный способ перемещениявид на передний план, отличный от [view removeFromSuperview]; [superview addSubview:view ...];.

Ответы [ 3 ]

4 голосов
/ 02 января 2011

Хорошо, я вышел по прихоти и попробовал что-то нелогичное.

Вместо этого, чтобы переместить взгляд на передний план:

[theView removeFromSuperview];
[theSuperview addSubview:theView positioned:NSWindowAbove relativeTo:nil];

Я просто отбросил строку removeFromSuperviewинтересно, что же на самом деле делает AppKit, если вы дважды пытаетесь добавить представление к суперпредставлению (я предполагал, что оно обеспечивает защиту от этого).

Он работает, по крайней мере, под Snow Leopard, и решает множество проблем.,Представление, уже присутствующее в суперпредставлении, не добавлено , как предполагает название метода, но оно действительно устанавливает свою позицию без необходимости сначала удалять его из суперпредставления.

1 голос
/ 20 января 2014

Для программного запуска событий мыши вы можете использовать Выполнение двойного щелчка с помощью CGEventCreateMouseEvent ()

CGEventRef ourEvent = CGEventCreate(NULL); //save the mouse event to track location
PostMouseEvent(kCGMouseButtonLeft, NX_LMOUSEDOWN, CGEventGetLocation(ourEvent));

void PostMouseEvent(CGMouseButton button, CGEventType type, const CGPoint point)
{
   CGEventRef theEvent = CGEventCreateMouseEvent(NULL, type, point, button);
   CGEventSetType(theEvent, type);
   CGEventPost(kCGHIDEventTap, theEvent);
   CFRelease(theEvent);
}

Если у вас много движущегося контента, вы должны даже позвонить CGEventCreate(NULL); дооперация и, возможно, даже сделать что-то вроде:

CGEventRef ourEvent = CGEventCreate(NULL);

//Some long operation

CGEventRef dragEvent = CGEventCreate(NULL);
PostMouseEvent(kCGMouseButtonLeft, NX_LMOUSEDOWN, CGEventGetLocation(ourEvent));
PostMouseEvent(kCGMouseButtonLeft, NX_LMOUSEDRAGGED, CGEventGetLocation(dragEvent));

Это дает иллюзию пользователю перетаскивать элементы, даже если они перемещаются из суперпредставления в другое.

0 голосов
/ 28 марта 2012

Я нашел ваш пост, так как у меня была та же проблема (довольно раздражающая вещь, кстати). Правильным решением является сортировка подпредставлений, используя собственную функцию сравнения. В родительском представлении вызовите -sortSubviewsUsingFunction: context: method.

...