Windows XP 可通過使用多臺監(jiān)視器擴(kuò)大您的桌面,進(jìn)而提高您的工作效率。一臺計(jì)算機(jī)上可連接多達(dá)十臺單獨(dú)的監(jiān)視器,借助于這些監(jiān)視器,您的桌面可以有充足的空間容納大量的程序或窗口。通過將項(xiàng)目從一臺監(jiān)視器移動到另一臺監(jiān)視器或?qū)⑵鋽U(kuò)展到多臺監(jiān)視器,您可以輕松地同時(shí)執(zhí)行多項(xiàng)任務(wù)。您可以在一臺監(jiān)視器上編輯圖像或文本,同時(shí)在另外一臺監(jiān)視器上查看 Web 活動。或者,您還可以打開一篇長文檔的多個(gè)頁,將這些頁拖動到多臺監(jiān)視器中,以便輕松查看文字布局和圖像。您亦可以將 Microsoft Excel 電子表格在兩臺監(jiān)視器間拖動,這樣無需使用滾動條便可以查看多個(gè)列的信息。
連接多臺監(jiān)視器
將一臺監(jiān)視器用作主監(jiān)視器,它將在您啟動計(jì)算機(jī)后顯示“登錄”對話框。此外,多數(shù)程序會在您首次打開時(shí)在主監(jiān)視器上顯示程序窗口。您可以為每臺監(jiān)視器選擇不同的屏幕分辨率和顏色質(zhì)量設(shè)置??梢詫⒍嗯_監(jiān)視器連接到各自的視頻適配器,也可以連接到支持多輸出的一個(gè)單獨(dú)的視頻適配器。若要連接多臺監(jiān)視器并進(jìn)行配置,請按照下列步驟操作: 1. 單擊“開始”,然后單擊“控制面板”。
2. 單擊“外觀和主題”,然后單擊“顯示”。
3. 在“設(shè)置”選項(xiàng)卡上,單擊“識別”,以在每臺監(jiān)視器上顯示一個(gè)大型數(shù)字。此數(shù)字表明各監(jiān)視器對應(yīng)的圖標(biāo)。
4. 單擊監(jiān)視器圖標(biāo)并將該圖標(biāo)拖動到不同的位置上,這些位置分布代表了您希望在兩臺監(jiān)視器間移動項(xiàng)目的方式。然后單擊“確定”或“應(yīng)用”來查看更改。
注意:圖標(biāo)位置決定了您在兩臺監(jiān)視器間移動項(xiàng)目的方式。例如,如果您正在使用兩臺監(jiān)視器,并希望通過左右拖動的方式將項(xiàng)目從一臺監(jiān)視器移到另一臺監(jiān)視器中,請將圖標(biāo)并列排放。若要以上下拖動的方式在兩臺監(jiān)視器間移動項(xiàng)目,請將圖標(biāo)上下排放。圖標(biāo)的位置不必與監(jiān)視器的物理位置對應(yīng)。即使您的監(jiān)視器并排放置,也可以將圖標(biāo)上下排列。
更改主監(jiān)視器
1. 在“顯示屬性”對話框的“設(shè)置”選項(xiàng)卡上,單擊代表要指定為主監(jiān)視器的監(jiān)視器的圖標(biāo)。
2. 通過單擊選中“使用該設(shè)備作為主監(jiān)視器”復(fù)選框。注意,如果您選中的監(jiān)視器圖標(biāo)當(dāng)前已設(shè)置為主監(jiān)視器,則此復(fù)選框不可用。
在多臺監(jiān)視器中查看同一桌面
1. 在“顯示屬性”對話框的“設(shè)置”選項(xiàng)卡上,單擊代表除主監(jiān)視器外還需要使用的其他監(jiān)視器的圖標(biāo)。
2. 通過單擊選中“將 Windows 桌面擴(kuò)展到該監(jiān)視器上”復(fù)選框。啟用此功能后,您可以在屏幕上將項(xiàng)目拖動到其他監(jiān)視器上,也可以調(diào)整窗口的大小,將窗口擴(kuò)展到多臺監(jiān)視器上。
在多臺監(jiān)視器間移動項(xiàng)目
1. 在“顯示屬性”對話框的“設(shè)置”選項(xiàng)卡上,單擊“識別”,以在每臺監(jiān)視器上顯示一個(gè)大型數(shù)字。此數(shù)字表明各監(jiān)視器對應(yīng)的圖標(biāo)。
2. 單擊監(jiān)視器圖標(biāo)并將圖標(biāo)拖動到不同的位置上,這些位置分布代表了您希望在兩臺監(jiān)視器間移動項(xiàng)目的方式。然后單擊“確定”或“應(yīng)用”。
3. 在屏幕上拖動桌面上的項(xiàng)目,直到它出現(xiàn)在另一臺監(jiān)視器上。也可以調(diào)整窗口的大小,將窗口擴(kuò)展到多臺監(jiān)視器上。
使用雙視屏
在多數(shù)便攜式計(jì)算機(jī)和某些臺式計(jì)算機(jī)(一個(gè)視頻卡上帶有兩個(gè)視頻端口)上,您可以使用雙視屏將顯示區(qū)域擴(kuò)展到另一臺監(jiān)視器上。雙視屏與多臺監(jiān)視器的功能十分相近,不同之處是您無法選擇主顯示器。在便攜式計(jì)算機(jī)上,主監(jiān)視器始終是 LCD 顯示屏幕。在臺式計(jì)算機(jī)上,第一個(gè)視頻輸出端口連接的是主監(jiān)視器。當(dāng)您連接了第二臺監(jiān)視器并打開計(jì)算機(jī)后,使用“控制面板”中的“顯示”工具對您的設(shè)置進(jìn)行配置,步驟與配置多臺監(jiān)視器相同。您可以在有接埠或無接埠的便攜式計(jì)算機(jī)上使用雙視屏。
以上摘自【如何在 Windows XP 中配置和使用多臺監(jiān)視器】
http://support.microsoft.com/kb/307873/zh-cn
Win 98之后開始支持多顯示器(Multiple Display)。Windows多顯示器情況分為兩種,一是單顯卡多顯示器,一是多顯卡多顯示器。前一種的多顯示器依靠顯卡的多個(gè)接口,一般顯卡有D-Sub接口+DVI-I接口(相關(guān)資料請看顯卡接口一文)。后一種通過不同的顯示器接到不同的顯卡來實(shí)現(xiàn)。 多顯示器的情況就給編些GUI帶來了困難,但是多顯示器也帶來了好處,可以將多個(gè)顯示器組合起來做成大面積屏幕,可以看電影了,只是這樣成本高了點(diǎn)。
一般PC配有一塊顯卡和一臺顯示器,但是可以在主板上再插一塊顯卡,然后使用兩個(gè)顯示器。后加入的顯示器被Windows設(shè)置為主顯示器(主屏),另外的顯示器叫做副顯示器(副屏)。其中主屏的坐標(biāo)被設(shè)為(0,0),打開控制面板->顯示,打開顯示對話框,進(jìn)入設(shè)置面板,可以看到多個(gè)顯示器,同時(shí)可以知道哪個(gè)是主屏,哪個(gè)是副屏,并且可以通過鼠標(biāo)拖動副屏來調(diào)整副屏相對于主屏的位置。如果只有一塊顯卡,該顯卡有多個(gè)輸出接口,可以將不同的顯示器接到不同的輸出接口來實(shí)現(xiàn)多屏,此時(shí)主屏不能選擇,筆記本上主顯示器是LCD(液晶屏),臺式機(jī)為連接顯卡第一個(gè)輸出接口的顯示器。
下面就我實(shí)際開發(fā)中遇到的問題,結(jié)合《Programming for Multiple Monitors in Windows 98》這樣一篇文章,講述一下多顯示器情況下的編程。
為方便描述,現(xiàn)假設(shè)PC原有一臺顯示器,坐標(biāo)分辨率為(1024*768),然后再添加一顯卡和顯示器,分辨率為(800*600),這樣(800*600)的顯示器成為主屏,(1024*768)的顯示器成為副屏。下面以此例進(jìn)行描述,為了便于理解,有些以屏幕取代顯示器:
一、虛擬桌面(Virtual desktop)
一臺顯示器時(shí),虛擬桌面就是所看到的桌面,坐標(biāo)(0,0),大小(1024,768)。2臺顯示器時(shí),副屏坐標(biāo)為(800,0),大小為(1024*768),虛擬桌面坐標(biāo)(0,0),大小 (1824,768),此時(shí)的虛擬桌面并非你看到的2個(gè)顯示器中的任何一個(gè)。示意圖如下:
由上圖可見,Virtual desktop是兩者拼接起來的結(jié)果。
二、多顯示器相關(guān)API
1. 數(shù)據(jù)類型
HMONITOR 顯示器的句柄
MONITORINFO 顯示器信息
MONITORINFOEX 顯示器信息(上面結(jié)構(gòu)的擴(kuò)展)
typedef struct tagMONITORINFO
{
DWORD cbSize;
RECT rcMonitor;
RECT rcWork;
DWORD dwFlags;
} MONITORINFO, *LPMONITORINFO;
typedef struct tagMONITORINFOEXA
{
MONITORINFO;
TCHAR szDevice[CCHDEVICENAME];
} MONITORINFOEX, *LPMONITORINFOEX;
2. 獲得某點(diǎn)所在的屏幕
HMONITOR MonitorFromPoint(POINT pt,DWORD dwFlags);
Pt為點(diǎn)坐標(biāo)
dwFlags可取下面的值,表示沒有任何顯示器包含該點(diǎn)時(shí),返回什么值MONITOR_DEFAULTTONULL(返回NULL)
MONITOR_DEFAULTTOPRIMARY(返回主屏)
MONITOR_DEFAULTTONEAREST(返回最靠近該目標(biāo)的屏幕)
3. 獲取某矩形區(qū)域,窗口所在屏幕
HMONITOR MonitorFromRect(LPRECT lprc,DWORD dwFlags);
lprc為指定矩形區(qū)域
dwFlags含義與2相同
HMONITOR MonitorFromWindow(HWND hWnd,DWORD dwFlags);
hWnd為指定窗口
dwFlags含義同2
這兩個(gè)接口返回包含目標(biāo)最多的屏幕,如果沒有任何屏幕包含目標(biāo),那么根據(jù)第二個(gè)參數(shù)返回具體的值。
4. 獲取顯示器信息
BOOL GetMonitorInfo( HMONITOR hmonitor, LPMONITORINFO lpmi);
hmonitor 顯示器句柄
lpmi MONITORINFO或MONITORINFOEX結(jié)構(gòu)指針
注意MONITORINFOEX是MONITORINFO的超集,作為參數(shù)時(shí)需先設(shè)置它的cbSize屬性,使它等于自身的大小。
可以這樣使用
MONITORINFOEX mix;
mix.cbSize = sizeof(mix);
GetMonitorInfo(hMonitor, (LPMONITORINFO)&mix);
5. 獲取顯示器的寬和高
GetSystemMetrics(int nIndex);
使用SM_CXSCREEN,SM_CYSCREEN可以獲取主屏大小(800, 600)
如果要獲得虛擬桌面的大小,需要使用SM_CXVIRTUALSCREEN,SM_CYVIRTUALSCREEN,此時(shí)獲取的大小為(1824, 768)
6. 獲取工作區(qū)大小
BOOL SystemParametersInfo(
UINT uiAction, // system parameter to retrieve or set
UINT uiParam, // depends on action to be taken
PVOID pvParam, // depends on action to be taken
UINT fWinIni // user profile update option
);
上面函數(shù)對使用uiAction為SPI_GETWORKAREA,SPI_SETWORKAREA時(shí),做了改進(jìn),以前總是對主屏進(jìn)行操作。 現(xiàn)在要獲取其他屏幕的屬性,可以使用GetMonitorInfo,要設(shè)置其他屏幕可以在uiAction為SPI_SETWORKAREA時(shí),將RECT作為pvParam,這樣就可以設(shè)置包含該RECT的顯示器。
7. 便利相關(guān)顯示器
BOOL WINAPI EnumDisplayMonitors(
HDC hdc,
LPCRECT lprcClip,
MONITORENUMPROC lpfnEnum,
LPARAM dwData);
hdc 設(shè)備環(huán)境
lprcClip 矩形區(qū)域
lpfnEnum 回調(diào)函數(shù)
dwData 傳給回調(diào)函數(shù)的參數(shù)
回調(diào)函數(shù)需要有下面的形式
BOOL CALLBACK MonitorEnumProc(
HMONITOR hmonitor,
HDC hdcMonitor,
LPRC lprcMonitor,
DWORD dwData);
下面引用《Programming for Multiple Monitors in Windows 98》的原文說明
The MONITORENUMPROC callback is called for each monitor that intersects the visible region of hdc and the lprcClip parameter. If the lprcClip parameter is NULL, then no additional clipping is performed. The dwData parameter is for user-defined data and is passed through to the dwData parameter in the callback function. MONITORENUMPROC is a user-defined callback function that must have the following signature:
BOOL CALLBACK MonitorEnumProc(
HMONITOR hmonitor,
HDC hdcMonitor,
LPRC lprcMonitor,
DWORD dwData);
If the hdc passed to EnumDisplayMonitors was NULL, then hdcMonitor is NULL. Otherwise, hdcMonitor contains a valid device context whose color attributes match the display monitor defined by hmonitor. If hdcMonitor is NULL, then lprcMonitor is in virtual-desktop coordinates. It is important to note that no application needs to use EnumDisplayMonitors to handle monitors of differing bit depths, since Windows automatically dithers high-color images on lower-color devices. You should use this function only if you want to do custom dithering to ensure the best possible display. In order to help you understand exactly how EnumDisplayMonitors is used, I will present a couple of code snippets illustrating common usage scenarios.
One use for EnumDisplayMonitors is to make sure that images are drawn optimally on lower-color devices. The best way to do this is to change how your window's WndProc handles the WM_PAINT message.
case WM_PAINT:
HDC hdc;
hdc = BeginPaint(hWnd,
&paintStruct);
EnumDisplayMonitors(hdc, NULL, monitorEnumPaintProc, 0);
EndPaint(&paintStruct);
Inside your callback, you query the passed device context to determine its capabilities and display area and do your drawing accordingly.
8. 枚舉顯示器設(shè)備
BOOL WINAPI EnumDisplayDevices(
PVOID Unused, //Reversed, Set to NULL
DWORD iDevNum, //index of monitor to query information
PDISPLAY_DEVICE lpDisplayDevice, //output information
DWORD dwFlags); //set to 0
其中iDevNum是指查詢設(shè)備的索引,以0為基數(shù),如果有該設(shè)備存在則填充lpDisplayDevice,返回TRUE;如果沒有該設(shè)備,則返回FALSE。如果要枚舉所有的設(shè)備,那么需要讓iDevNum從0開始一直調(diào)用該函數(shù),知道返回FALSE為止。
第三個(gè)參數(shù)的結(jié)構(gòu)定義如下:
typedef struct _DISPLAY_DEVICE {
DWORD cb;
BYTE DeviceName[32]; //name of the device. Same as value get by GetMonitorInfo
BYTE DeviceString[128]; //Firendly name of the device
DWORD StateFlags; //不詳
} DISPLAY_DEVICE, *PDISPLAY_DEVICE,
*LPDISPLAY_DEVICE;
StateFlags參數(shù)含義不詳,但是可以通過它的取值看出些漢以來:
#define DISPLAY_DEVICE_ATTACHED_TO_DESKTOP
0x00000001
#define DISPLAY_DEVICE_MULTI_DRIVER
0x00000002
#define DISPLAY_DEVICE_PRIMARY_DEVICE
0x00000004
#define DISPLAY_DEVICE_MIRRORING_DRIVER
0x00000008
#define DISPLAY_DEVICE_VGA_COMPATIBLE
0x00000010
下面引用《Programming for Multiple Monitors in Windows 98》的原文說明
Since EnumDisplayDevices allows you to query devices that aren't part of the desktop, your application can use monitors in an exclusive manner, without having to share the screen with the desktop. To do this, find a device that doesn't have the DISPLAY_DEVICE_ATTACHED_TO_DESKTOP bit set and call the Win32 API function CreateDC, passing the name returned in the DeviceName member of lpDisplayDevice. If you create a device context in this manner, you should delete it when you're done with it by calling DeleteDC.
9.
三、GUI編程注意事項(xiàng)
GUI編程使用了顯示器,此時(shí)如果不考慮多顯示器情況,可能出現(xiàn)顯示問題。例如用戶當(dāng)前將任務(wù)條拖放到副屏上,在副屏上進(jìn)行操作,運(yùn)行程序后程序出現(xiàn)在主屏上,這會讓用戶感覺程序沒有運(yùn)行,但這并不是主要問題。 當(dāng)用戶將主屏上的窗口拖放到副屏后,點(diǎn)擊某個(gè)按鈕或菜單,此時(shí)程序進(jìn)行了動態(tài)的位置調(diào)整,坐標(biāo)設(shè)想為(0,0),那么窗口又從副屏跑回主屏了,此時(shí)我想用戶會覺得惱火。 具體的做法可以在窗口創(chuàng)建的時(shí)候和窗口移動的時(shí)候,獲取窗口所處屏幕信息,并記錄下當(dāng)前顯示屏的原點(diǎn)。例如:
CPOINT m_ ptOrg; //在.h文件中聲明變量
//在WM_MOVE或者窗口初始化時(shí)調(diào)用, 保存原點(diǎn)信息
HMONITOR hWndMonitor = MonitorFromWindow(GetSafeHwnd(), MONITOR_DEFAULTTONULL);
MONITORINFOEX monitorInfo;
if (hWndMonitor == NULL) return;
monitorInfo.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(hWndMonitor, &monitorInfo);
m_ptOrg.x = monitorInfo.left
m_ptOrg.y = monitorInfo.top
當(dāng)調(diào)用SetWindowPos時(shí),需要注意此時(shí)傳遞的RECT的原點(diǎn)應(yīng)該以哪個(gè)計(jì)算。
四、多窗口的一些有趣的事情
一般第二個(gè)窗口的原點(diǎn)橫坐標(biāo)是第一個(gè)窗口的寬,任務(wù)欄和桌面顯示在主屏上。默認(rèn)情況下,副屏在主屏的右邊,鼠標(biāo)可以向左移動出主屏外。并且可以將任務(wù)欄拖到副屏中。
多窗口時(shí),Control Panel會記住上次的位置,下次打開的時(shí)候還在原來的屏幕上出現(xiàn)。例如打開Control Panel,此時(shí)顯示在主屏上,如果將它移動到副屏上,然后關(guān)閉,再次打開的時(shí)候會出現(xiàn)在副屏上。