Chapter 4. Screens
Breaking out of the browser provides you with additional challenges when developing applications. In addition to positioning elements within your application, you now have control over where the application itself is positioned. In addition, you now have to expand your thinking beyond a browser window to a user’s desktop, which consists of one or more monitors.
The Screen
class in Adobe AIR provides you with information about the current
user’s monitor setup. This allows you to take advantage of the full
capability of the user’s desktop, including multiple monitor configurations.
By using the data contained in this class, you can get explicit information
about the number of monitors, the positioning of these monitors, and even
the capabilities of the monitors themselves.
Positioning Windows on the Desktop
Solution
Use the Screen
class to
determine the width and height of the primary monitor on the user’s
computer. Using this information, you can position your application in
the center of the screen.
Discussion
The Screen
class has properties
that reflect characteristics of the user’s primary monitor and provides
an instance of itself in the static variable Screen.mainScreen
. Included in these
properties are two variables that define the width and height of the
monitor: bounds
and visibleBounds
.
bounds
: Thebounds
property of theScreen
class is an instance of theRectangle
class, which provides the properties for the entire space on a screen that is available to the operating system.visibleBounds
: ThevisibleBounds
property is an instance of theRectangle
class, which provides the properties for the available space on the screen. On a Windows system, this is the full size of the screen without the taskbar. On a Mac, this could be the full size of the screen without the menu bar. Also, note that, depending on system preferences, this could include or not include the Dock on a Mac.
Both the bounds
and visibleBounds
variables are instances of the
Rectangle
class, which provides the
width, height, x, and y values for the screen as well as additional
positioning values. With these variables, you can determine the center
point of the screen as well as the application’s relative
positioning.
After you have determined the center point, you can then calculate
where the window will need to be positioned to be in the center. To
accomplish this, you can adjust the x and y positions of the current
NativeWindow
instance in your
application. To find these values, you subtract half the application’s
width and half the application’s height from the center point and then
position the NativeWindow
instance at
that point.
ActionScript
Within ActionScript, you first need to import the
flash.display.Screen
class. You
then can determine the center x and y values by dividing the Screen.mainScreen.bounds.width
and Screen.mainScreen.bounds.height
values by 2.
Finally, you can position the nativeWindow
instance’s x and y values by
subtracting half the window’s width and height from the center
points.
<?xml version="1.0" encoding="utf-8"?> <mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" horizontalAlign="center" verticalAlign="middle"> <mx:Script> <![CDATA[ import flash.display.Screen; private function handleClick(event:MouseEvent):void { var centerX:Number = Screen.mainScreen.bounds.width / 2; var centerY:Number = Screen.mainScreen.bounds.height / 2 nativeWindow.x = centerX - (nativeWindow.width / 2); nativeWindow.y = centerY - (nativeWindow.height / 2); } ]]> </mx:Script> <mx:Button id="centerButton" click="handleClick(event)" label="Center Window" /> </mx:WindowedApplication>
JavaScript
Within JavaScript, you can access the Screen
class with air.Screen
. To determine the width and height of the
primary monitor, you use air.Screen.mainScreen.bounds.width
and
air.Screen.mainScreen.bounds.height
. By
dividing these two values in half, you have the center point of the
user’s primary monitor.
Next, subtract half the application’s width and height from
these center values to determine the point at which the application
should be positioned to center it on the screen. The nativeWindow
instance that refers to the
current application window is located in window.nativeWindow
. Set its x and y values
to the predetermined point to center the window on the user’s
screen.
<html> <head> <title>Entry 4.1 - Center a Window</title> <script type="text/javascript" src="AIRAliases.js"></script> <script type="text/javascript"> function handleClick(){ var centerX = air.Screen.mainScreen.bounds.width / 2; var centerY = air.Screen.mainScreen.bounds.height / 2; window.nativeWindow.x = centerX - (window.nativeWindow.width / 2); window.nativeWindow.y = centerY - (window.nativeWindow.height / 2); } </script> </head> <body> <input id="centerButton" type="button" value="Center Window" onclick="handleClick()" /> </body> </html>
Positioning Windows Across Multiple Monitors
Problem
You want to be able to center your application on any of the available monitors for the user’s current desktop.
Solution
Use the static Screen.screens
array, which contains the properties of the available
monitors.
Discussion
The process of centering the application on any available monitor is twofold. First, you need to loop through the array of screens to determine the monitors that are available. Second, you must calculate the center point of the monitor that is selected.
Looping through the available monitors requires looping through
the Screen.screens
array. To center
your application in Positioning Windows on the Desktop, you used the Screen.mainScreen
property, which held a
reference to an instance of the Screen
class. Each element in the Screen.screens
array is an instance of the
Screen
class as well. Each of these
instances corresponds to one of the user’s available screens. You can
use the bounds rectangle of each Screen
defined in the array to determine the
width, height, x, and y values of the available monitors.
Calculating the center point now requires an additional step. In
AIR, the primary monitor is always positioned at 0,0, and other monitors
are positioned relative to their positioning on the user’s desktop. For
example, if the user had a monitor above the primary monitor, its x and
y values would be negative. If you are trying to center a window on a
specific monitor, the starting point will be that window’s x and y
positions as defined in its instance of the Screen
class. From that point, you can add
half the width and height to determine the center.
ActionScript
In this example, the handleCreationComplete
method loops through
each of the available monitors and populates a group of radio buttons.
Each radio button is given a value that corresponds to the index of
the screen in the Screen.screens
array with which you can retrieve a reference to each screen instance
and its properties.
When the centerButton
is
clicked, the handleClick
method
determines the monitor that the user selected with the radio buttons
and calculates that screen’s center point. Finally, the application
window is positioned at the center point of the selected monitor. If a
screen is not selected, an Alert
window is shown.
<?xml version="1.0" encoding="utf-8"?> <mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" creationComplete="handleCreationComplete()"> <mx:Script> <![CDATA[ import mx.controls.Alert; import flash.display.Screen; import mx.collections.ArrayCollection; [Bindable] private var screens:ArrayCollection; private function handleCreationComplete():void { screens = new ArrayCollection(); var output:String = ""; var screen:Screen; for(var i:uint = 0; i < Screen.screens.length; i++) { screen = Screen.screens[i]; output = "Screen " + i + " - "; output += "Width: " + screen.bounds.width; output += " Height: " + screen.bounds.height; screens.addItem({ label: output }); } } private function handleClick(event:MouseEvent):void { if(monitorButtonGroup.selectedValue != null) { var selectedVal:Object = monitorButtonGroup.selectedValue; var screen:Screen = Screen.screens[selectedVal] as Screen; var centerX:Number = screen.bounds.x + screen.bounds.width / 2; var centerY:Number = screen.bounds.y + screen.bounds.height / 2; nativeWindow.x = centerX - (nativeWindow.width / 2); nativeWindow.y = centerY - (nativeWindow.height / 2); } else { mx.controls.Alert.show("Please Select a Monitor",""); } } ]]> </mx:Script> <mx:RadioButtonGroup id="monitorButtonGroup" /> <mx:Repeater id="screensRepeater" dataProvider="{screens}"> <mx:RadioButton id="monitorsButton" group="{monitorButtonGroup}" value="{screensRepeater.currentIndex}" width="100%" label="{screensRepeater.currentItem.label}" /> </mx:Repeater> <mx:Button id="centerButton" click="handleClick(event)" label="Center on Selected Monitor" /> </mx:WindowedApplication>
JavaScript
In this example, the function populateScreens
is called in response to the
onload
event. This method loops
through each of the screens available on the user’s computer. It adds
a radio button for each of these screens along with a label for each
button that gives the screen’s index in the Screen.screens
array as well as its width
and height. It is important to note that if you have only one monitor,
you will see only one option here.
The page also contains a button that triggers the handleClick
function when clicked. This
method determines which radio button is selected and then calculates
the center point of the referenced screen. The application window is
positioned at this center point. If no screen is selected, an alert
window is launched.
<html> <head> <title>Entry 4.2 - Multiple Monitors</title> <script type="text/javascript" src="AIRAliases.js"></script> <script type="text/javascript"> function populateScreens() { var form = document.getElementById('radioButtons'); for(i=0; I < air.Screen.screens.length; i++) { var screen = air.Screen.screens[i]; var rb = document.createElement('input'); rb.type='radio'; rb.name='screens'; rb.value=i; form.appendChild(rb); form.innerHTML += 'Screen ' + i + ' - ' form.innerHTML += 'Width: ' + screen.bounds.width; form.innerHTML += ' Height: ' + screen.bounds.height; form.innerHTML += '<br />'; } } function handleClick() { var buttons = document.forms['screensForm'].elements['screens']; var selectedValue; for( i=0; i<buttons.length;i++) { if( buttons[i].checked) { selectedValue = buttons[i].value; } } if (selectedValue) { var screen = air.Screen.screens[selectedValue]; var centerX = screen.bounds.x + screen.bounds.width / 2; var centerY = screen.bounds.y + screen.bounds.height / 2; window.nativeWindow.x = centerX - (window.nativeWindow.width / 2); window.nativeWindow.y = centerY - (window.nativeWindow.height / 2); } else { alert('Please Select a Screen'); } } </script> </head> <body onload="populateScreens()" style="text-align:center;"> <form id="radioButtons" name="screensForm"></form> <br /> <input type="button" value="Center on Selected Screen" onclick="handleClick()" /> </body> </html>
Determining the Monitors on Which an Application Is Currently Displayed
Solution
Use the getScreensForRectangle
, which is a static method of the Screen
class, to determine which screens are
being used to display a given region as defined by the given rectangle
instance.
Discussion
In situations where the current screen needs to be calculated, you
can use the getScreensForRectangle
.
This static method of the Screen
class takes one argument: a rectangle. When you pass in an instance of
the Rectangle
class, it returns an
array of the screens the rectangle occupies.
In this case, the bounds
property of the NativeWindow
class
provides the instance of the Rectangle
class that is needed for the
getScreensForRectangle
method. By
passing this value into the method, you can determine which screens the
referenced window occupies.
In the following examples, an event listener is attached to the
native window’s moving
event. This
means that each time the application window is moved, the event listener
method will be called. In the handleMove
method, the currently occupied
screens are calculated and then displayed in the application.
ActionScript
In this example, the list of the currently occupied
screens is stored in an ArrayCollection
, which is
bound to a List
and updated in the
handleMove
listener method for the
moving event when the window is moved. This listener method is also
added as a listener to the creationComplete
event to ensure it is
executed when the application is launched and rendered.
<?xml version="1.0" encoding="utf-8"?> <mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" moving="handleMove(event)" creationComplete="handleMove(event)"> width="320" height="240"> <mx:Script> <![CDATA[ import mx.collections.ArrayCollection; [Bindable] private var monitors:ArrayCollection = new ArrayCollection(); private function handleMove(event:Event):void { monitors.removeAll(); var windowBounds:Rectangle = this.nativeWindow.bounds; var screens:Array = Screen.getScreensForRectangle(windowBounds); var output:String = ""; var screen:Screen; for( var i:uint = 0; i < screens.length; i++ ) { screen = screens[i]; output = "Screen " + i + " - "; output += "Width: " + screen.bounds.width; output += " Height: " + screen.bounds.height; monitors.addItem({ label: output }); } } ]]> </mx:Script> <mx:Label text="Occupied Screens" fontWeight="bold" /> <mx:List id="monitorsList" dataProvider="{monitors}" width="100%" height="100%" /> </mx:WindowedApplication>
JavaScript
In this example, the event listener, handleMove
, is registered for the AIR
moving
event and also for the
JavaScript onload
event of the page
body. The method is called any time the window is moved and also when
the page is loaded. It determines the currently occupied screens
before adding a new div
to the main
listing div
for each of the screens
that is returned from the call to getScreensForRectangle
.
<html> <head> <title>Entry 4.3 - Get Current Application Screens</title> <script type="text/javascript" src="AIRAliases.js"></script> <script type="text/javascript"> window.nativeWindow.addEventListener(air.NativeWindowBoundsEvent.MOVING, handleMove); function handleMove(event) { var listing = document.getElementById('listing'); while(listing.hasChildNodes()) { listing.removeChild(listing.firstChild); } var screens = air.Screen.getScreensForRectangle(window.nativeWindow.bounds); for(i=0;i < screens.length;i++) { var newDiv = document.createElement('div'); newDiv.innerHTML += "Screen " + i; newDiv.innerHTML += " WIDTH: " + screens[i].bounds.width; newDiv.innerHTML += " HEIGHT: " + screens[i].bounds.height; listing.appendChild(newDiv); } } </script> </head> <body onload="handleMove(event)" style="text-align:center;"> <strong>Occupied Screens</strong> <div id="listing"></div> </body> </html>
Get Adobe AIR 1.5 Cookbook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.