基于WINDOWS 32API封装的显示器类: (2) 源文件

来源:互联网 发布:精准医学 大数据 编辑:程序博客网 时间:2024/06/08 19:27

  1#include "stdafx.h"
  2#include "monitor.h"
  3#include <stack>
  4#include <cassert>
  5using namespace std;
  6
  7/***************************************************************************************
  8   2009-12-5 当显示器不存在时,要删除窗口记录信息
  9   2009-12-8 改为使用相对于父窗口的位置来恢复子窗口,这样当父窗口位置和大小变化时,
 10             子窗口都能正确恢复
 11****************************************************************************************/
 12
 13//CMonitor实现
 14CMonitor::CMonitor(HMONITOR hMonitor, DWORD dwIndex):
 15m_hMonitor(hMonitor),
 16m_dwIndex(dwIndex)
 17{
 18    MONITORINFOEX mi;
 19    mi.cbSize = sizeof( mi );
 20    ::GetMonitorInfo( m_hMonitor, &mi );
 21    m_strName = mi.szDevice;
 22}
 23
 24//获取显示器的整个区域
 25void CMonitor::GetMonitorRect(RECT& rect) const
 26{
 27    MONITORINFO mi;
 28    RECT        rc;
 29    mi.cbSize = sizeof( mi );
 30    ::GetMonitorInfo( m_hMonitor, &mi );
 31    rc = mi.rcMonitor;
 32
 33    ::SetRect(&rect, rc.left, rc.top, rc.right, rc.bottom );
 34}
 35//获取显示器的工作区域
 36void CMonitor::GetWorkAreaRect(RECT& rect) const
 37{
 38    MONITORINFO mi;
 39    RECT        rc;
 40    mi.cbSize = sizeof( mi );
 41    ::GetMonitorInfo( m_hMonitor, &mi );
 42    rc = mi.rcWork;
 43
 44    ::SetRect(&rect, rc.left, rc.top, rc.right, rc.bottom );
 45}
 46//获取显示器的像素高度
 47DWORD CMonitor::GetPixelHeight() const
 48{
 49    DEVMODE devmode;
 50    devmode.dmSize = sizeof(DEVMODE);
 51    EnumDisplaySettings(m_strName.c_str(), ENUM_CURRENT_SETTINGS, &devmode);
 52    return devmode.dmPelsHeight;
 53}
 54//获取显示器的像素宽度
 55DWORD CMonitor::GetPixelWidth() const
 56{
 57    DEVMODE devmode;
 58    devmode.dmSize = sizeof(DEVMODE);
 59    EnumDisplaySettings(m_strName.c_str(), ENUM_CURRENT_SETTINGS, &devmode);
 60    return devmode.dmPelsWidth;
 61}
 62//获取显示器每单位像素的位数
 63DWORD CMonitor::GetBitsPerPixel() const
 64{
 65    DEVMODE devmode;
 66    devmode.dmSize = sizeof(DEVMODE);
 67    EnumDisplaySettings(m_strName.c_str(), ENUM_CURRENT_SETTINGS, &devmode);
 68    return devmode.dmBitsPerPel;
 69}
 70//获取显示器的显示频率
 71DWORD CMonitor::GetDisplayFrequency() const
 72{
 73    DEVMODE devmode;
 74    devmode.dmSize = sizeof(DEVMODE);
 75    EnumDisplaySettings(m_strName.c_str(), ENUM_CURRENT_SETTINGS, &devmode);
 76    return devmode.dmDisplayFrequency;
 77}
 78//获取显示器的左上角X位置
 79DWORD CMonitor::GetMonitorLeft() const
 80{
 81    DEVMODE devmode;
 82    devmode.dmSize = sizeof(DEVMODE);
 83    EnumDisplaySettings(m_strName.c_str(), ENUM_CURRENT_SETTINGS, &devmode);
 84    return devmode.dmPosition.x;
 85}
 86//获取显示器的左上角Y位置
 87DWORD CMonitor::GetMonitorTop() const
 88{
 89    DEVMODE devmode;
 90    devmode.dmSize = sizeof(DEVMODE);
 91    EnumDisplaySettings(m_strName.c_str(), ENUM_CURRENT_SETTINGS, &devmode);
 92    return devmode.dmPosition.y;
 93}
 94//是否是主显示器
 95bool CMonitor::IsPrimaryMonitor() const
 96{
 97    MONITORINFO mi;
 98    mi.cbSize = sizeof( mi );
 99    ::GetMonitorInfo( m_hMonitor, &mi );
100    return mi.dwFlags == MONITORINFOF_PRIMARY;
101}
102
103//获取某矩形相对于显示器居中后的区域
104void CMonitor::CenterRectToMonitor( LPRECT lprc, bool bWorkArea /*=false*/) const
105{
106    int  w = lprc->right - lprc->left;
107    int  h = lprc->bottom - lprc->top;
108
109    RECT rect;
110    if (bWorkArea)
111        GetWorkAreaRect(rect);
112    else
113        GetMonitorRect(rect);
114
115    lprc->left = rect.left + ( rect.right - rect.left - w ) / 2;
116    lprc->top = rect.top + ( rect.bottom - rect.top - h ) / 2;
117    lprc->right    = lprc->left + w;
118    lprc->bottom = lprc->top + h;
119}
120
121//CMonitorManager 实现
122///< 单件定义宏
123SINGLETON_IMPLEMENT(CMonitorManager)
124
125CMonitorManager::CMonitorManager()
126{
127   UpdateMonitors();
128}
129
130CMonitorManager::~CMonitorManager()
131{
132   FreeMonitors();
133}
134
135//初始化系统当前拥有的显示器
136void CMonitorManager::UpdateMonitors()
137{
138   FreeMonitors();
139   ::EnumDisplayMonitors(NULL, NULL, AddMonitorsCallBack, (LPARAM)this);
140}
141
142void CMonitorManager::FreeMonitors()
143{
144    for (vector<CMonitor*>::iterator iter=m_vec_monitor.begin(); iter!=m_vec_monitor.end();)
145    {
146        delete (*iter); iter = m_vec_monitor.erase(iter);
147    }
148}
149//获取系统当前显示器的个数
150DWORD CMonitorManager::GetCount()
151{
152   return m_vec_monitor.size();
153}
154//根据索引获取某个显示器
155CMonitor* CMonitorManager::GetMonitor(DWORD dwIndex)
156{
157    assert(dwIndex > 0);
158    if (dwIndex > m_vec_monitor.size())  return NULL;
159    return m_vec_monitor[dwIndex-1];
160}
161//获取主显示器
162CMonitor* CMonitorManager::GetPrimaryMonitor()
163{
164   for (vector<CMonitor*>::iterator iter=m_vec_monitor.begin();iter!=m_vec_monitor.end();++iter)
165   {
166       if ((*iter)->IsPrimaryMonitor()) return (*iter);
167   }
168   return NULL;
169}
170//获取相对某矩形最近的显示器
171CMonitor* CMonitorManager::GetNearestMonitor(const RECT& rect)
172{
173    HMONITOR hMonitor = ::MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST);
174    assert(hMonitor);
175    return FindMonitor(hMonitor);
176}
177//获取相对某点最近的显示器
178CMonitor* CMonitorManager::GetNearestMonitor(const POINT& pt)
179{
180    HMONITOR hMonitor = ::MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
181    assert(hMonitor);
182    return FindMonitor(hMonitor);
183}
184//获取相对某窗口最近的显示器
185CMonitor* CMonitorManager::GetNearestMonitor(HWND hWnd)
186{
187    HMONITOR hMonitor = ::MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
188    assert(hMonitor);
189    return FindMonitor(hMonitor);
190}
191//根据某句柄获取显示器
192CMonitor* CMonitorManager::FindMonitor(HMONITOR hMonitor)
193{
194    for (vector<CMonitor*>::iterator iter=m_vec_monitor.begin(); iter!=m_vec_monitor.end();++iter)
195    {
196        if ((*iter)->m_hMonitor == hMonitor) return (*iter);
197    }
198    return NULL;
199}
200//WIN32回调API,在这个回调函数内实现初始化,当前有多少个显示器,就回调多少次
201BOOL CALLBACK CMonitorManager::AddMonitorsCallBack(HMONITOR hMonitor,HDC hdcMonitor,LPRECT lprcMonitor,
202       LPARAM dwData)
203{
204   CMonitorManager* pMonitorManger = (CMonitorManager*)dwData;
205   int nIndex = pMonitorManger->m_vec_monitor.size();
206   CMonitor* pMonitor = new CMonitor(hMonitor, ++nIndex);
207   pMonitorManger->m_vec_monitor.push_back(pMonitor);
208   return TRUE;
209}
210
211//获取虚拟桌面(也就是由当前所有显示器组成的一个桌面)的区域大小
212void CMonitorManager::GetVirtualDesktopRect(RECT& rect)
213{
214    ::SetRect(&rect,::GetSystemMetrics( SM_XVIRTUALSCREEN ),::GetSystemMetrics( SM_YVIRTUALSCREEN ),
215             ::GetSystemMetrics( SM_CXVIRTUALSCREEN ),::GetSystemMetrics( SM_CYVIRTUALSCREEN ));
216}
217//获取某矩形相对于虚拟桌面居中后的区域
218void CMonitorManager::CenterWindowToAll(RECT& rect, bool bUseWorkArea /* = false */)
219{
220    RECT rcAll, rcWork;
221    int  iWidth, iHeight;
222    if (bUseWorkArea)
223    {
224        GetPrimaryMonitor()->GetWorkAreaRect(rcWork);
225        GetVirtualDesktopRect(rcAll);
226        iWidth = rect.right-rect.left, iHeight = rect.bottom-rect.top;
227        rect.left = rcWork.left + (rcAll.right-rcAll.left-iWidth)/2;
228        rect.top  = rcWork.top + (rcAll.bottom-rcAll.top-iHeight)/2;
229        rect.right = rect.left + iWidth;
230        rect.bottom = rect.top + iHeight;
231    }
232    else
233    {
234        GetVirtualDesktopRect(rcAll);
235        iWidth = rect.right-rect.left, iHeight = rect.bottom-rect.top;
236        rect.left = rcAll.left + (rcAll.right-rcAll.left-iWidth)/2;
237        rect.top  = rcAll.top + (rcAll.bottom-rcAll.top-iHeight)/2;
238        rect.right = rect.left + iWidth;
239        rect.bottom = rect.top + iHeight;
240    }
241}
242/**
243  @brief  居中窗口
244  @param hWnd  窗口句柄
245  @param iMonitorIndex  显示器索引,其参数意义如下:   
246  1)<0--则表示在整个桌面居中 2)0--则在当前显示器居中 3)>=1--则表示在其它显示器居中
247  @param bUseWorkArea  是否在对应显示器工作区中居中: true在显示器工作区居中,false在显示器桌面居中 
248*/
249void CMonitorManager::CenterWindow(HWND hWnd,int iMonitorIndex /* = 0 */, bool bUseWorkArea /* = false*/)
250{
251    RECT rect;
252    ::GetWindowRect(hWnd, &rect );
253    if (0 > iMonitorIndex )
254    {
255       CenterWindowToAll(rect, bUseWorkArea);
256    }
257    else if (0 == iMonitorIndex)
258    {
259       CMonitorManager::GetNearestMonitor(hWnd)->CenterRectToMonitor(&rect,bUseWorkArea);
260    }
261    else
262    {
263        CMonitor* pMonitor = CMonitorManager::GetMonitor(iMonitorIndex);
264        if (!pMonitor)  return;
265        pMonitor->CenterRectToMonitor(&rect, bUseWorkArea);
266    }
267    ::SetWindowPos(hWnd, NULL, rect.left, rect.top, 0, 0, SWP_NOSIZE|SWP_NOZORDER);
268}
269
270/**
271    @brief 单显示器全屏
272    @param hWnd 被全屏的窗口
273    @param bFullScreen 是否全屏: true表示全屏,false表示恢复
274    @param iMonitorIndex 显示器索引,其参数意义如下:   
275    1)<0--则表示在整个桌面全屏 2)0--则在当前显示器全屏 3)>=1--则表示在其它显示器全屏
276    * 彻底实现全屏,包括去除边框样式,只留客户区
277    @return  true表示操作成功,已经全屏或恢复;false表示操作失败,没有全屏或恢复
278    * FullScreenWindow(hWnd,true,iMonitorIndex)和FullScreenWindow(hWnd,false)要成对调用用于全屏和恢复
279*/
280bool CMonitorManager::FullScreenWindow(HWND hWnd, bool bFullScreen, int iMonitorIndex /*= 0*/)
281{
282    if (!hWnd||!IsWindow(hWnd))  return false;
283
284    stack<HWND>  WndStack;
285    HWND         hParent;
286    map<HWND, WndInfo>::iterator iter;
287
288    long lOldStyle, lNewStyle;
289    long lOldExStyle, lNewExStyle;
290    RECT rcNew, rcOld, rcMonitor;
291    lNewStyle = lOldStyle = GetWindowLong(hWnd, GWL_STYLE);
292    lOldExStyle = lNewExStyle = GetWindowLong(hWnd, GWL_EXSTYLE);
293
294    if (bFullScreen)
295    {
296        GetWindowRect(hWnd, &rcOld);
297        hParent = GetParent(hWnd);
298        if (hParent && (lOldStyle&WS_CHILD))
299        {
300            ScreenToClient(hParent, rcOld);
301        }
302        m_map_wnd.insert(make_pair(hWnd, WndInfo(lOldStyle, lOldExStyle, rcOld, false)));
303    }   
304    if (lOldStyle & WS_CHILD)
305    {
306        for (HWND hTempParent = GetParent(hWnd); hTempParent; )
307        {
308            hParent = hTempParent; hTempParent = GetParent(hParent);
309            WndStack.push(hParent);
310            lOldStyle = GetWindowLong(hParent, GWL_STYLE);
311            if (bFullScreen)
312            {
313                GetWindowRect(hParent, &rcOld);
314                lOldExStyle = GetWindowLong(hParent, GWL_EXSTYLE);
315                if (hTempParent && (lOldStyle&WS_CHILD))
316                {
317                    ::ScreenToClient(hTempParent, rcOld);
318                }
319                m_map_wnd.insert(make_pair(hParent, WndInfo(lOldStyle, lOldExStyle, rcOld, false)));
320            }
321            if (lOldStyle&WS_POPUP || lOldStyle&WS_OVERLAPPED)  break;
322        }
323    }
324    else   //弹出式或重叠窗口
325    {
326        if (bFullScreen)
327        {
328         if (lOldStyle & WS_CAPTION)  lNewStyle &= ~WS_CAPTION;
329           if (lOldStyle & WS_DLGFRAME) lNewStyle &= ~WS_DLGFRAME;
330           if (lOldStyle & WS_THICKFRAME) lNewStyle &= ~WS_THICKFRAME;
331           if (lOldStyle & WS_BORDER) lNewStyle &= ~WS_BORDER;
332           if ((lOldExStyle & WS_EX_DLGMODALFRAME)) lNewExStyle &= ~WS_EX_DLGMODALFRAME;
333           if (lOldExStyle & WS_EX_WINDOWEDGE) lNewExStyle &= ~WS_EX_WINDOWEDGE;
334           if (lOldExStyle != lNewExStyle)  SetWindowLong(hWnd, GWL_EXSTYLE, lNewExStyle);
335           if (lOldStyle != lNewStyle)      SetWindowLong(hWnd, GWL_STYLE, lNewStyle);
336        }
337    }
338    //逐层全屏或恢复其父窗口
339    if (bFullScreen)
340    {
341        if (0 > iMonitorIndex)
342        {
343            GetVirtualDesktopRect(rcMonitor);
344        }
345        else if (0 == iMonitorIndex)
346        {
347            GetNearestMonitor(hWnd)->GetMonitorRect(rcMonitor);
348        }
349        else
350        {
351            CMonitor* pMonitor = GetMonitor(iMonitorIndex);
352            if (!pMonitor)
353            {
354                m_map_wnd.erase(hWnd);    return false;
355            }
356            pMonitor->GetMonitorRect(rcMonitor);
357        }
358        rcNew = rcMonitor;
359    }
360    for (; !WndStack.empty(); WndStack.pop())
361    {
362        hParent = WndStack.top();
363        iter = m_map_wnd.find(hParent);
364        if (bFullScreen)
365        {
366            if (iter != m_map_wnd.end() && (*iter).second._bFull) continue;
367            lOldStyle = lNewStyle = GetWindowLong(hParent,GWL_STYLE);
368            lOldExStyle = lNewExStyle = GetWindowLong(hParent, GWL_EXSTYLE);
369            if (lOldStyle & WS_CAPTION)  lNewStyle &= ~WS_CAPTION;
370            if (lOldStyle & WS_BORDER)   lNewStyle &= ~WS_BORDER;
371            if (lOldStyle & WS_DLGFRAME) lNewStyle &= ~WS_DLGFRAME;
372            if (lOldStyle & WS_THICKFRAME) lNewStyle &= ~WS_THICKFRAME;
373          if (lOldExStyle & WS_EX_DLGMODALFRAME) lNewExStyle &= ~WS_EX_DLGMODALFRAME;
374            if (lOldExStyle & WS_EX_WINDOWEDGE)    lNewExStyle &= ~WS_EX_WINDOWEDGE;
375            if (lOldExStyle != lNewExStyle)    SetWindowLong(hParent, GWL_EXSTYLE, lNewExStyle);
376            if (lOldStyle != lNewStyle)     SetWindowLong(hParent, GWL_STYLE, lNewStyle);
377      if (lOldStyle & WS_CHILD)
378            {
379                ScreenToClient(hParent, rcNew);
380            }
381            SetWindowPos(hParent, 0, rcNew.left,rcNew.top,rcNew.right-rcNew.left,rcNew.bottom-rcNew.top,
382                         SWP_SHOWWINDOW|SWP_NOZORDER|SWP_FRAMECHANGED);
383            (*iter).second._bFull = true;
384        }
385        else
386        {
387            if (iter == m_map_wnd.end() || !(*iter).second._bFull)  continue;
388            WndInfo& wndinfo = (*iter).second; wndinfo._bFull = false;
389            rcOld = wndinfo._rcWnd;
390            SetWindowLong(hParent, GWL_STYLE, wndinfo._lStyle);
391            SetWindowLong(hParent, GWL_EXSTYLE, wndinfo._lExStyle);
392            SetWindowPos(hParent, 0, rcOld.left,rcOld.top,rcOld.right-rcOld.left,rcOld.bottom-rcOld.top,
393                         SWP_SHOWWINDOW|SWP_NOZORDER);
394            m_map_wnd.erase(iter);
395        }
396    }
397    //全屏或恢复本窗口
398    hParent = GetParent(hWnd);     iter = m_map_wnd.find(hWnd);
399    if (bFullScreen)
400    {
401        if (iter != m_map_wnd.end() && (*iter).second._bFull)  return true;
402        lOldStyle = GetWindowLong(hWnd, GWL_STYLE);
403        if (hParent && (lOldStyle & WS_CHILD))
404        {
405            for(HWND hChild = ::GetTopWindow(hParent); hChild; hChild = ::GetNextWindow(hChild, GW_HWNDNEXT))
406            {
407                if (hChild != hWnd) ::ShowWindow(hChild, SW_HIDE);
408            }
409            ScreenToClient(hParent, rcNew);
410        }
411        SetWindowPos(hWnd, 0, rcNew.left,rcNew.top,rcNew.right-rcNew.left,rcNew.bottom-rcNew.top,
412            SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOZORDER);
413        (*iter).second._bFull = true;
414    }
415    else
416    {
417     if (iter == m_map_wnd.end() || !(*iter).second._bFull)  return true;
418       WndInfo& wndinfo = (*iter).second; wndinfo._bFull = false;
419       rcOld = wndinfo._rcWnd;
420       SetWindowLong(hWnd, GWL_STYLE, wndinfo._lStyle);
421       SetWindowLong(hWnd, GWL_EXSTYLE, wndinfo._lExStyle);
422       if (hParent && (wndinfo._lStyle & WS_CHILD))
423       {
424           for(HWND hChild = ::GetTopWindow(hParent); hChild; hChild = ::GetNextWindow(hChild, GW_HWNDNEXT))
425           {
426              ::ShowWindow(hChild, SW_SHOWNORMAL);
427           }
428       }
429       SetWindowPos(hWnd, 0, rcOld.left,rcOld.top,rcOld.right-rcOld.left,rcOld.bottom-rcOld.top,
430           SWP_SHOWWINDOW|SWP_NOZORDER);
431       m_map_wnd.erase(iter);
432    }
433    return true;
434}
435
436/**
437  @brief 双显示器全屏
438  @param hWndFirst  在显示器1全屏的窗口句柄
439  @param hWndSecond 在显示器2全屏的窗口句柄
440  @return  true表示全屏都成功,false表示至少有一个全屏失败
441*/
442bool CMonitorManager::FullScreenWindow(HWND hWndFirst, HWND hWndSecond)
443{
444    if (!hWndFirst || !IsWindow(hWndFirst) ) return false;
445    if (!hWndSecond || !IsWindow(hWndSecond)) return false;
446
447    RECT rcOld;
448    long lStyle, lExStyle;
449    HWND hFirstParent = 0, hSecondParent = 0, hTempParent;
450    bool bFullMainWnd = true;
451    for (hTempParent = GetParent(hWndFirst); hTempParent; )
452    {
453        hFirstParent = hTempParent; hTempParent = GetParent(hFirstParent);
454        if (hTempParent && (GetWindowLong(hFirstParent, GWL_STYLE)&WS_POPUP))
455        {
456            bFullMainWnd = false;
457        }
458    }
459    for (hTempParent = GetParent(hWndSecond); hTempParent; )
460    {
461        hSecondParent = hTempParent; hTempParent = GetParent(hSecondParent);
462        if (hTempParent && (GetWindowLong(hSecondParent, GWL_STYLE)&WS_POPUP))
463        {
464            bFullMainWnd = false;
465        }
466    }
467    if (hFirstParent && hSecondParent)
468    {
469        if (hSecondParent == hFirstParent && bFullMainWnd)
470        {
471            HWND hWnds[] = {hWndFirst, hWndSecond};
472            for (int i = 0; i < 2; ++i)
473            {
474                GetWindowRect(hWnds[i], &rcOld);
475                ScreenToClient(hFirstParent, rcOld);
476                lStyle = GetWindowLong(hWnds[i], GWL_STYLE);
477                lExStyle = GetWindowLong(hWnds[i], GWL_EXSTYLE);
478                m_map_wnd.insert(make_pair(hWnds[i], WndInfo(lStyle, lExStyle, rcOld, false)));
479            }
480            if (!FullScreenWindow(hFirstParent, true, -1))  return false;
481        }
482    }
483    if (!FullScreenWindow(hWndFirst, true, 1))   return false;
484    if (!FullScreenWindow(hWndSecond, true, 2))  return false;
485    ShowWindow(hWndFirst, SW_SHOWNORMAL); ShowWindow(hWndSecond, SW_SHOWNORMAL);
486    return true;
487}


原创粉丝点击