Рисование в NSView внутри обработчика событий - PullRequest
0 голосов
/ 26 апреля 2018

Я перепробовал все, что мог, но не повезло.

У меня есть проект, который по сути является «интерпретатором» языка программирования. Таким образом, события передаются в цикл интерпретатора, интерпретированный код делает что угодно (в этом случае обновляет битовую карту памяти), затем цикл интерпретатора возвращается и возвращается обработчик событий. В конце концов вызывается drawRect приложения, и растровое изображение памяти обращается к NSView. Это все самое лучшее из того времени.

Но ... есть несколько ситуаций, когда интерпретируемый «код» хочет вызвать короткую анимацию, и делает это, обновляя битовую карту памяти, используя usleep () в течение нескольких миллисекунд, обновляя битовую карту памяти, usleep ( ) и т. д. Анимация занимает чуть меньше секунды, поэтому блокировка потоков не должна быть проблемой.

Проблема в том, что ни одна из анимаций не отображается, и экран не обновляется до тех пор, пока не истечет интерпретированный код, и событие не вернется.

Функция сна, которая вызывается, когда интерпретированный код указывает, что она хочет спать, выглядит следующим образом:

void KSleep(DWORD tm) {

    if( [pView lockFocusIfCanDraw] ) {
        inSleep = true;
        [pView setNeedsDisplay:YES];
        [pView display];
        [pView drawRect:NSMakeRect(0, 0, pView.frame.size.width, pView.frame.size.height)];
        [pView unlockFocus];
    }
    usleep(tm*1000);
}

'inSleep' - это глобальная переменная, которую я настроил для целей тестирования, 'pView' - это глобальный NSView * для единственного представления окна. ПРИМЕЧАНИЕ. Да, часть приведенного выше кода является избыточной, я просто включил ее, чтобы показать, что я пробовал многочисленные комбинации, пытаясь указать ОС, что представление грязное, и обновить его. Никто из них не работал.

Код drawRect (удаляющий весь код, который выполняет обычное перетаскивание растрового изображения) выглядит следующим образом:

-(void)drawRect:(CGRect)rect {

    CGContextRef context = [[NSGRaphicsContext currentContext] graphicsPort];
    CGContextSaveGState(context);
    if( inSleep ) CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1.0);
    else CGContextSetRGBFillColor(context, 1.0, 1.0, 0.0, 1.0);
    CGContextFillRect(context, CGRectMake(0,0,200,200));
    CGContextRestoreGState(context);
}

Итак:
1) Событие -mouseDown () происходит и вызывает интерпретатор с событием.
2) Интерпретированный код обращается к растровому изображению (я игнорирую это здесь, поскольку это не важно для работы или не работает обновления экрана), и вызывает 'sleep.'
3) Переводчик, увидев вызов сна, вызывает Ksleep () (см. Выше).
4) Ksleep блокирует фокус, который, кажется, создает контекст, поскольку без этого отладчик выдает предупреждения о контексте 0x0 во время функции drawRect (), а с помощью lockFocus он не имеет и, по-видимому, имеет допустимое значение контекста .
5) Ksleep помечает представление как нуждающееся в обновлении и вызывает (по-разному) «display» и / или «drawRect» и т. Д.
6) Процедура drawRect получает контроль (точки останова указывают, что в этом отношении все работает нормально). 'inSleep' установлен правильно. Он выполняет все действия в drawRect, как и ожидалось. Но НИЧЕГО не показывает на дисплее, пока ...
7) drawRect возвращается к Ksleep, время ожидания истекает, интерпретатор продолжает интерпретацию, интерпретированный код выполняет больше прорисовки и больше снов, примерно 10 раз (таким образом повторяя шаги 2-7 примерно 10 раз).

С момента запуска программы до тех пор, пока действие мыши не вызовет попытку «анимации», в представлении отображается желтый прямоугольник. Как только происходит щелчок мыши, вызывающий «анимацию», НИЧЕГО не обновляется в окне до тех пор, пока анимация полностью не завершится (хотя drawRect IS выполняется несколько раз в течение этой попытки анимации), ТОГДА прямоугольник становится синим. Но точки останова показывают, что выполнение проходит через drawRect (с true inSleep) каждый раз, когда вызывается подпрограмма KSleep ().

Это что-то нить? (Программа явно не создает никаких потоков.)

Я не особо ищу предложения о том, как избежать структуры анимации / KSleep, я понимаю, что это не самый предпочтительный метод работы Macos, но это попытка портировать старый проект из другого места и изменить ' интерпретировать код, чтобы избежать этого не представляется возможным.

Спасибо за любые идеи или предложения.

1 Ответ

0 голосов
/ 28 апреля 2018

Решение, которое я нашел, состояло в том, чтобы поместить ВСЕ код интерпретатора во второй поток, освобождая основной поток для возможности обновления отображения. Несмотря на то, что процедура drawRect работала и рисовала, она не отображалась на дисплее до тех пор, пока текущий цикл «интерпретация команд» не завершился и не вернулся. Эта страница содержит достаточное количество информации по теме: https://developer.apple.com/library/content/technotes/tn2133/_index.html

Кроме того, все «недействительные» вызовы / операторы должны были быть сохранены / помещены в общий «наименьший прямоугольник, который включает в себя все недействительные», а затем этот недействительный элемент был выполнен ПОСЛЕ «интерпретации команды», возвращенной перед И / ИЛИ сон () был сделан.

PITA.

...