FLEX: диалог не отображается сразу - PullRequest
4 голосов
/ 11 сентября 2009

В приложении AIR у меня есть следующий код:

theDialog = PopUpManager.createPopUp (this, TheDialogClass, true) как TheDialogClass; theDialog.addEventListener (FlexEvent.CREATION_COMPLETE, cpuIntensiveCalc);

В конце cpuIntensiveCalc диалог удаляется. Диалог информирует пользователя, что «что-то происходит, пожалуйста, подождите».

Проблема в том, что cpuIntensiveCalc запускается до рисования диалога. Таким образом, пользовательский опыт заключается в том, что приложение зависает на 10 секунд без индикатора, затем модальное диалоговое окно быстро мигает (менее секунды) на экране.

Документы Adobe говорят это о creation_complete

Отправляется, когда компонент завершает свою конструкцию, обработка свойств, измерение, макет и рисование.

Так что это похоже на правильное событие.
Во имя полноты я тоже попробовал

theDialog = PopUpManager.createPopUp (this, TheDialogClass, true) как TheDialogClass; cpuIntensiveCalc ();

Но были те же результаты.

ТИА

Ответы [ 3 ]

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

(у меня была такая же проблема =>, даже если эта ветка старая, я просто хотел предложить свое решение)

(отказ от ответственности: это немного уродливо, но говорят, что это нормально на уровне пользовательского интерфейса ... ;-))

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

=> Вы обычно выполняете свой код в потоке пользовательского интерфейса после того, как пользователь выполнил какое-то действие с виджетом. Любой вызов для обновления компонента пользовательского интерфейса (например, setProgress или setLabel) будет отображаться только на экране в конце цикла рендеринга (см. Снова жизненный цикл UiComponent).

=> В терминологии вызов "cpuIntensiveCalc" в callLater позволит инфраструктуре отобразить ваше всплывающее окно перед выполнением метода.

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

new MuchLaterRunner(popup, 7, cpuIntensiveCalc).runLater();

MuchLaterRunner определяется следующим образом:

public class MuchLaterRunner
    {
        var uiComp:UIComponent;
        var currentCounter = 0;
        var cyclesToWaitBeforeExecution=0;

        var command:Function;

        public function MuchLaterRunner(uiComp:UIComponent, cyclesToWaitBeforeExecution:uint, command:Function)
        {
            this.uiComp = uiComp;
            this.command = command;
            this.cyclesToWaitBeforeExecution =cyclesToWaitBeforeExecution;
        }

        public function runLater() {

            currentCounter ++;
            if (currentCounter >= cyclesToWaitBeforeExecution) {
                uiComp.callLater(command);
            } else {
                // wait one more cycle...
                uiComp.callLater(runLater);
            }
        }

    }

Проблема та же, что и при последующем вызове setProgress: мы должны разделить cpuIntensiveCalc на небольшие вызываемые методы, которые можно запускать в каждом цикле пользовательского интерфейса, в противном случае индикатор выполнения не будет ошибаться, прогресс.

1 голос
/ 11 сентября 2009

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

Время взлома ...

У вас есть два варианта.

(Это должно работать, но не проверено) Оберните вызов cpuIntensiveCalc () в callLater, чтобы пользовательский интерфейс мог завершить рендеринг, прежде чем блокировать рендеринг.

Или

Используйте «Зеленые потоки», чтобы прервать обработку, чтобы полностью не блокировать обработку пользовательского интерфейса. Взгляните .

0 голосов
/ 11 октября 2009

Использовать событие enterFrame во всплывающем окне. Не забудьте удалить прослушиватель в обработчике события enterFrame - в противном случае метод интенсивного использования процессора будет вызываться в каждом кадре, что приведет к сбою приложения. Если сначала это не работает, используйте частный номер в качестве счетчика и продолжайте увеличивать его в обработчике ввода кадра - вызывайте тяжелый метод процессора только тогда, когда счетчик достигнет соответствующего значения. Найдите «подходящее» значение по следам и ошибкам.

theDialog = PopUpManager.createPopUp(this, TheDialogClass, true) as TheDialogClass;
theDialog.addEventListener(Event.ENTER_FRAME, onEnterFrame);
private function onEnterFrame(e:Event):void
{
  //can use theDialog instead of e.currentTarget here.
  (e.currentTarget).removeEventListener(Event.ENTER_FRAME, onEnterFrame);
  cpuIntensiveCalc();
}
//in case the above method doesn't work, do it the following way:
theDialog.addEventListener(Event.ENTER_FRAME, onEnterFrame);
private var _frameCounter:Number = 0;
private function onEnterFrame(e:Event):void
{
  _frameCounter++;
  var desiredCount:Number = 1;//start with one - increment until it works.
  if(_frameCounter < desiredCount)
    return;
  //can use theDialog instead of e.currentTarget here.
  (e.currentTarget).removeEventListener(Event.ENTER_FRAME, onEnterFrame);
  cpuIntensiveCalc();
}
...