В моем приложении Flex4 панель вкладок используется следующим образом:

<s:TabBar id="tabs"/>
    <mx:ViewStack id="vs" height="100%" width="100%">
        <s:NavigatorContent label="Tab 1"  width="100%" height="100%">
            ...
        </s:NavigatorContent>
        <s:NavigatorContent label="Tab 2"  width="100%" height="100%">
            ...
        </s:NavigatorContent>
        <s:NavigatorContent label="Tab 3"  width="100%" height="100%">
            ...
        </s:NavigatorContent>
    </mx:ViewStack>
</s:TabBar>

По умолчанию приложение открывается с вкладкой 1. Вкладка 2 еще не построена.

Проблема в том, что когда я меняю вкладки на вкладку 2, Flex очень долго создает компоненты пользовательского интерфейса вкладки 2 и отображает содержимое вкладки. Приложение в основном зависает во время этого процесса. Мне нужно указать пользователю, что ему нужно подождать несколько секунд.

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

Я хотел бы просто отображать окно заголовка во время создания вкладки. Но я не знаю, как запустить его, когда я переключаю вкладку, так что окно заголовка появляется раньше и во время создания вкладки 2.

Я знаю, что mx ViewStack может иметь свойство change="", но когда я использую его, окно заголовка не появляется, пока вкладка 2 не завершит загрузку.

Я не уверен, как реализовать функцию callLater() в приведенном ниже сценарии.

Может ли кто-нибудь помочь мне выяснить, как вызвать окно заголовка, чтобы оно отображалось до и во время сборки вкладки 2?

Ссылки:

Как мы реализуем экран «Пожалуйста, подождите…» в гибком режиме, когда приложение занято

Flex: ищу шаблон проектирования для отображения курсора "занято", когда мое приложение "занято"

ОБНОВЛЕНИЕ 1:

С помощью комментария createDeferredContent Дэвида ниже и комментария setTimeout от weltraumpirat в моем предыдущем сообщении, ссылка на который приведена выше, я смог взломать решение, в результате которого во время загрузки содержимого вкладки 2 отображался занятый курсор. Вот что я сделал:

Создайте вкладку 2 как компонент, реализующий следующее:

<s:VGroup 
    ...
    preinitialize="preinit"
    creationComplete="start1">

    private function preinit():void {
        mx.managers.CursorManager.setBusyCursor();
    }

    private function start1():void {
        setTimeout(start2,100);
    }

    private function start2():void {
        // create mxml components
        myBC.createDeferredContent();

        // place any required actionscript code here
        mx.managers.CursorManager.removeBusyCursor();
    }

    ...

    <s:BorderContainer id="myBC" creationPolicy="none">
        <!--- place all mxml code here to create layout -->
    </s:BorderContainer>

</s:VGroup>

Несколько примечаний:

(1) Хотя курсор занятости отображается до того, как вкладка 2 завершит сборку, приложение по-прежнему зависает, и когда пользователь перемещает мышь, курсор занятости остается на экране, в то время как значок мыши по умолчанию (стрелка) перемещается по экрану в соответствии с управлением пользователь, пока вкладка 2 не завершит сборку и не отобразится. Не идеально, но, по крайней мере, курсор занятости указывает на то, что приложение что-то делает. Если бы я хотел, я мог бы заменить курсор занятости окном заголовка, указывающим занятость и т. Д.

(2) Изменение тайм-аута со 100 мс на 50 мс по-прежнему дает хорошие результаты. Но уменьшение его до 10 мс приводит к тому, что курсор занятости появляется только тогда, когда все компоненты построены и отображены. Следует ожидать, что уменьшение тайм-аута ниже некоторого порога вызовет такое поведение. Интересно, зависит ли этот порог для значения тайм-аута (например, от 10 до 50 мс) от клиентского компьютера? Или, если я использовал 100 мс, безопасно ли это покрыть все клиентские машины? (Откуда мы знаем, что это будет?)

(3) Я ожидал, что замена setTimeout(start2,100); на callLater(start2); и удаление creationPolicy="none" должны дать аналогичный результат, но это не так (например, курсор занятости никогда не появляется, а приложение зависает на несколько секунд, пока не отобразится вкладка 2). Я никогда раньше не использовал callLater(), так что, возможно, я сделал что-то не так (?).

1
ggkmath 7 Фев 2013 в 09:06
1
Это не настоящее решение, но попробуйте установить для параметра createPolicy ViewStack значение «all»: <mx:ViewStack creationPolicy="all" />. По умолчанию стек представлений использует отложенное создание экземпляров и не создает невидимые представления, пока они не понадобятся. Настоящее решение - понять, почему создание представления на второй вкладке занимает так много времени. Хотите показать этот код или описать, что он делает? Мы могли бы даже помочь вам с подходом, который использует callLater (или другие идеи, предложенные вам), если мы поймем, почему создание вашего представления занимает так много времени.
 – 
Sunil D.
7 Фев 2013 в 10:17
2
Если для параметра createPolicy ViewStack установлено значение «all», это может ускорить процесс, но также означает, что при инициализации приложения потребуется гораздо больше времени. Есть ли какие-либо тяжелые вычисления, кроме компонентов пользовательского интерфейса и построения макета, при переходе на Tab2?
 – 
kyohiro
7 Фев 2013 в 10:36
Задержка в обработке связана только с тем, что Flex создает и размещает различные компоненты пользовательского интерфейса на вкладке 2. Эта вкладка включает в себя множество форм, текстовых областей и довольно сложную диаграмму.
 – 
ggkmath
7 Фев 2013 в 18:34

1 ответ

Лучший ответ

Если у вас есть тяжелые вычисления во время инициализации Tab2, вы можете разделить их на небольшие части и выполнять их последовательно, используя механизм callLater.

Вот ОЧЕНЬ упрощенный пример:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
           xmlns:s="library://ns.adobe.com/flex/spark" 
           xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
<fx:Script>
    <![CDATA[
        import mx.core.FlexGlobals;
        import mx.events.FlexEvent;
        import mx.managers.CursorManager;

        private var i:int = 0;

        protected function nc2_initializeHandler(event:FlexEvent):void
        {
            FlexGlobals.topLevelApplication.enabled = false;                
            CursorManager.setBusyCursor();
            callLater(initTab2);
        }

        protected function initTab2():void
        {
            var j:int;

            //Part of calculations
            for (j=0; j< 10000; j++)
            {
                i++;
            }   

            //Check if completed
            if (i<1000000)
            {
                //If not call again
                callLater(initTab2);                    
            }
            else
            {
                //Finished
                CursorManager.removeBusyCursor();
                FlexGlobals.topLevelApplication.enabled = true;
            }
        }

    ]]>
</fx:Script>
<fx:Declarations>
    <!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:VGroup gap="10" top="10" left="10">
    <s:TabBar id="tabs"  dataProvider="{vs}"/>
    <mx:ViewStack id="vs" width="100%" >
        <s:NavigatorContent label="Tab 1"  width="100%" height="100%" >
            <s:Label text="Tab1 content"/>
        </s:NavigatorContent>
        <s:NavigatorContent id="nc2" label="Tab 2"  width="100%" height="100%">
            <s:Label text="Tab2 content" initialize="nc2_initializeHandler(event)"/>
        </s:NavigatorContent>
        <s:NavigatorContent label="Tab 3"  width="100%" height="100%">
            <s:Label text="Tab3 content"/>
        </s:NavigatorContent>
    </mx:ViewStack>

</s:VGroup>
1
David Goshadze 7 Фев 2013 в 12:28
Спасибо, Дэвид, к сожалению, задержка связана с тем, что Flex создает компоненты пользовательского интерфейса и размещает их через mxml, а не код AS3, который я могу сгруппировать для запуска в такой функции, как initTab2(). Если только я не смог переместить подмножество mxml-кода в блок <fx:Declarations> и выполнить его каким-либо образом, используя ваш метод (пример?).
 – 
ggkmath
7 Фев 2013 в 18:31
Вы можете преобразовать объявления mxml в функции ActionScript и выполнять их последовательно.
 – 
David Goshadze
7 Фев 2013 в 18:49
Я имею в виду, что каждый элемент пользовательского интерфейса mxml может быть создан и добавлен к родительскому объекту в ActionScript.
 – 
David Goshadze
7 Фев 2013 в 18:55
Если я установлю для компонента значение invisible, сэкономит ли это время Flex для создания / компоновки? Если так, я могу вернуть компоненты в visible, используя ваш метод для callLater().
 – 
ggkmath
7 Фев 2013 в 18:59
Хм ... я никогда не думал об этом ... возможно, если использовать вместе с includeInLayout
 – 
David Goshadze
7 Фев 2013 в 19:03