Windows可以将多个显示器映射为虚拟桌面,使我们可以利用这一点设计出方便工作的应用程序。例如PowerPoint就充分发挥了双显示器的优势(大多数的笔记本电脑都支持),它可以在一个显示器上播放幻灯片,而在另一个显示器上显示备注,可以控制播放的进程,使使用者做商务演说的时候非常等心应手。那么我们怎么开发这种应用程序呢?这篇文章将向你展示如果用Delphi实现使用多显示器的应用程序。

Windows还支持克隆显示方式,每个显示器输出同样的内容,这对某些应用也是有意义的。还有些显卡虽然也支持两个显示器,不过他们并不是真正意义上的多显示器,而是虚拟高分辨率显示模式(如2048×768或者1024×1536),通过显卡将画面分别显示到两个显示器上。这两种显示模式都不是本文介绍的zhongdian,而且也非常简单,所以我们也就不再赘述了。

Windows最多支持10个显示器,Windows将所有显示器映射为一个大的虚拟桌面。可以将显示器理解为桌面某个局部的视图。在显示属性中可以根据显示器的物理位置任意排布这些显示器。如果显示器的排列不规则,虚拟桌面上的某些部分可能无法显示在任何一个显示器上。为了不使一个窗体显示在两个显示器之间等原因的考虑,Windows将一个显示器作为主显示器。启动计算机时,登录对话框就显示在主显示器中。绝大多数程序启动示,都会显示在主监视器中。

根据上述介绍,不难发现几个重要的概念:桌面、显示器、主显示器等。首先必须先弄清楚这些概念以及他们之前的关系。这是掌握多显示器应用程序开发方法的重点。理解了这些概念,其他的部分就非常好理解了。

桌面实际上是指Windows可显示的逻辑区域。实际上是可以将一个窗体显示到桌面之外的。然而这并不是说桌面的所有部分都会显示在某台显示器上(原因如前所述);但反过来说,任何一个显示器显示的内容都必然是桌面的一部分。

桌面是一个矩形区域,可以通过顶点坐标(Top,Left)和宽高来描述桌面的尺寸。为什么还需要顶点坐标呢?因为顶点坐标不是想当然的(0,0)。那么(0,0)在哪里呢?说来话长,还是让我们先来回顾一下刚才提到地一个概念——主显示器吧。Windows希望一般的程序初始的时候显示到主显示器,因为人们习惯于关注一个离自己最近的显示器。而Windows也不可能强制用户把最左边一个显示器作为主显示器,这样一来应用程序为了把自己显示到主显示器,就需要费脑筋的计算。然而,多数用户都只有一个显示器(两个显示器实在太占地方了),而一般的应用程序也不希望大费周章的去计算主显示器在哪里,自己应该显示在什么位置。所以Windows提出了一个合理的解决方案:以主显示器的顶点坐标作为坐标系的原点。这样一来,普通的程序之需要想在单显示器环境中一样考虑问题就可以了。

显示器是桌面的局部视图。就好像透过窗户看窗外的风景,站在不同的窗前就可以看到不同的画面。同样的,显示器也是一个矩形区域,同样可以通过顶点坐标(Top,Left)和宽高来描述它的尺寸。顶点坐标是相对于桌面坐标系原点的,也就是相对于主显示器的顶点。

工作区的概念比较简单,它是指显示器中除了任务条和其他停靠在桌面上的窗体之外的矩形区域。

Windows为多显示器应用程序的开发提供了一组API。VCL将这些API封装起来,非常自然的融入整个Framework之中,使得开发多显示器应用程序变得非常简单。下面就介绍与之相关的内容。

在VCL之中大家最熟悉的恐怕非TCustomForm莫属了,它是所有窗体的基类。TCustomForm的Position属性用来设置窗体的现实位置,其可选值中有两个是值得关心的:一个是poScreenCenter,当Position属性被设置成poScreenCenter时,窗体会显示到主显示器的中央;另一个是poDesktopCenter,当Position属性被设置成poDesktopCenter时,窗体显示在整个桌面的中央。如果把这个属性设成poDesktopCenter,程序又运行在一个有多台显示器的系统上,那么这个窗口就会显示在两个显示器之间,会给用户带来不必要的麻烦。因此即使我们的程序不是针对多显示器而设计的,也应该细心处理这个值。另外一个属性是DefaultMonitor,它的作用与Position有些类似,决定窗口最初显示在哪个显示器内。它有四个备选值:dmDesktop,dmPrimary,dmMainForm和dmActiveForm。他们的含义如下:

Value
Meaning

dmDesktop
不特别处理

dmPrimary
将窗体显示到第一个显示器上。这又是一个陷阱,字面上理解是主显示器,而事实上它是指Screen.Monitor[0]这个显示器。

dmMainForm
将窗体显示到主窗体所在的显示器

dmActiveForm
将窗体显示到桌面上活动窗体所在的显示器

TCustomForm还有一个只读的共有属性(没有Published)Monitor,它提供了访问窗体所在显示器实例的引用,这个值与DefaultMonitor是有紧密的关联的。

那么怎么在使窗体在不同的显示器之间移动呢?这并不困难,估计你也想到了。这里介绍两种方法:

第一,   可以设置TCustomForm的Top和Left使窗体显示在桌面的任意位置。正如前面所述,桌面是由所有显示器组成的。它们有共同的坐标系,所以可以根据显示器的逻辑位置决定窗体的位置。现在的问题是如何获得每个显示器的逻辑位置和尺寸,后面就会介绍。

第二,   可以调用TCustomForm的MakeFullyVisible方法将窗体完全显示到指定的显示器之中。可以通过这个方法避免窗口在两个显示器上各显示一部分。

刚才我们提出了一个问题:如何获得每个显示器的逻辑位置和尺寸。为了解答这个问题,需要再介绍连个类:TScreen和TMonitor。

TScreen描述与显示设备有关的一些信息,我们主要关心与显示器逻辑位置和尺寸有关的信息。其他方面的内容可以在Delphi的文档中获知。在程序运行的时候VCL自动创建一个TScreen的实例——全局变量,所以通常情况下程序是不需要实例化TScreen的。

TScreen有一组形如Desktop*的属性,这些属性描述了整个桌面的尺寸和各顶点坐标。还有对开发多显示器应用程序有重要意义的连个属性:MonitorCount和Monitors。通过这两个属性我们可以枚举出系统中所有的显示器(TMonitor)的实例,每个实例都反映了相应显示器的相对位置和分辨率等信息(后文会详细说明)。

在TScreen的众多属性之中,我们会找到Height和Width这两个属性。要特别警惕它们不是指整个桌面的尺寸,而是指主显示器的高度和宽度。这非常容易让人产生错觉,无以为是整个桌面的尺寸。与之类似的还有形如WorkArea*的一组属性,它们描述了主显示器的工作区域的尺寸和各顶点坐标。是不是觉得少了什么?为什么没有获取主显示器相对位置的属性?原因就像前面所说的:Windows是以主显示器的左上角为坐标系原点的,所以主显示器的相对位置必然是(0,0)。

除了这些属性之外,还要介绍TScreen的三个成员函数:MonitorFromPoint,MonitorFromRect和MonitorFromWindow。顾名思义,他们分别是获取个坐标、某个区域和某个窗口所在的显示器的实例。在实际的开发中可能也会用到。

最好,再来看看TMonitor类。它封装了物理显示器的有关属性——这些属性都是只读的。下表简单介绍了这些属性的含义,它们对编写多显示器应用程序非常有用:

属性
说明

Handle
获取该显示器的Windows句柄

MonitorNum
获取显示器的编号

Primary
获取该显示器是否是主显示器。又且仅有一个显示器的Primary是True。

Top
获取显示器的上边界

Left
获取显示器的左边界

Height
获取显示器的高度

Width
获取显示器的宽度

BoundsRect
获取显示器的对应桌面的区域,它与上面四个属性是等价的

WorkareaRect
获取显示器的工作区对应桌面的区域。

清楚地了解了TScreen和TMonitor之后,前面的问题也就自然解决了。到这里,本文已经介绍了开发多显示器应用程序所需的全部知识。相信你可以利用这些知识开发出非常实用的软件产品。

附:你可以下载一个DEMO,帮助理解本文。

http://my.6to23.com/yukin2010/download/MultiMonitorDemo.rar

http://www.pfan.cn/Article/2510.html

在Delphi中开发使用多显示器的应用程序(MonitorCount和DefaultMonitor)的更多相关文章

  1. 在 Visual Studio 2010 中开发和部署 Windows Azure 应用程序

    原文 在 Visual Studio 2010 中开发和部署 Windows Azure 应用程序 在 Visual Studio 2010 中开发和部署 Windows Azure 应用程序 Jim ...

  2. BEGINNING SHAREPOINT® 2013 DEVELOPMENT 第6章节--在SharePoint2013中开发、集成和构建应用程序 总结

    BEGINNING SHAREPOINT® 2013 DEVELOPMENT 第6章节--在SharePoint2013中开发.集成和构建应用程序  总结         SharePoint开发已经 ...

  3. Delphi For Android 开发笔记-附:如何Delphi中同时实现Windows、Android版的GetModuleFileName函数

    在Windows中开发DLL时,经常会需要获取当前DLL所在目录以便读取同目录下的其他文件,而目前Delphi在开发android时,其实没多大必要获取,因为整个工程只有一个so文件,而这个so文件也 ...

  4. 如何在Delphi中调用VC6.0开发的COM

    上次写了如何在VC6.0下对Delphi写的COM进行调用,原本想马上写如何在Delphi中调用VC6.0开发的COM时,由于在写事例程序中碰到了个很怪的问题,在我机子上用VC写的接口程序编译能通过. ...

  5. Delphi for iOS开发指南(8):在iOS应用程序中使用Tab组件来显示分页

    Delphi for iOS开发指南(8):在iOS应用程序中使用Tab组件来显示分页 在FireMonkey iOS应用程序中的Tab Tab由FMX.TabControl.TTabControl定 ...

  6. Delphi for iOS开发指南(7):在iOS应用程序中使用WebBrowser组件

    Delphi for iOS开发指南(7):在iOS应用程序中使用WebBrowser组件 在FireMonkey iOS应用程序中使用WebBrowser 在iOS平台上,FireMonkey使用T ...

  7. Delphi for iOS开发指南(6):在iOS应用程序中使用ComboBox组件来从列表中选择某一项

    http://blog.csdn.net/delphiteacher/article/details/8924110 Delphi for iOS开发指南(6):在iOS应用程序中使用ComboBox ...

  8. Delphi中SendMessage使用说明(所有消息说明) good

    Delphi中SendMessage使用说明 SendMessage基础知识 函数功能:该函数将指定的消息发送到一个或多个窗口.此函数为指定的窗口调用窗口程序,直到窗口程序处理完消息再返回.而函数Po ...

  9. Delphi中stringlist分割字符串的用法

    Delphi中stringlist分割字符串的用法 TStrings是一个抽象类,在实际开发中,是除了基本类型外,应用得最多的. 常规的用法大家都知道,现在来讨论它的一些高级的用法. 1.CommaT ...

随机推荐

  1. 【已解决】谁动了我的CurrentPrincipal?求助我在给Artech的wcf petshop增加授权机制的时候遇到的问题。

    这个问题已解决,是绑定设置的问题,主要还是因为我自己没有深入理解WCF绑定的安全机制.在这篇博客里面我来说说怎么解决的. 下载了Artech的wcf petshop源码(博文链接)并调试运行成功后,打 ...

  2. [学习笔记]jQuery实现一些动画效果的方法

    jQuery实现效果的方法 1,隐藏和显示:hide(),show(),toggle()  // [ˈtɑ:gl]切换 语法: $(selector).hide(speed,callback); $( ...

  3. DevExpress ASP.NET 使用经验谈(6)-ASPxGridView属性设置与CRUD界面优化

    上一节中,我们通过简单的配置,通过ASPxGridView控件的使用,完成了对数据库表的CRUD操作. 这样的界面展现,功能是达到了,但是操作体验上,还是有所欠缺的. 图一 默认生成的列表界面 图二 ...

  4. Javah生成JNI头文件

    首先确保java的环境变量配置好了. 1:打开cmd 进入doc命令窗口: 进入class所在目录,我的class是在F:\summerVacation\ndkhelloworld\bin\class ...

  5. Android——用户登陆及用户名和密码的保存

    Android——用户登陆及用户名和密码的保存   在之前的学习过程中已经将Android学习完了,但是在后面将近一年的时间里都没有进行过Android开发,所以对Android的所有的知识点又有点忘 ...

  6. python学习之day9

    队列queue 队列是线程安全的,它保证多线程间的数据交互的一致性. 先进先出队列Queue import queue q = queue.Queue(maxsize=3) #maxsize为队列最大 ...

  7. 转: cmd和amd的区别

    AMD 规范在这里:https://github.com/amdjs/amdjs-api/wiki/AMDCMD 规范在这里:https://github.com/seajs/seajs/issues ...

  8. 三个C++资源链接(大量)

    https://github.com/fffaraz/awesome-cpp http://blog.jobbole.com/78901/ https://github.com/programthin ...

  9. Cocos2d-x 创建自己定义项目模板

    你是否以前为cocos方便高速开发而兴奋,你是否以前为各种工具的便利开发而感动,但如今的你是否为每次创建一个新的项目都是HelloWorldScene而苦恼? 好吧,事实上我也感觉到了,每次创建一个项 ...

  10. HDU 5012 Dice DFS

    简单DFS //#pragma comment(linker, "/STACK:16777216") //for c++ Compiler #include <stdio.h ...