
Adobe
放置或移动窗口时, 经常需要了解桌面屏幕的尺寸和相对位置。Adobe AIR 通过 Screen 类提供对此信息的访问。图 1 中显示的 Screens 范例应用程序演示如何使用 Screen API。

图 1。Screens 范例应用程序利用了 AIR 中的 Screen API。
注意: 本范例应用程序按原样提供, 用于教学目的。
若要充分利用本篇文章, 您需要以下软件和文件:
本范例应用程序包括以下文件:
应具备使用 Flex Builder 或 Flex SDK 构建应用程序的一般经验。有关使用此快速入门指南的详细信息, 请参阅用 Flex 构建快速入门范例应用程序。
虚拟桌面由一个或多个分立的屏幕组成。 (由操作系统) 指定主屏幕, 并将虚拟桌面的原点放置在此屏幕的左上角。向右和向下为正值, 就像您对计算机显示器所料想的那样。主屏幕上方和左侧的屏幕中的坐标为负值。
屏幕的可用区域要排除任何任务栏、菜单栏、停靠栏、边栏或其它始终绘制于任何窗口之前的栏。Screen 类报告整个屏幕和可用区域的尺寸。
Screens 应用程序在虚拟桌面上绘制屏幕的示意图, 其中包括该应用程序自身窗口的缩小版本。每个屏幕的可用区域以蓝色显示。在屏幕内、但在可用区域之外的区域以灰色显示。应用程序窗口所在的屏幕上以浅蓝色加亮显示。
若要测试 Screens, 请下载并启动应用程序的安装程序文件 (Screens.air)。可以四处移动应用程序窗口, 更改显示器的分辨率和颜色深度, 以及更改任务栏的大小和位置, 从而观察对 AIR Screen API 报告的屏幕信息所产生的效果。使用方向键可以使窗口在不同屏幕之间跳转 (如果计算机系统中有多台显示器)。
Screen 应用程序使用了若干非 AIR 所特有的图形函数。有关这些函数的详细信息, 请参阅《ActionScript 3.0 语言参考》*。
矩形边界描述了位置和尺寸。虚拟桌面的矩形边界是包含所有屏幕的边界框。为了计算此边界框, Screens 应用程序遍历由静态 Screen.screens 属性提供的 Screen 对象数组中的每个屏幕, 并将屏幕的每个边与边界框的当前边相比较。如果屏幕的值远远超过当前边界框的值, 则加大边界框的值, 使其与屏幕相匹配。结果为包含所有屏幕的矩形边界。
private function computeVirtualBounds(screens:Array):Rectangle{
var bounds:Rectangle = new Rectangle();
for each (var screen:Screen in screens){
if(bounds.left > screen.bounds.left){bounds.left = screen.bounds.left;}
if(bounds.right < screen.bounds.right){bounds.right = screen.bounds.right;}
if(bounds.top > screen.bounds.top){bounds.top = screen.bounds.top;}
if(bounds.bottom < screen.bounds.bottom){bounds.bottom = screen.bounds.bottom;}
}
return bounds;
}
计算出虚拟桌面的大小后, 即可确定应用程序窗口的大小。将窗口的宽度设置为主屏幕宽度的 60% (再为边框增加少许)。随虚拟桌面成比例地调整窗口的高度, 以使窗口的高度足以完整地显示桌面的缩略图:
var scale:Number = (Screen.mainScreen.bounds.width * .6)/virtualScreenBounds.width; stage.stageWidth = (Screen.mainScreen.bounds.width * .6) + (border * 2); stage.stageHeight = (virtualScreenBounds.height * scale) + (border * 2);
可以使用 Screen 类的静态 mainScreen 属性访问操作系统所指定主屏幕的 Screen 对象。
由于 Screens 应用程序类扩展 Sprite 类, 因此使用子画面的图形函数绘制桌面的示意图。使用屏幕坐标以完整大小绘制桌面中的屏幕。作用于主子画面的转换矩阵平移并缩放桌面示意图, 使其适合窗口的显示区域。
用 Matrix 类的 createBox() 方法创建转换矩阵。此方法采用水平和垂直缩放系数作为参数。对这两个参数使用相同的缩放比例, 该比例的计算方法为窗口的显示区域除以虚拟桌面的总宽度。createBox() 方法对于示意图要移动 (或平移) 的幅度也采用了参数, 以使示意图在窗口上恰当地排列整齐。
redraw() 方法计算出转换矩阵, 将其赋给主子画面 transform 对象的 matrix 属性, 然后调用绘制桌面示意图的元素的函数。响应 enterFrame 事件时将调用 redraw() 方法。
private function redraw(event:Event):void{
virtualScreenBounds = computeVirtualBounds(Screen.screens);
var scale:Number = (stage.nativeWindow.width - border * 2)/virtualScreenBounds.width;
virtualScreenToWindowTransform.createBox(scale, scale, 0,
border - (virtualScreenBounds.x * scale),
border - (virtualScreenBounds.y * scale));
transform.matrix = virtualScreenToWindowTransform;
graphics.clear();
drawScreenRepresentation();
highlightScreens();
drawWindowModel();
}
为了绘制桌面, drawScreenRepresentation() 方法遍历 Screen 类的 screens 数组。对于每个屏幕, 例程都为整个屏幕绘制一个矩形, 再为可用区域绘制另一个矩形:
with(graphics){
//绘制屏幕矩形
beginFill(screenColor,.5);
drawRect(screen.bounds.left,
screen.bounds.top,
screen.bounds.width,
screen.bounds.height);
endFill();
//为屏幕的可用区域绘制矩形
beginFill(usableScreenColor,.5);
drawRect(screen.visibleBounds.left,
screen.visibleBounds.top,
screen.visibleBounds.width,
screen.visibleBounds.height);
endFill();
//...
此方法还绘制若干标签。用 BitmapData.draw() 方法将这些标签绘制到位图中。使用位图填充的方式向主子画面绘制所得的标签位图。
使用位图填充时的一个意外之处是填充对准子画面的原点, 而非对准要填充区域的左上角。对于重复的纹理, 这可能不是问题, 但用于标签时, 这可能会使文字远离被填充区域之外。解决方案是使用另一个转换矩阵将标签位图移动至被填充区域。下面几行向主屏幕的中心绘制包含“Main Screen”这几个字的位图:
//绘制标签, 用于显示哪个屏幕是“主”屏幕
var mainLabelBitmap:BitmapData = drawLabel("Main Screen");
labelTransform = new Matrix(1, 0, 0, 1,
(Screen.mainScreen.visibleBounds.width - mainLabelBitmap.width)/2,
(Screen.mainScreen.visibleBounds.height - mainLabelBitmap.height)/2);
with(graphics){
beginBitmapFill(mainLabelBitmap,labelTransform,false);
drawRect((Screen.mainScreen.visibleBounds.width - mainLabelBitmap.width)/2,
(Screen.mainScreen.visibleBounds.height - mainLabelBitmap.height)/2,
mainLabelBitmap.width, mainLabelBitmap.height);
endFill();
mainLabelBitmap = null;
}
通过 Screens 应用程序, 可以使用方向键使窗口在屏幕之间跳转。为了确定向何处移动窗口, 应用程序必须确定其当前所处的屏幕以及位于所选方向的屏幕 (如果有)。
可以使用静态 Screen.getScreensForRectangle() 方法确定当前屏幕。此方法以数组形式返回与矩形相交的所有屏幕。以下函数将窗口边界传入 getScreensForRectangle() 方法, 并返回所得数组中的第一个屏幕:
private function getCurrentScreen():Screen{
var current:Screen;
var screens:Array = Screen.getScreensForRectangle(stage.nativeWindow.bounds);
(screens.length > 0) ? current = screens[0] : current = Screen.mainScreen;
return current;
}
如果该窗口由于某种原因不在任何屏幕中, 则返回主屏幕。
为了找到窗口所要移至的正确屏幕, 将对屏幕的数组按垂直或水平方向进行排序, 然后通过遍历排序后的数组来比较相关的坐标。以下方法将窗口移向左侧:
/*Moves the window to the next screen to the left*/
private function moveLeft():void{
var currentScreen:Screen = getCurrentScreen();
var left:Array = Screen.screens;
left.sort(sortHorizontal);
for(var i:int = 0; i < left.length - 1; i++){
if(left[i].bounds.left < stage.nativeWindow.bounds.left){
stage.nativeWindow.x += left[i].bounds.left - currentScreen.bounds.left;
stage.nativeWindow.y += left[i].bounds.top - currentScreen.bounds.top;
}
}
}
上方调用的 sort 方法使用以下排序函数比较屏幕坐标:
private function sortHorizontal(a:Screen, b:Screen):int{
if (a.bounds.left > b.bounds.left){
return 1;
} else if (a.bounds.left < b.bounds.left){
return -1;
} else {return 0;}
}
Charles Ward 是一名技术作者, 它喜欢钻研新技术。在之前的 (专业) 职业生涯中, 他曾参与创建开拓性的计算机游戏, 如 Falcon 3.0 和 4.0 以及 Star Trek: A Final Unity。在闲暇时间, Charles 喜欢自由潜水以及和他的孩子们玩耍。