tags:

views:

37

answers:

2

In Flex Air app, how do you open a window behind an active one?

I tried following and i can't seem to get it to work

<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" 
                       xmlns:s="library://ns.adobe.com/flex/spark" 
                       xmlns:mx="library://ns.adobe.com/flex/mx"
                       creationComplete="onCreationComplete(event)">

    <fx:Script>
        <![CDATA[
            import mx.events.FlexEvent;

            import spark.components.Window;

            private var window1:Window  = new Window();
            private var window2:Window  = new Window();
            private var timer:Timer     = new Timer(3000,1);

            private function onCreationComplete(event:FlexEvent):void
            {
                window1         = new Window();
                window1.title   = "Window 1";
                window1.width   = 200;
                window1.height  = 200;
                window1.open(false);
                window1.orderInBackOf(this);

                window2         = new Window();
                window2.title   = "Window 2";
                window2.width   = 200;
                window2.height  = 200;

                timer.addEventListener(TimerEvent.TIMER_COMPLETE, openWindow2, false, 0, true);
                timer.start();          
            }

            private function openWindow2(event:TimerEvent):void
            {
                window2.open(false);    
                window2.orderInBackOf(window1);
            }
        ]]>
    </fx:Script>
</s:WindowedApplication>

With this code, I would expect window1 to open behind the main app window and, in 3 seconds, window2 would open behind window1. But if you execute this, window1 will open on top of the main window and window2 will open on top of window1 and the main app will retain focus. This seems like a bug in the Flex. If so is there any workaround for this problem?

A: 

Is there a particular reason you're setting the useWeakReference parameter to true? Otherwise, you should be able to just call:

timer.addEventListener(TimerEvent.TIMER_COMPLETE, openWindow2);

However, there's a bug in that line of code. The TIMER_COMPLETE event is fired when the timer is finished all its cycles. You have set your timer to "fire" infinitely. So it will never complete it's cycles.

You need to modify that line of code to the following and you should get your expected results:

timer.addEventListener(TimerEvent.TIMER, openWindow2);




To address your second question (why window1 doesn't appear behind the application). Judging by the return value of the orderInBackOf function:

Boolean  — true if the window was succesfully sent behind;
           false if the window is invisible or minimized. 

It seems that ordering fails if the the window is invisible. It may be the case that, by having the code in the creationComplete handler, you're calling this function before the Application window has a chance to display itself. Try moving that code within your openWindow2 function, as well. Yeilding:

        private function openWindow2(event:TimerEvent):void
        {
            window1.orderInBackOf(this);
            window2.open(false);    
            window2.orderInBackOf(window1);
        }

I hope this helps in some way,

  • gMale

EDIT: per my last comment try this,

        private function openWindow2(event:TimerEvent):void
        {
            window1.depth = 5; //arbitrary number
            window2.depth = 4;
            window1.open(false); //assumes window1 isn't opened before
            window2.open(false);                    
        }
gmale
yeah useWeakReference wasn't necessary, but TIMER_COMPLETE is right. If you look at my code, I have the timer set up to repeat only once. so After the first run, it will fire TIMER_COMPLETE. Well I guess the problem is that I was calling orderInBackOf before window was visible. moving window1.orderInBackOf(this) to openWindow2 moved the window1 behind the main app. However this is not the behavior I want. I want to open window1 behind the main app not open window1 and then move it behind. I wish there was openInBackOf() function.. or open(false) should open it behind the active window
lordofthefobs
@Sang: try using open(true) -- to give the window focus when it's opened, see if that makes a difference. You are right about the timer thing, I don't know why I misread it the first time. I would try using the TIMER event anyway just to see if anything changes.
gmale
@Sang: Here's an [example app](http://www.adobe.com/devnet/air/flex/quickstart/controlling_display_order_windows.html) from Adobe
gmale
Well again the problem I want to solve is how to open a window behind the active one. open(true) will open the second window activated which is not what I want. I want the first, currently active window to retain focus and stay in front. I've seen the Z example and played around with it before. But that example doesn't help me since he's manipulating already opened window. I want to open a brand new window behind an already opened one.
lordofthefobs
@Sang: Right, I was speculating that maybe using open(true) might change the behavior of orderInBackOf since the window would have focus. After that, you could return focus wherever you wanted it. Does orderToBack() also not work as expected? One other thing I can think of is to try setting the window's *depth* property before calling open. In Spark containers, the item with lowest depth is in the back. Highest in front.
gmale
Hmm I haven't tried setting the depth. I shall try that next. Although I'm not sure how well that would work since I don't know how many windows I'll have to open. I will let you know how that goes
lordofthefobs
edited my answer above to include the depth suggestion / test.
gmale
A: 

So it seems like there isn't a good way to solve this problem. A workaround would be to add event listener for AIREvent.WINDOW_COMPLETE and move the window in the event handler. This seems like "correct" workaround and it works for a simple case like my original example. Problem is that this approach did not work on my code.

If you look at the spark.components.Window code from the sdk, you will see that an event listener for Event.ENTER_FRAME is added when opening the window (in commitProperties()). Then in the event handler, enterFrameHandler(), it keeps a counter, and on second frame, dispatch AIREvent.WINDOW_COMPLETE event. This makes me think that AIREvent.WINDOW_COMPLETE event will fire on second frame regardless of the status of the window even though the livedoc says:

Dispatched when the Window completes its initial layout and opens the underlying NativeWindow.

I'm guessing my window wasn't full created by the second frame and therefore orderInBackOf failed.


So here's my workaround:

First, in my window, I override open(openWindowActive). If openWindowActive is false, I add an event listener for Event.ENTER_FRAME. In the event handler, I keep a counter and, when the frame count reaches a certain number (10 right now), I move the current window behind the active one. This is a VERY hacky way to get around this problem. I've been increasing the limit and now it succeeds about 90% of the time. I could continue to increase the limit until I get close to 100% but I hate having to check this condition every time I make any changes to the window. Also this condition could be different depending on the machine.

I would LOVE it if someone can tell me how wrong my workaround is and tell me a much much better way to solve my problem... but till then this will have to do...

lordofthefobs