2013-08-29 1 views
2

Примечание: Обновление ниже ...Как я могу разрешить пользователю настраивать NSSlider без приостановки цикла обновления приложения?

У меня есть настольное приложение какао, которое состоит из ряда элементов управления вокруг пользовательских NSView. Я использую displayLink для управления обновлениями.

Когда пользователь нажимает на NSControl (слайдер, кнопка, флажок, радиокнопка), приложение оказывается замороженным до тех пор, пока мышь не будет отпущена. На самом деле я могу подтвердить, что обратный вызов displayLink (getFrameForTime) НЕ срабатывает в течение времени. Если я создаю таймер, который также не срабатывает, оба остаются приостановленными до тех пор, пока пользователь не освободит мышь, после чего приложение возобновит обновление.

Управление связано, и если я обновляю это значение из другого потока (например, через обратный вызов из MIDI-интерфейса), слайдер ведет себя так, как ожидалось: он перемещается, значение обновляется и приложение не приостанавливается.

Я чувствую, что это должно быть довольно очевидное решение, но я в тупике.

  • Проверка «непрерывный» в IB делает как рекламируется: посылает значения непрерывно, но по-прежнему демонстрирует такое поведение (предотвращает обновление пользовательского интерфейса), пока мышь не будет отпущен.

  • Это, по-видимому, связано конкретно с mouseDown on NSControl? Почему этот блок, и мне действительно нужно подклассифицировать все мои элементы пользовательского интерфейса, чтобы изменить это поведение (кажется экстремальным)

  • DisplayLink в своей нити, так почему mouseDown на основном потоке блокирует его? Если это так, то с учетом предписания об обновлении пользовательского интерфейса Cocoa из-за основного потока, как мне с ним справиться?

Любая помощь очень ценится.

Update

Per @ комментарии николаевские ниже, я могу подтвердить, что с помощью NSTimer и добавить его в NSEventTrackingRunLoopMode не блокирует. Тем не менее, я бы очень хотел использовать CVDisplayLink, который (согласно документации) работает в своем собственном потоке и не должен быть заблокирован таким образом. В отличие от CADisplayLink, я не могу найти способ явно назначить runloop CVDisplayLink (похоже, что это не работает), поэтому, возможно, новый вопрос должен быть:

Почему блок CVDisplayLink на NSEventTrackingRunLoopMode?

+1

Можете ли вы опубликовать минимальный пример проекта, который демонстрирует описанное поведение? –

+0

Несомненно, теперь это вместе ... – andrew

+0

Хорошо, проект здесь. Обратите внимание, что это очень минимально, он ничего не отображает (смотрите консоль для NSLog с таймера и с displayLink). Также обратите внимание, что слайдер ни к чему не подключен и ничего не делает: https://dl.dropboxusercontent.com/u /930604/Personal/DisplayLinkIssue.zip – andrew

ответ

2

Вашего тестового проекта показывает, что вы вызываете display метода представлены видом изнутри обратного вызова по ссылке дисплея.

При комментировании сообщения display линия отображения вызывается непрерывно даже при перемещении ползунка.

Так что не так, так это то, что когда runloop переходит в режим отслеживания событий, вызов display по блокам нитей на линии отображения до тех пор, пока мышь не будет отпущена, и цикл выполнения вернется в режим по умолчанию. Вы можете легко подтвердить это, поставив оператор журнала перед вызовом и один за ним.

Почему именно это случается, для меня непонятно. Ясно, что незаконно вызывать методы представления из фонового потока. Вы должны вызвать отображения окна путем диспетчеризации setNeedsDisplay: на главной теме:

static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now, const CVTimeStamp* outputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext) 
{ 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     [(__bridge MyCustomView*)displayLinkContext setNeedsDisplay:YES]; 
    }); 
    return kCVReturnSuccess; 
} 
+0

Огромное спасибо! 1. Странно. Но ... 2. Честно говоря, я не помню, почему я назвал отображение там (мой код начинался как яблочный шаблон и немного мутировал, когда я работал), мне это не нужно. Чрезвычайно благодарен за вашу помощь, это раздражало меня целую вечность. – andrew

+1

Добро пожаловать. Это один из тех случаев, когда действительно помогает [резиновая утка] (http://en.wikipedia.org/wiki/Rubber_duck_debugging). Иногда резиновая утка - ТАК. –

+1

Я только что заказал утку.: D И да ... ясно, что начало этого кода слишком долго не помогло. – andrew

3

При нажатии на NSControl режим runloop переходит от NSDefaultRunLoopMode в NSEventTrackingRunLoopMode до тех пор, пока мышь не работает. Это означает, что только запуск источников цикла (ссылка на изображение) и таймеров огонь, которые были добавлены в этот режим.

Вы можете добавить таймеры в любой режим, используя -[NSRunLoop addTimer:forMode:]. Для ссылки на изображение эквивалентным методом является -[CADisplayLink addToRunLoop:forMode:].

Чтобы сделать анимацию продолжаться во время отслеживания событий вы могли бы сделать что-то вроде:

[myDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] 
        forMode:NSEventTrackingRunLoopMode]; 
+0

Благодарим за то, что вы указали мне в хорошем направлении ... Это, похоже, описывает проблему (и очень помогает мне понять, что происходит), но я на OSX не iOs , поэтому я использую CVDisplayLink, а не CADisplayLink. CVDisplayLink https://developer.apple.com/library/mac/documentation/QuartzCore/Reference/CVDisplayLinkRef/Reference/reference.html не предлагает способ указать runloop. Я буду рыть. – andrew

+0

@ andrew О, я вижу. Прошло довольно много лет с тех пор, как я использовал это в Mac OS, и у меня создалось впечатление, что Apple добавила возможность использования Cocoa для использования ссылок на отображение. Это намного проще в iOS с красивой 'CADisplayLink'. Если я правильно помню, 'CVDisplayLink' использовал собственный поток для обратного вызова. Я не могу понять, почему цикл цикла должен влиять на это. Сожалею. –

+0

Я могу подтвердить, что это разрешает проблему для NSTimers, поэтому я уверен, что вы поставили диагноз проблемы, я просто повесил трубку на том, как получить доступ к объекту timerLink timer на MacOS (теперь можно прокручивать документы, но да, это кажется менее прямым чем это делает с CADisplayLink ..., который должен использовать свой собственный поток. hrm. Может быть, я просто портирую все на iphone;)) – andrew

Смежные вопросы