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 }
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 }
需要注意的是
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 显示优先级为最高层
【推荐】FFA 2024大会视频回放:Apache Flink 的过去、现在及未来
【推荐】中国电信天翼云云端翼购节,2核2G云服务器一口价38元/年
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步