Windows可以将多个显示器映射为虚拟桌面
使我们可以利用这一点设计出方便工作的应用程序
例如PowerPoint就充分发挥了双显示器的优势(大多数的笔记本电脑都支持)
它可以在一个显示器上播放幻灯片
而在另一个显示器上显示备注
可以控制播放的进程
使使用者做商务演说的时候非常等心应手
那么我们怎么开发这种应用程序呢?这篇文章将向你展示如果用Delphi实现使用多显示器的应用程序
Windows还支持克隆显示方式每个显示器输出同样的内容这对某些应用也是有意义的还有些显卡虽然也支持两个显示器不过他们并不是真正意义上的多显示器而是虚拟高分辨率显示模式(如×或者×)通过显卡将画面分别显示到两个显示器上这两种显示模式都不是本文介绍的zhongdian而且也非常简单所以我们也就不再赘述了
Windows最多支持个显示器Windows将所有显示器映射为一个大的虚拟桌面可以将显示器理解为桌面某个局部的视图在显示属性中可以根据显示器的物理位置任意排布这些显示器如果显示器的排列不规则虚拟桌面上的某些部分可能无法显示在任何一个显示器上为了不使一个窗体显示在两个显示器之间等原因的考虑Windows将一个显示器作为主显示器启动计算机时登录对话框就显示在主显示器中绝大多数程序启动示都会显示在主监视器中
根据上述介绍不难发现几个重要的概念桌面显示器主显示器等首先必须先弄清楚这些概念以及他们之前的关系这是掌握多显示器应用程序开发方法的重点理解了这些概念其他的部分就非常好理解了
桌面实际上是指Windows可显示的逻辑区域实际上是可以将一个窗体显示到桌面之外的然而这并不是说桌面的所有部分都会显示在某台显示器上(原因如前所述)但反过来说任何一个显示器显示的内容都必然是桌面的一部分
桌面是一个矩形区域可以通过顶点坐标(TopLeft)和宽高来描述桌面的尺寸为什么还需要顶点坐标呢?因为顶点坐标不是想当然的()那么()在哪里呢?说来话长还是让我们先来回顾一下刚才提到地一个概念——主显示器吧Windows希望一般的程序初始的时候显示到主显示器因为人们习惯于关注一个离自己最近的显示器而Windows也不可能强制用户把最左边一个显示器作为主显示器这样一来应用程序为了把自己显示到主显示器就需要费脑筋的计算然而多数用户都只有一个显示器(两个显示器实在太占地方了)而一般的应用程序也不希望大费周章的去计算主显示器在哪里自己应该显示在什么位置所以Windows提出了一个合理的解决方案以主显示器的顶点坐标作为坐标系的原点这样一来普通的程序之需要想在单显示器环境中一样考虑问题就可以了
显示器是桌面的局部视图就好像透过窗户看窗外的风景站在不同的窗前就可以看到不同的画面同样的显示器也是一个矩形区域同样可以通过顶点坐标(TopLeft)和宽高来描述它的尺寸顶点坐标是相对于桌面坐标系原点的也就是相对于主显示器的顶点
工作区的概念比较简单它是指显示器中除了任务条和其他停靠在桌面上的窗体之外的矩形区域
Windows为多显示器应用程序的开发提供了一组APIVCL将这些API封装起来非常自然的融入整个Framework之中使得开发多显示器应用程序变得非常简单下面就介绍与之相关的内容
在VCL之中大家最熟悉的恐怕非TCustomForm莫属了它是所有窗体的基类TCustomForm的Position属性用来设置窗体的现实位置其可选值中有两个是值得关心的一个是poScreenCenter当Position属性被设置成poScreenCenter时窗体会显示到主显示器的中央另一个是poDesktopCenter当Position属性被设置成poDesktopCenter时窗体显示在整个桌面的中央如果把这个属性设成poDesktopCenter程序又运行在一个有多台显示器的系统上那么这个窗口就会显示在两个显示器之间会给用户带来不必要的麻烦因此即使我们的程序不是针对多显示器而设计的也应该细心处理这个值另外一个属性是DefaultMonitor它的作用与Position有些类似决定窗口最初显示在哪个显示器内它有四个备选值dmDesktopdmPrimarydmMainForm和dmActiveForm他们的含义如下
ValueMeaningdmDesktop不特别处理dmPrimary将窗体显示到第一个显示器上
这又是一个陷阱
字面上理解是主显示器
而事实上它是指Screen
Monitor[
]这个显示器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是以主显示器的左上角为坐标系原点的所以主显示器的相对位置必然是()
除了这些属性之外还要介绍TScreen的三个成员函数MonitorFromPointMonitorFromRect和MonitorFromWindow顾名思义他们分别是获取个坐标某个区域和某个窗口所在的显示器的实例在实际的开发中可能也会用到
最好再来看看TMonitor类它封装了物理显示器的有关属性——这些属性都是只读的下表简单介绍了这些属性的含义它们对编写多显示器应用程序非常有用
属性说明Handle获取该显示器的Windows句柄MonitorNum获取显示器的编号Primary获取该显示器是否是主显示器
又且仅有一个显示器的Primary是TrueTop获取显示器的上边界Left获取显示器的左边界Height获取显示器的高度Width获取显示器的宽度BoundsRect获取显示器的对应桌面的区域
它与上面四个属性是等价的WorkareaRect获取显示器的工作区对应桌面的区域
清楚地了解了TScreen和TMonitor之后前面的问题也就自然解决了到这里本文已经介绍了开发多显示器应用程序所需的全部知识相信你可以利用这些知识开发出非常实用的软件产品
附你可以下载一个DEMO帮助理解本文
http://mytocom/yukin/download/MultiMonitorDemorar