VC一些经验系列:《平均绘画矩形图,双击全屏》

1.RGB宏报错

RGB宏是这样的,

#define RGB(r,g,b)          ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16)))

但是penBlack.CreatePen(PS_SOLID, 3, #ff0000); 在有的文件中可以用,有的文件中会报错【error C2064: 项不会计算为接受 1 个参数的函数】

   我猜应该是编译器,包含的括号运算有一定的限制导致的。

所以改成((COLORREF)(((255)|((WORD)((0))<<8))|(((DWORD)(0))<<16)));  //(BYTE) 删除就可以了


            //draw rectangle
            dc.SelectStockObject(NULL_BRUSH); //不使用画刷

            CPen penBlack;

    //penBlack.CreatePen(PS_SOLID, 3, #ff0000);
            COLORREF crColor = ((COLORREF)(((255)|((WORD)((0))<<8))|(((DWORD)(0))<<16)));
            penBlack.CreatePen(PS_SOLID, 3, crColor);


            CPen* pOldPen = dc.SelectObject(&penBlack);
            dc.Rectangle(CRect(WndRect.left -2,WndRect.top -2, WndRect.right+1,WndRect.bottom+1));

2.  给出窗口的总数,计算每行要画多少窗口

//计算每行窗口的个数  //1 4 9 16 32 64 128 256
   float fMaxWndNumOfRow = sqrt((float)nNumOfLVWnd);
   long nTemp = fMaxWndNumOfRow;
   int nMaxWndNumOfRow = fMaxWndNumOfRow>nTemp?nTemp+1:nTemp;

3. 得到每行的窗口数量之后,就可以按照比例 1*1 ,  2*2, 3*3, 4*4, 5*5, 6*6,来画图了

  1 void CMainDialog::DeployLiveViewWnds(int nNumOfLVWnd)   //just Comment关于画图,最好用float---doubel 因为更精确
  2 {OutputDebugString(L"enter DeployLiveViewWnds");
  3 
  4    this->Invalidate();//reflash windows first
  5 
  6    nTotalWnd = nNumOfLVWnd;
  7 
  8 
  9    //计算每行窗口的个数  //1 4 9 16 32 64 128 256
 10    float fMaxWndNumOfRow = sqrt((float)nNumOfLVWnd);
 11    long nTemp = fMaxWndNumOfRow;
 12    int nMaxWndNumOfRow = fMaxWndNumOfRow>nTemp?nTemp+1:nTemp;
 13 
 14    
 15 
 16 
 17    int   i(0), nRow(0), nCol(0), nTempNumOfLVWnd(0);
 18    int   nLVWndWidth(0), nLVWndHeight(0);
 19    int   nNextX(0), nNextY(0), nNextWidth(0), nNextHeight(0);
 20    CRect rectClient;
 21    this->GetClientRect(rectClient);
 22 
 23 
 24    //==============
 25    //just 位移 让  右 和 下 都有足够的位置画完矩形,普通场合 右和下  会少一个像素
 26    rectClient.bottom = rectClient.bottom -2;
 27    rectClient.right =  rectClient.right -2;
 28    //==============
 29 
 30 
 31    // Get the width and height of live view window
 32    TCHAR temp[200];
 33    wsprintf(temp, L"CMainDialog::DeployLiveViewWnds ()  主窗口 left=%d, top=%d, right=%d, bottom=%d , ",rectClient.left, rectClient.top, rectClient.right, rectClient.bottom);
 34    OutputDebugString(temp);
 35 
 36    //bottom = 600
 37    //right = 800
 38 
 39 
 40    //1280  720
 41    //640-1   310-1
 42 
 43 
 44    //800* 600
 45    //400-1*300-1
 46    //if 1windows      0,    0, 400-1, 300-1
 47    //if 2windows    400,    0, 400-1, 300-1
 48    //if 3windows      0,  300, 400-1, 300-1
 49    //if 4windows    400,  300, 400-1, 300-1
 50 
 51 
 52    nLVWndWidth = (rectClient.right - PPT_LEFT_CTRL_PANEL_WIDTH - 1) / nMaxWndNumOfRow;  //(800 -0 -1) /2   = 399
 53    if (nNumOfLVWnd % nMaxWndNumOfRow == 0)
 54    {
 55           nTempNumOfLVWnd = nNumOfLVWnd;
 56           wsprintf(temp,L"nNumOfLVWnd = %d",nNumOfLVWnd);
 57             OutputDebugString(temp);
 58             //4 windows    //4%2 = 0    => nTempNumOfLVWnd = 4
 59    }
 60    else
 61       nTempNumOfLVWnd = nNumOfLVWnd + nMaxWndNumOfRow - (nNumOfLVWnd % nMaxWndNumOfRow);
 62       //1 windows    //1+2 -(1%2) = 2
 63       //9 windows    //9+3 -(9%3) = 3
 64 
 65    wsprintf(temp,L"hejie rectClient.bottom=%d,  nTempNumOfLVWnd=%d",rectClient.bottom,nTempNumOfLVWnd);
 66     OutputDebugString(temp);
 67 
 68    nLVWndHeight = (rectClient.bottom - PPT_BOTTOM_CTRL_PANEL_HEIGHT - 1) / (nTempNumOfLVWnd / nMaxWndNumOfRow);
 69    // (600-0-1)/   (2/2) => 599
 70    // (600-0-1)/   (2/2) => 599
 71    // (600-0-1)/   (4/2) => 299
 72    // (600-0-1)/   (4/2) => 299
 73    // (600-0-1)/   (9/3) => 199.6
 74 
 75     wsprintf(temp,L"hejie nLVWndHeight=%d",nLVWndHeight);
 76     OutputDebugString(temp);
 77 
 78    OutputDebugString(L"Deploy the windows of live view========");
 79    // Deploy the windows of live view
 80    for (i = 0; i < MAX_LIVE_VIEW_WINDOWS; i++) 
 81    {
 82       if (i < nNumOfLVWnd) {
 83 
 84           OutputDebugString(L"before InvalidateRect");
 85          m_pLVWnd[i]->InvalidateRect(NULL, FALSE);//redraw the rectangle
 86          nRow = i / nMaxWndNumOfRow;   //0++ / 2 =>  0  0.5  1  1.5
 87          nCol = i % nMaxWndNumOfRow;   //0++ % 2 =>  0  1    0  0 
 88          // Calculate the coordinates and size for each live view window
 89            nNextX = PPT_LEFT_CTRL_PANEL_WIDTH + (nCol * nLVWndWidth) + 1;
 90            nNextY = (nRow * nLVWndHeight) + 1;
 91 
 92            wsprintf(temp,L"hejie nNextX=%d,  nNextY=%d================",nNextX,nNextY);
 93            OutputDebugString(temp);
 94 
 95            if (rectClient.right - (nNextX + nLVWndWidth) < nLVWndWidth)
 96               nNextWidth = rectClient.right - nNextX - 1;
 97            else
 98                nNextWidth = nLVWndWidth;
 99          if ((rectClient.bottom - PPT_BOTTOM_CTRL_PANEL_HEIGHT) - (nNextY + nLVWndHeight) < nLVWndHeight)
100               nNextHeight = (rectClient.bottom - PPT_BOTTOM_CTRL_PANEL_HEIGHT) - nNextY - 1;
101          else
102             nNextHeight = nLVWndHeight;
103 
104           wsprintf(temp,L"moveWindows 第%d个子窗口 的 nNextX=%d,  nNextY=%d,  nNextWidth=%d, nNextHeight=%d ",i,nNextX,nNextY,nNextWidth,nNextHeight);
105           OutputDebugString(temp);
106           
107           
108           //让LiveViewWnd窗口小一点, 每个窗口中间的分隔大一点。offset值-2为了缩放窗口, 让给显示选中矩形框
109           m_pLVWnd[i]->MoveLVWindow(nNextX +2, nNextY +2, nNextWidth -2, nNextHeight-2);//modify the windwos Count!!!!!important    设置默认小窗口的size
110           m_pLVWnd[i]->ShowWindow(SW_SHOW);
111          
112 
113           //保留每个liveView Wnd的rect
114         if(LV_WND_4 == nTotalWnd ) 
115         {
116             SubLiveViewRect4[i] = CRect( nNextX +1, nNextY+1, nNextWidth + nNextX+2,  nNextHeight + nNextY+2);
117 
118             //left和top + 1是因为不和LiveView重合
119             //right 和bottom +2 是因为 前面offset已经+1了,然后需要再+1么?
120         }
121         else if(LV_WND_9 == nTotalWnd ) 
122         {
123             /*
124             #ifdef _AFX_NO_OCC_SUPPORT 
125             _AFXWIN_INLINE void CWnd::MoveWindow(int x, int y, int nWidth, int nHeight, BOOL bRepaint)
126                 { ASSERT(::IsWindow(m_hWnd)); ::MoveWindow(m_hWnd, x, y, nWidth, nHeight, bRepaint); }
127             #endif //_AFX_NO_OCC_SUPPORT
128             _AFXWIN_INLINE void CWnd::MoveWindow(LPCRECT lpRect, BOOL bRepaint)
129                 { MoveWindow(lpRect->left, lpRect->top, lpRect->right - lpRect->left,
130                     lpRect->bottom - lpRect->top, bRepaint); }
131             */
132             //我们可以知道x,y, nWidth,nHeight  如何通过rect得到,
133             //lpRect->left, lpRect->top, 
134             //lpRect->right - lpRect->left,     //3-1
135             //lpRect->bottom - lpRect->top,     //4-2 
136             //上面是MoveWinodws()的X,Y,Width,Height 值。    请看上面是MoveWindows()的定义
137 
138 
139 
140             //反过来,要换算成rect值,
141             //只需要nNextX , nNextY, nNextHeight + nNextX, nNextWidth + nNextY
142             
143 
144             SubLiveViewRect9[i] = CRect( nNextX +1 , nNextY +1, nNextWidth + nNextX+2 ,  nNextHeight + nNextY+2 );
145 
146              
147         }
148 
149 
150       }
151       else {
152          m_pLVWnd[i]->InvalidateRect(NULL, FALSE);
153          m_pLVWnd[i]->ShowWindow(SW_HIDE);
154       }
155    }
156 }
平均分隔多个窗口

 重点是:MoveWindow(x,y, width, height)要换算成Rect矩形,废了蛮多周折,才找到原因。 所以才会想起写下此篇文章。

我们的需求是这样的,

平均分隔各个视图后,

用户单击/双击 后,需要有选中矩形(单击/双击 选中后,可以操作此视图对象+数据对象;  双击 全屏放大    )

刷新如何不让丢失呢?在mainDialog的OnPaint()中,先判断nChooseIndex的值,这个值在subView中的单机事件中得到。

然后根据我们分隔画面的保存 CRect[i]来保存每个SubView的Rectangle,

然后就可在OnPaint()中画选中的矩形了

 1 void CMainDialog::OnPaint()
 2 {
 3     CPaintDC dc(this); // device context for painting
 4     // TODO: 在此处添加消息处理程序代码
 5     // 不为绘图消息调用 CDialog::OnPaint()
 6     
 7         //选中矩形,若单窗口模式下,则不画选中矩形
 8         if ( nTotalWnd != 1 )
 9         {
10             //draw rectangle
11             dc.SelectStockObject(NULL_BRUSH); //不使用画刷
12             CPen penBlack;
13             COLORREF crColor = ((COLORREF)(((255)|((WORD)((0))<<8))|(((DWORD)(0))<<16)));
14             penBlack.CreatePen(PS_SOLID, 2, crColor);//penBlack.CreatePen(PS_SOLID, 3, #ff0000);
15             CPen* pOldPen = dc.SelectObject(&penBlack);
16 
17             
18 
19             if (LV_WND_4 == nTotalWnd)
20             {
21             dc.Rectangle(&SubLiveViewRect4[nChooseWnd]);
22             }
23             
24             if (LV_WND_9 == nTotalWnd)
25             {
26             dc.Rectangle(&SubLiveViewRect9[nChooseWnd]);
27             }
28 
29         }
30 }
OnPaint

4、画矩形还有很多种方法

            //方法1.  实心矩形,和第4个方法是一样的,一个是实心,一个是空心
            CPen penBlack;
            penBlack.CreatePen(PS_TYPE_MASK, 3, #0000ff);
            m_pDC->SelectObject(&penBlack);
            m_pDC->Rectangle(&WndRect);
            penBlack.DeleteObject();
            
            //方法2.直接画线段,可以设置线的粗细,颜色  ,这个最好,但是麻烦点。
            CPen penBlack;
            penBlack.CreatePen(PS_SOLID, 3, #000000);
            m_pDC->SelectObject(&penBlack);
            m_pDC->MoveTo(WndRect.left -3, WndRect.top);
            m_pDC->LineTo(WndRect.left -3, WndRect.bottom -3  );
            m_pDC->LineTo(WndRect.right , WndRect.bottom  );
            m_pDC->LineTo(WndRect.right , WndRect.top );
            m_pDC->LineTo(WndRect.left -3, WndRect.top -3 );
            penBlack.DeleteObject();

            //方法3 .  空心,但是没有办法设置线的粗细
            CBrush brushBlue(#000000);
            dc.FrameRect(&WndRect,&brushBlue);

    

    //方法4 . 空心,可设置线的粗细,颜色

    CClientDC dc(this);   //获取设备句柄
            dc.SelectStockObject(NULL_BRUSH); //不使用画刷
            CPen penBlack;
            penBlack.CreatePen(PS_SOLID, 3, #ff0000);
            CPen* pOldPen = dc.SelectObject(&penBlack);
            //pOldPen->DeleteObject(); //大家可以试下DeleteObject penBlack和pOldPen 有什么区别
            //dc.Rectangle(CRect(WndRect.left -2,WndRect.top -2, WndRect.right+1,WndRect.bottom+1));
  

    //方法5  不能设置线的粗细,d3d不懂,如果错了,欢迎大家纠正,共同提高嘛,  不过朋友叫我速度学openGL ,他们那做游戏,如果想赚点钱,可以试试吧。

    //pDC->Draw3dRect(&WndRect,#ff0000,#00ff00);

5.双击全屏,再双击还原

我试过很多方法,最简单的就是MoveWindows,但是全屏后能还原小窗口的都不满意,

我就介绍一种完美的解决方案吧。

 1 void CLiveViewWnd::OnLButtonDblClk(UINT nFlags, CPoint point)
 2 {
 3     // TODO: 在此添加消息处理程序代码和/或调用默认值
 4     CMainDialog* mainDialog = NULL;
 5     mainDialog = (CMainDialog*) GetParent();
 6     mainDialog->nChooseWnd = m_ucWndNo;
 7 
 8     CStatic::OnLButtonDblClk(nFlags, point);
 9     OutputDebugString(L"enter =====================CLiveViewWnd::OnLButtonDblClk");
10     
11 
12     m_bFullScreen=!m_bFullScreen; // 设置全屏显示标志
13     LONG style = ::GetWindowLong(this->m_hWnd,GWL_STYLE);
14 
15     if(m_bFullScreen)//全屏显示
16     {
17      /*   //用MFC隐藏系统任务栏
18         CWnd * wnd = FindWindow(L"Shell_TrayWnd",NULL);
19         wnd->SetWindowPos(NULL,0,0,0,0,SWP_HIDEWINDOW);
20         */
21         
22         m_hWndParent=::GetParent(m_hWnd);   
23         ::ShowWindow(m_hWndParent,SW_HIDE); 
24 
25         ::SetParent(m_hWnd,NULL);   
26         style &= ~(WS_DLGFRAME | WS_THICKFRAME);
27         
28         SetWindowLong(this->m_hWnd,NULL, style);//SetWindowLong(this->m_hWnd,GWL_STYLE, style); GWL_STYLE表示MFC窗口属性,NULL表示没有窗口属性。
29         this->ShowWindow(SW_SHOWMAXIMIZED);//this->ShowWindow(SHOW_FULLSCREEN);
30 
31         //CRect rect;
32         //this->GetWindowRect(&rect);
33         //::SetWindowPos((this->m_hWnd,HWND_NOTOPMOST,rect.left-1, rect.top-1, rect.right-rect.left + 3, rect.bottom-rect.top + 3, SWP_FRAMECHANGED);
34  
35         int   nScreenWidth=GetSystemMetrics(SM_CXSCREEN);   
36         int   nScreenHeight=GetSystemMetrics(SM_CYSCREEN);
37         ::SetWindowPos(this->m_hWnd,HWND_TOPMOST,0,0, nScreenWidth,nScreenHeight, SWP_FRAMECHANGED);
38     }
39     else
40     {
41        /* //用MFC显示系统任务栏
42         CWnd * wnd = FindWindow(L"Shell_TrayWnd",NULL);
43         wnd->SetWindowPos(NULL,0,0,0,0,SWP_SHOWWINDOW);
44         //this->SetWindowPos(NULL,0,0,0,0,SWP_SHOWWINDOW);
45         */
46 
47         style |= WS_DLGFRAME | WS_THICKFRAME;
48         SetWindowLong(this->m_hWnd, NULL, style);
49         ::SetParent(m_hWnd,m_hWndParent);   
50         ::ShowWindow(m_hWndParent,SW_SHOW);  
51     }
52 }
OnLButtonDblClk

需要注意的是

SetWindowLong(this->m_hWnd,GWL_STYLE, style);   // GWL_STYLE表示MFC窗口属性,NULL表示没有窗口属性。

SetWindowPos(this->m_hWnd,HWND_TOPMOST,0,0, nScreenWidth,nScreenHeight, SWP_FRAMECHANGED);  //HWND_TOPMOST  显示优先级为最高层

原文地址:https://www.cnblogs.com/scotth/p/3424978.html