3 Replies Latest reply on Jan 12, 2011 5:01 PM by jordana309-36

    Multiple stages on multiple screens of different size

    jordana309-36 Level 1

      I'm working on a project that requires me to have two stages on two screens of different size. How do I do this in Flex, or is it even possible?

       

      More specifically, I am building a kiosk appliction, that will have the menu on a small touch-screen that sits in front of a larger, wall-mounted screen. When the user selects content to be played (videos, web sites, whatever) from the touch-screen, then the effect of that selection needs to be sent to the other stage. I need to be able to run a screen-saver on the main screen, also. Basically, the controls are the main application, and the other screen is simply a container for viewing things.

       

      I am currently packaging my Flex project in AIR, not through the web, so I actually have a windowed application. Basically, I just need to create a new window with a custom chrome that simply holds a movie.

       

      Is such a thing possible in Flex? I couldn't figure out how to spawn another stage, much less one that was referencable from the first stage.

        • 1. Re: Multiple stages on multiple screens of different size
          Flex harUI Adobe Employee

          mx:Window or s:Window creates another top-level window with its own stage.

          1 person found this helpful
          • 2. Re: Multiple stages on multiple screens of different size
            jordana309-36 Level 1

            [FINAL EDIT: The answer is below, provided by myself. Feel free to keep reading this if you want to see my other problems I came across in this project]

             

            Thank you! Let me play with that option for a little bit. I'll let you know how it goes in a few hours.

            Cheers!

             

            EDIT: This wasn't quite what I was looking for. I need to create a new window entirely, with it's own chrome, and its own stage that I can reference from my first stage.s:Window didn't have the ability to do that. It created another stage, but in the same window. I do not always know the size of my screen before I launch this application, so I need to be able to automatically detect the number of screens present, and get the height and width of each. I will need to set one window and stage (the primary) in the smaller screen with my controls, and another, separate window and stage in the large display, also set to the full size of that screen. Is there any way to do this? I'm sorry, but I'm still a little new at Flex.

             

            EDIT: I have read up a little more on the s:Window tag, and realized that it needs to be in its own mxml file. However, in all the examples I have read, I need to import a myComponents.windowSomething (class? filename?). I don't understand how to create that. Could somebody please explain that to me?

             

            I got all the chrome stuff figured out. Turns out that in the *app.xml file, everything is originally commented out. I've been developing a single AIR app for the last few months, and so I haven't had to worry about un-commenting the XML in that document. Stupid, beginner's mistake.

             

            I am also surrently able to dynamically figure out the size of both my screens, and position the main window on either screen at any resolution. I will post the code for everything once I get this working. Please, somebody, tell me how to create that myComponents thing. Examples are this (using MX), and this (using Spark). Do you see that import statement? How do I do that?

            • 3. Re: Multiple stages on multiple screens of different size
              jordana309-36 Level 1

              Hey all. I have reached the answer. I left everything up that I posted before, in case anybody is having similar issues. To create the custom component, click your project, create a package, and then right-click that package and create a new MXML component. Then, create the MXML just like you would before. Your root tag will be whatever you are working to modify (so, s:Window for my case, but you can do an s:Label or whatever you want). So, first, I'll give you the code for my simple Window component:

               

              [CODE]

              <?xml version="1.0" encoding="utf-8"?>
              <!-- This is a window component which creates a transparent window with no system chrome (no bars, close, min, max buttons, resize stuff) that contains... This screen is spawned from the main MXML WindowedApplication using AS 3. -->
              <s:Window xmlns:fx="http://ns.adobe.com/mxml/2009"
                                  xmlns:s="library://ns.adobe.com/flex/spark"
                                  xmlns:mx="library://ns.adobe.com/flex/mx"
                                  systemChrome="none" visible="true" transparent="true" showStatusBar="false" width="400" height="300"
                 
                  <s:layout>
                      <s:BasicLayout />
                  </s:layout>
                 
                  <s:Label id="controlScreenTitle" text="new Window from VideoScreen component" fontSize="72" fontWeight="normal" color="#222222">
                  <s:filters>
                      <s:DropShadowFilter color="#CCCCCC" />
                  </s:filters>
                  </s:Label>
              </s:Window>

              [/CODE]

               

              All I did was a very simple white box there. You can disable the system chrome and such from the main Window tag, as I have shown. The window this creates has no [ _ ] [ [] ] [ x ] buttons, bar along the bottom, or any background. In my actual project, this component will hold a container to play my video objects.

               

              Then, I create my main document:

              [CODE]

              <?xml version="1.0" encoding="utf-8"?>
              <!-- This is the main MXML file for the application. MXML is based on pure XML, and is actually a short-cut to generating AS code. You use MXML to set up the layout of the stage. -->
              <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"
                                      showStatusBar="false" alwaysInFront="false"
                                      creationComplete="init()">
                 
                  <!-- Imports -->
                  <fx:Style source="KioskScreensStyles.css" />
                  <fx:Script source="controlScreenMain.as" />
                 
                  <fx:Script>
                      <![CDATA[
                          /* Insert other ActionScript stuff here. Try to put as much of it as you can in the .AS file, though */
                      ]]>
                  </fx:Script>
                  <fx:Declarations>
                      <!-- Place non-visual elements (e.g., variables, services, value objects) here -->
                      <!-- Any variables placed in here will be global, and live for the entirety of the entire program's run. However, for simplicity's sake, I have placed all of those for this application in the imported .as file. But, for reference, they are described using MXML. ie: -->
                      <!--<fx:Type id="ASReferencableName">Value of the variable</fx:Type>-->
                  </fx:Declarations>
                 
                  <s:BorderContainer id="controlInterface" right="0" left="0" top="0" bottom="0" borderStyle="inset" borderColor="#CCCCCC">
                      <s:layout>
                          <!-- There are several layouts available to you:
                                  * s:BasicLayout will allow you to completely control all placement. Objects are absolutely placed, and don't move from their position on the stage, even if the screen scrolls.
                                  * s:TileLayout can be used to create grids of button objects.
                                  * s:HorizontalLayout and s:VerticalLayout will lay out elements horizontally or vertically on the stage. You can specify padding around each object (example below). Placement will begin from top-left corner of the visible stage. If you go with either of these, then no x, y properties on elements will be used, as the system will automatically place all elements in the order that they are created.
                          -->
                          <s:BasicLayout />
                          <!--<s:TileLayout columnAlign="justifyUsingWidth" rowAlign="justifyUsingHeight" />-->
                          <!--<s:HorizontalLayout verticalAlign="middle" paddingLeft="10" paddingRight="10" />-->
                      </s:layout>

                      <!-- We default the text of this ID as an error, showing that the .as did not link up. -->
                      <s:Label id="controlScreenTitle" text="Error loading program..." fontSize="48" fontWeight="normal" color="#222222">
                          <s:filters>
                              <s:DropShadowFilter color="#CCCCCC" />
                          </s:filters>
                      </s:Label>
                     
                      <!-- Creating the menu buttons for playing the movies -->
                      <s:ToggleButton id="btn1" label="Play video 1" click="btn1_clickHandler(event)" />
                      <s:ToggleButton id="btn2" label="Play video 2" click="btn2_clickHandler(event)" />
                      <s:ToggleButton id="btn3" label="Play video 3" click="btn3_clickHandler(event)" />
                      <s:ToggleButton id="btn4" label="Play video 4" click="btn4_clickHandler(event)" />
                      <s:ToggleButton id="btn5" label="Play video 5" click="btn5_clickHandler(event)" />
                      <s:ToggleButton id="btn6" label="Play video 6" click="btn6_clickHandler(event)" />
                         
                  </s:BorderContainer>
                 
              </s:WindowedApplication>

              [/CODE]

               

              Now, the important part will be the .as file. Here's parts of that:

              [CODE]

              /* Imports */
              /* import custom components. This is what allows us to open a new window in AIR. NOTE: THIS IS HOW YOU GET THAT CUSTOM MXML FILE IN HERE TO USE */
              import customComponents.VideoScreen;

              // import older mx stuff only when needed. Try to avoid using these.
              import mx.controls.Image;

              // import the newer Spark components. Use these for everything possible.
              import spark.components.VideoDisplay;
              import spark.components.Window;
              import spark.primitives.Rect;

              // Global variable declairation
              protected var screens:Array = Screen.screens;
              protected var controlScreenSizes:Rectangle = screens[0].bounds;
              protected var videoScreenSizes:Rectangle = screens[1].bounds;
              // All variables below Defined in init(), to be sure that they have been fully loaded
              // While the :Window declairation technically works for the controlScreen, Flash views this as an error, and will not process everything properly if I type it like that.
              //protected var controlScreen:Window = this.Window;
              protected var controlScreen;// = this;
              /* NOTE: THIS IS THE USE OF MY NEW, IMPORTED CUSTOM WINDOW. This is all you need to do to make it. */
              protected var videoScreen:VideoScreen = new VideoScreen();
              protected var btns:Array;

              /* Initialize all my variables, and call the needed functions to set everything up */
              protected function init():void
              {
                  controlScreen = this;
                  // This is a Window method that opens the Window. I did not have to code this.
                  videoScreen.open(false);
                  btns = [btn1, btn2, btn3, btn4, btn5, btn6];
                  placeScreens();
                  createControlScreen();
                  loadScreenSaver();
              }

              /* Moves all my screens so that they sit in the top-left of each of the two screens, and then expands to be full screen on those two screens, whatever size that may be. */
              private function placeScreens():void
              {
                  // We move it to -1,-1 because there is 1 px padding and dead white space that I can't figure out how to remove.
                  controlScreen.move(-1,-1);
                  controlScreen.width = (controlScreenSizes.width+1);
                  controlScreen.height = (controlScreenSizes.height+1);
                  controlInterface.width = (controlScreenSizes.width+1);
                  controlInterface.height = (controlScreenSizes.height+1);
                  videoScreen.systemChrome = "Standard";
                  videoScreen.move(controlScreenSizes.width,0);
                  videoScreen.width = (videoScreenSizes.width);
                  videoScreen.height = (videoScreenSizes.height);
              }

              /* Puts all the buttons where they belong, and attached the background image that we need and so forth */
              private function createControlScreen():void
              {
                 /* Most of this code is not needed for the demonstration, so I only include what I feel would be helpful, with psudocode for the rest */
                  var backgroundImg:Image = new Image();
                  backgroundImg.source = "assets/backgroundImg.jpg";
                  var backgroundVid:VideoDisplay = new VideoDisplay();
                  backgroundVid.source = "assets/backgroundVid.mp4";
                  backgroundVid.width = (controlScreenSizes.width+1);
                  backgroundVid.height = (controlScreenSizes.height+1);
                  backgroundVid.autoPlay = true;
                  backgroundVid.muted = true;
                  backgroundVid.loop = true;
                 
                  /* Format the buttons. You can change height, width, x and y position on the form, label (the text on it), and some other things (including the ability to spawn video or picture or sound when clicked and such for animations. */
                  /* buncha code that moved the buttons around and made them all fit in the screen dynamically based on the screen size. */
                 
                  /* Finally, play with controlScreenTitle, which is a label control that you can styple and use for text on the screen in addition to the buttons. In here is just a bunch of code to do that*/
                 
                  /* Attach the elements to the controlInterface. The first put on has the lowest z, therefore is under the rest. Stack them in the order you want then displayed. The first one should be either backgroundImg (image), or backgroundVid (video), depending on what you provided and want. Note that the video causes the buttons to lag a lot */
                  controlInterface.contentGroup.addElement(backgroundImg);
                  //controlInterface.contentGroup.addElement(backgroundVid);
                  controlInterface.contentGroup.addElement(controlScreenTitle);
                  controlInterface.contentGroup.addElement(btn1);
                  controlInterface.contentGroup.addElement(btn2);
                  controlInterface.contentGroup.addElement(btn3);
                  controlInterface.contentGroup.addElement(btn4);
                  controlInterface.contentGroup.addElement(btn5);
                  controlInterface.contentGroup.addElement(btn6);
                 
                  /* Buncha code for the functionality */
              } // End function createControlScreen()

              /* Puts the screensaver up on the video display so that we don't burn out the display */
              private function loadScreenSaver():void
              {
                  //pull in screensave into that window
              }

              /* Makes sure that the user doesn't see two buttons active at the same time--that would look like two movies were playing at the same time. */
              private function deselectOtherButtons(clicked:int):void
              {
                  for(var i:int=0; i<6; i++)
                  {
                      if(i != (clicked-1))
                      {
                          btns[i].selected = false;
                      }
                  }
              }

              /* All of the below do the same thing: unselect all the other buttons when one of the buttons is clicked. I could just create one click event handler, but I wanted to leave the possiblity of customizing the result of each button's click, so I left it this way. */
              protected function btn1_clickHandler(event:MouseEvent):void
              {
                  deselectOtherButtons(1);
              }

              protected function btn2_clickHandler(event:MouseEvent):void
              {
                  deselectOtherButtons(2);
              }

              protected function btn3_clickHandler(event:MouseEvent):void
              {
                  deselectOtherButtons(3);
              }

              {
                  deselectOtherButtons(4);
              }

              protected function btn5_clickHandler(event:MouseEvent):void
              {
                  deselectOtherButtons(5);
              }

              protected function btn6_clickHandler(event:MouseEvent):void
              {
                  deselectOtherButtons(6);
              }

              [/CODE]

               

              If anybody looking at this has any questions about it, feel free to ask me. I am not usually able to comb the forums, so you'll have to PM me or something. I actually put this up right after I found my solution, so there is work still to be done on it (obviously). But if you ever need to do anything like this, here's some code for you.