by Joe Ward

Joe Ward

Created

10 October 2011

Requirements
Prerequisite knowledge

General experience of building applications
with Flex Builder is suggested. For more
details on getting started with this Quick
Start, refer to Building the Quick Start
sample applications with Flex
.
Required products

Sample files

User level

Intermediate
 
Adobe AIR provides several methods and properties for controlling the display order of application windows. The Z sample application, shown in Figure 1, illustrates the following AIR features:
 
  • Activating a window
  • Pulling a window to the top of the display order
  • Pushing a window to the bottom of the display order
  • Ordering a window relative to another application window
  • Keeping a window in front of other windows
The Z sample application demonstrates how to control the display order of application windows.
Figure 1. The Z sample application demonstrates how to control the display order of application windows.
 
Note: This is a sample application provided, as is, for instructional purposes.
 
This sample application includes the following files:
 
  • Z.as: The main application file in ActionScript; includes the code discussed in this article
  • Z-app.xml: The AIR application descriptor file
  • ZWindow.as: Extends the NativeWindow class to customize the behavior of the example windows in the Z application
  • CircularZWindow.as: Extends ZWindow to draw a circular window
  • RectangularZWindow.as: Extends ZWindow to draw a rectangular window
  • TriangularZWindow.as: Extends ZWindow to draw a triangular window
  • Sample AIR icon files
Important: The application descriptor file, FileCompressionTool-app.xml, uses the AIR 3.0 namespace. To modify and repackage this application, you need to download and use AIR 3 SDK along with Flash Builder 4.5.
 

 
About window depth sorting

AIR allows you to sort windows into two display order groups based on the value of the alwaysInFront property. Any windows with alwaysInFront set to true are displayed in front of any windows with alwaysInFront set to false. (They're also displayed in front of other windows of other applications, so discretion should be exercised when setting this property to true.)
 
AIR provides four methods for ordering the display depth of a window relative to other windows:
 
  • orderToFront()
  • orderToBack()
  • orderInFrontOf(NativeWindow)
  • orderInBackOf(NativeWindow)
In addition, the activate() method also orders a window to the front.
 
Changing the value of the alwaysInFront property may also change the ordering of a window. For example, changing the value from true to false orders the window behind any other alwaysInFront windows, but still in front of other windows. When you use the orderInFrontOf() or orderInBackOf() methods, the window takes on the alwaysInFront setting of the target window.
 
The window ordering methods return a boolean value that indicates whether the ordering operation succeeded. The only reason an ordering operation may fail is if the window being ordered is not visible.
 
These ordering methods and properties are defined for the Flex mx:WindowedApplication and mx:Window classes, as well as for the AIR NativeWindow class. The Z example application is an ActionScript project, so it operates with NativeWindow objects, but you can use the same techniques with Flex windows.
 

 
The Z sample application

The Z application draws three example windows that allow you to experiment with the depth ordering APIs and how they interact with user manipulation of the windows. On the Windows operating system, a fourth window supplies a menu bar which contains menu commands for the depth ordering methods and properties.
 
To test the application, launch the Z application (Z.air) file. Use the application or window menu to exercise the native window depth ordering methods and properties on the three geometric windows.
 

 
Understanding the code

The Z application creates three example windows whose display order can be set through menu commands. A base class, ZWindow, is defined to establish the window behaviors. The subclasses: CircularZWindow, TriangularZWindow, and RectangularZWindow, extend this base class to draw a distinctive geometric shape.
 
 
Dispatching the ordering commands
The ordering methods and properties are called in response to commands selected from the menu. Each example window adds its own menu with event handlers to exercise the ordering methods and properties:
 
The alwaysInFront and visible properties are Boolean values so negating their current value works to toggle the setting:
 
private function toggleAlwaysInFront(event:Event):void{ alwaysInFront = !alwaysInFront; } private function toggleVisibility(event:Event):void{ visible = !visible; }
The orderToFront() and orderToBack() methods move a window to the front or back of its display order group. When using the Z application, be sure to note how the behavior of these commands changes depending on the alwaysInFront properties of the windows:
 
private function orderToFrontCommand(event:Event):void{ orderToFront(); } private function orderToBackCommand(event:Event):void{ orderToBack(); }
The activate() method makes the window visible, orders it to front, and also gives the window focus.
 
private function activateCommand(event:Event):void{ activate(); }
The orderInBackOf() and orderInFrontOf() methods require a reference to another window. In Z, these references are stored in the data property of the relevant menu commands so that the reference can be retrieved from the target of the menu item select event object. Note that the alwaysInFront setting also changes to match that of the window passed as an argument:
 
private function orderBehindCommand(event:Event):void{ orderInBackOf(event.target.data as ZWindow); } private function orderInFrontCommand(event:Event):void{ orderInFrontOf(event.target.data as ZWindow); }
 
Setting up the menus
The makeZOrderMenu() method of the ZWindow class creates a menu with commands to control a single window. The main Z class calls this method for each window so that the application has a menu for each of the three example windows.
 
The Mac OS X and Windows operating systems handle menus differently, so different functions are called when the application is run on the different operating systems. On Windows, the following function is called to create the menus for the initial application window, adding a menu for each Z window, as well as a Source Code menu:
 
private function createWindowMenu():NativeMenu{ var menu:NativeMenu = new NativeMenu(); for each(var zWindow:ZWindow in ZWindow.zWindows){ menu.addSubmenu(zWindow.makeZOrderMenu(), zWindow.title); } menu.addSubmenu(createSourceCodeMenu(),"Source Code"); return menu; }
On Mac OS X, the following function is called to modify the standard application menu. Z removes the existing File, Edit , and Window menus and adds a menu for each Z window, as well as a Source Code menu:
 
private function modifyApplicationMenu():void{ var menu:NativeMenu = NativeApplication.nativeApplication.menu; //Remove unwanted standard menus for each(var item:NativeMenuItem in menu.items){ if((item.label == "File") || (item.label == "Edit") || (item.label == "Window")){ menu.removeItem(item); } } //Add a menu for each example window for each(var zWindow:ZWindow in ZWindow.zWindows){ menu.addSubmenu(zWindow.makeZOrderMenu(), zWindow.title); } //Add the source code menu menu.addSubmenu(createSourceCodeMenu(), "Source Code"); }
 
Creating the command menus
The ZWindow base class defines the makeZOrderMenu() method that returns a NativeMenu object containing the menu commands and submenus for a window:
 
public function makeZOrderMenu():NativeMenu{ var menu:NativeMenu = new NativeMenu(); var stateAlwaysInFront:NativeMenuItem = menu.addItem(new NativeMenuItem("Always in front")); stateAlwaysInFront.addEventListener(Event.SELECT, toggleAlwaysInFront); var stateVisible:NativeMenuItem = menu.addItem(new NativeMenuItem("Visible")); stateVisible.addEventListener(Event.SELECT, toggleVisibility); menu.addEventListener(Event.DISPLAYING, function(event:Event):void{ stateAlwaysInFront.checked = alwaysInFront; stateVisible.checked = visible; }); menu.addItem(new NativeMenuItem("",true));//separator var commandActivate:NativeMenuItem = menu.addItem(new NativeMenuItem("Activate")); commandActivate.addEventListener(Event.SELECT, activateCommand); var commandOrderToFront:NativeMenuItem = menu.addItem(new NativeMenuItem("Order to front")); commandOrderToFront.addEventListener(Event.SELECT, orderToFrontCommand); var commandOrderToBack:NativeMenuItem = menu.addItem(new NativeMenuItem("Order to back")); commandOrderToBack.addEventListener(Event.SELECT, orderToBackCommand); var submenuOrderInFront:NativeMenuItem = menu.addSubmenu(createWindowSubmenu(),"Order in front of"); submenuOrderInFront.submenu.addEventListener(Event.SELECT, orderInFrontCommand); var submenuOrderBehind:NativeMenuItem = menu.addSubmenu(createWindowSubmenu(),"Order behind"); submenuOrderBehind.submenu.addEventListener(Event.SELECT, orderBehindCommand); return menu; }
The first two items in the menu show the window alwaysInFront and visible settings. To make sure that the state of the menu matches the state of the window, the menu item checked property is updated in response to the menu displaying event. The displaying event is dispatched immediately before the menu is made visible.
 
menu.addEventListener(Event.DISPLAYING, function(event:Event):void{ stateAlwaysInFront.checked = alwaysInFront; stateVisible.checked = visible; });
Separator items are created by setting the isSeparator parameter to true in the item constructor.
 
menu.addItem(new NativeMenuItem("",true));//separator
Command items are added by adding an item with the appropriate label and attaching an event listener that carries out the command. For example, the following statement adds the activate command:
 
var commandActivate:NativeMenuItem = menu.addItem(new NativeMenuItem("Activate")); commandActivate.addEventListener(Event.SELECT, activateCommand);
The event handler simply calls the window activate() method.
 
private function activateCommand(event:Event):void{ activate(); }
 
Creating the window submenus
For the Order in front of and Order behind commands to work, the second window needed for the command must be identified. For these commands, Z provides a submenu listing the other example windows. The createWindowSubmenu() method creates the NativeMenu object for the Order in front of and Order behind menus:
 
private function createWindowSubmenu():NativeMenu{ var windowMenu:NativeMenu = new NativeMenu(); windowMenu.addEventListener(Event.DISPLAYING, displayWindows); return windowMenu; }
The submenus initially have no members. Instead, Z adds an item for each of the windows when the menu dispatches the displaying event. The displayWindows() method adds the items to the submenu by looping through the static ZWindow.zWindows array, which contains every instance of a ZWindow:
 
private function displayWindows(event:Event):void{ for each(var existing:NativeMenuItem in event.target.items){ event.target.removeItem(existing); } for each(var zWindow:ZWindow in ZWindow.zWindows){ if(zWindow != this){ var item:NativeMenuItem = event.target.addItem(new NativeMenuItem(zWindow.title)); item.data = zWindow; } } }
To make it easier to access the ZWindow object for the windows listed in the menu, the window object is assigned to the menu item data property. The data property is of type object, so you can assign any object to it. This allows the assigned object to be accessed through the event object target property when handling the menu item select event. For example, the handler for the commands in the Order in front of menu calls the orderInFront() method as follows:
 
private function orderInFrontCommand(event:Event):void{ orderInFrontOf(event.target.data as ZWindow); }