Заставить Flex обновить экран?

Это может быть вопрос для новичков, но я не могу понять его.

Я использую flex для разработки графического интерфейса для большого проекта, в частности строки состояния внизу. В моем классе StatusBar есть ProgressBar, который другие классы, выполняющие работу, могут сообщать об обновлении (изменении завершения и метки панели) по мере продвижения. Проблема, с которой я сталкиваюсь, заключается в том, что flex не обновляет то, что отображается на экране, например, пока не станет слишком поздно.

ProgressBar инициализирован, готово 0%
какой-то класс устанавливает ProgressBar на 12% готово
какой-то класс выполняет некоторую работу
какой-то класс устанавливает ProgressBar на 56%

Что происходит, так это то, что 12% готово никогда не отображается, он просто зависает на 0% во время работы, а затем переходит сразу к 56% готово. Я пытался понять жизненный цикл гибкого компонента (недействительность и проверка), и я думаю, что понимаю это и применяю его правильно, но он вообще не работает. Мне нужно сказать flex, чтобы он перерисовал мой StatusBar (или, по крайней мере, ProgressBar внутри) после того, как some class установит его на 12%, но до того, как какой-то класс начнет выполнять свою работу . Как мне это сделать?


person Community    schedule 13.07.2009    source источник
comment
Эту проблему действительно следует рассматривать как разрешение Flex обновлять экран. Как указано ниже, Flash - это однопоточная модель выполнения вашего кода. Таким образом, вам нужно разбить вашу работу на части, позволяя игроку обновлять отображение между фрагментами. callLater () или использование таймеров для самостоятельного управления фрагментами - это основные доступные механизмы. Имейте в виду, что если вы не этого сделаете, браузер, скорее всего, отключит Flash-плеер через 45 секунд (по умолчанию FF).   -  person verveguy    schedule 11.08.2011


Ответы (6)


Как упоминалось в других ответах, флэш-плеер является однопоточным, если вы не разбиваете свою работу на отдельные фрагменты, которые могут выполняться в отдельных «кадрах», вы увидите скачки и заикания в пользовательском интерфейсе, что является эффективно то, что вы видите.

Если вы действительно должны увидеть это сообщение 12%, то этого недостаточно, чтобы сделать список отображения недействительным, поскольку список отображения не имеет возможности обновиться до тех пор, пока работа 56% не будет завершена, вы должны явно прервать цикл естественного события с помощью вызов validateNow() после того, как ваше сообщение было установлено.

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

person ianmjones    schedule 14.07.2009
comment
Я все еще не могу его получить, я вызываю invalidateDisplayList (), за которым сразу же следует validateNow (), и, похоже, он не обновляется. Мой класс StatusBar, а также ProgressBar и ProgressBarSkin объявляются недействительными, а затем проверяются, хотя он проходит весь путь и даже делает drawRect () для фактического перерисовки заполненной части ProgressBar, но на самом деле он все еще не обновляется. экран. - person ; 14.07.2009
comment
Вы пробовали callLater, setTimeout или что-то подобное, как я предлагал? Похоже, ваша обработка блокирует средство визуализации от обновления экрана. Вам нужно сделать паузу и дать ему вздохнуть. - person Glenn; 15.07.2009
comment
Ага! Поговорим о странности, я могу обновить его, когда захочу, используя setTimeout, если время для выполнения остальной части функции после setTimeout (doWork, X) займет меньше X. Другими словами, я должен отпустить вспышку в режиме ожидания (более 25 мс). Однако это ломается, если я помещаю точки останова не в то место или пытаюсь пройти через код. - person ; 16.07.2009

Гленн,

Это совсем не то, как работает многопоточность во Flex. Как и во многих пользовательских интерфейсах, у него есть насос сообщений в основном потоке пользовательского интерфейса (они делают это в кадрах). Когда вы вызываете callLater (), он помещает переданный указатель на функцию в конец очереди перекачки сообщений (в следующем кадре) и немедленно возвращается. Затем функция вызывается, когда насос сообщений завершает обработку всех сообщений ранее (например, щелчки мыши).

Проблема в том, что, поскольку изменение свойства вызывает запуск событий пользовательского интерфейса, они затем помещают свои собственные сообщения в насос, который теперь приходит после вызова вашего метода, который вы поместили туда из callLater ().

У Flex есть несколько потоков, но они существуют по собственным причинам Adobe и поэтому недоступны для пользователей. Я не знаю, есть ли способ гарантировать, что обновление пользовательского интерфейса произойдет в определенный момент, но есть возможность вызвать callLater несколько раз, пока операция не произойдет. Начните с небольшого числа и увеличивайте его, пока количество итераций не даст желаемого результата. Пример:

// Change this to a number that works... it will probably be over 1, depending on what you're doing.
private const TOTAL_CALL_COUNT:int = 5;

private var _timesCalled:int = 0;

//----------------------------------------------------------------
private function set Progress( progress:int ):void
{
    progressBar.value = progress;
    DoNextFunction();
}

//----------------------------------------------------------------
private function DoNextFunction():void
{
    if( _timesCalled >= TOTAL_CALL_COUNT )
    {
        _timesCalled = 0;
        Function();
    }
    else
    {
        _timesCalled++;
        callLater( DoNextFunction );
    }
}
person user337682    schedule 10.05.2010
comment
Вы неправильно понимаете мой ответ. В основном я говорил об AS3 / Flash, а не о Flex. callLater - это еще и реализация Flex. Он просто использует такие события, как ENTER_FRAME, для работы в фоновом режиме. - person Glenn; 28.07.2011
comment
Отключение callLater для setTimeout заставит его работать в AS3. - person Paul Keefe; 25.02.2012

Попробуйте вызывать invalidateDisplayList () после каждого изменения индикатора выполнения. Что-то типа :

Class StatusBar
{

    public function set progress(value:uint):void
    {
        progressBar.value = value;
        progressBar.invalidateDisplayList();
    }
}

Flex имеет цикл аннулирования, который позволяет избежать перерисовки экрана при каждом изменении свойства. Например, если значение свойства изменяется 3 раза за один кадр, оно будет отображаться только с последним установленным значением. Вы можете принудительно перерисовать компонент, вызвав invidateDisplayList (), что означает, что updateDisplayList будет выполняться немедленно, а не ждать следующего кадра.

person Florian F    schedule 13.07.2009
comment
На самом деле он не вызовет updateDisplayList () сразу, но вызовет его при следующем обновлении экрана / кадре. Если бы он сделал это немедленно, это бы как бы нарушило суть модели недействительности / валидации. - person cliff.meyers; 14.07.2009
comment
Мое плохое, вы абсолютно правы. Вместо вызова invalidateDisplayList () вы должны напрямую вызывать updateDisplayList () - person Florian F; 14.07.2009

ActionScript в Flash Player, как и Javascript в браузере, является псевдопоточным. То есть они однопоточные, но имеют несколько стеков выполнения. Это означает, что вы не можете «засыпать» в конкретном потоке, но вы можете создать новый стек выполнения, который откладывается на более позднее время. Гибкий способ сделать это - функция callLater. Вы также можете использовать функции setTimeout / setInterval. Или вы можете использовать объект таймера, встроенный во флеш-плеер. Или даже прослушиватель событий "ENTER_FRAME". Все это по сути позволит вам делать то, что вам нужно, если я прав в отношении причины ваших проблем.

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

Проблема может заключаться в том, что говорит PeZ, но если это не поможет, вы можете попробовать отложенные вызовы для рабочих классов. Теперь ваш процесс может выглядеть так:

  1. Прогресс инициализирован.
  2. Поработай немного.
  3. Обновить индикатор выполнения до 12. (сделать список отображения недействительным)
  4. setTimeout (doMoreWork, 100);
  5. Обновите индикатор выполнения до 52.

(если ваш worker является UIcomponent, вы можете использовать uicomp.callLater (...), в противном случае вам нужно использовать setTimeout / timers / enter_frame для чистых классов AS3).

person Glenn    schedule 13.07.2009

Иногда его необходимо установить в ноль, прежде чем присвоить другое значение. progressBar.setProgress (0, progressBar.maximum); progressBar.setProgress (newValue, progressBar.maximum);

person Yury Euceda    schedule 15.04.2015

Я использую Flash Builder 4.6, и у меня также есть проблема с отображением индикатора выполнения. Я открываю новое окно, в котором запускаю новый класс мультизагрузчика (39 Мо контента). Новое окно открывается в фоновом режиме, а в главном окне отображается индикатор выполнения, пока класс мультизагрузчика не завершит свою работу. Однако открывающееся окно блокирует анимацию моего главного окна. Я знаю, что это не класс мультизагрузчика, потому что я видел, что он работает правильно.

Но я постараюсь найти новые способы сделать это.

Основная цель моего поста - это сложность, которую Adobe построил вокруг flash. Когда вы ищете ресурсы для своего собственного приложения или ответы на свои вопросы, найти хороший ресурс очень сложно. Существует полная путаница (на стороне Adobe и на стороне пользователя) между AS3, Flex, Flash CS, Flash Builder, AiR, ... Если вы попытаетесь разработать в AS3, вы обнаружите, что некоторые примеры не работают для вы, потому что это не реализовано в вашем SDK. У вас появляется все больше и больше форумов, дающих вам «лучшие практики» или ироничные ответы, основанные на опыте использования различных платформ для разработки.

Например, прямо здесь, выше, я вижу progressBar.value = value; По своему опыту могу сказать, что в Flash Builder 4.6 это свойство доступно только для чтения. Но это может быть специальный класс, созданный пользователем, но кто может сказать.

person XcentY    schedule 23.12.2013