24上位机VC MFC程序实现自给窗口界面
功能展示 很多时候,我们将上位机程序功能编写强大的同时,也希望我们的程序漂亮大方,进而增加用户使用程序的乐趣。程序的美化除了直接加载第三方皮肤文件外,我们还可以通过自绘窗口来实现。我们当前例程就是一个自绘后的程序,抛砖引玉供大家学习,效果如图
24上位机VC MFC程序实现自给窗口界面
要点提示 实现窗口的绘制相对来说比较麻烦,有多处系统处理的函数要我们自行绘制处理,其次是得准备些漂亮的位图用于程序的美化,如美化窗口边框,标题栏等等,而后利用设备上下文类CDC将这些图片绘制在窗体上就可以了。CDC提供了StretchBlt函数,用于绘制图像,其语法 BOOL StretchBlt( int x, int y, int nWidth, int nHeight, CDC* pSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, DWORD dwRop ); X,Y表示目标区域在上角坐标 nWidth, nHeight表示目标区域的宽度和高度 pSrcDC 表示源设备上下文指针 xSrc, ySrc表示源设备上下文的左上角坐标 nSrcWidth, nSrcHeight表示源设备上下文宽度与高度 dwRop 表示光栅效果
绘制窗口标题栏和边框时不能用GETDC函数,因为GETDC方法获得是窗口客户区域的设备上下文指针,就使用GetWindowDC方法获得窗口设备上下文指针 ; 我们当前例程在标题栏上利用位图绘制了几个按钮,当用户单击不同的按钮时,会执行相应的操作。 在绘制标题栏按钮时,要知道 标题栏按钮的显示区域,该区域会随着窗体的大小变化而不同,知道了按钮的显示区域,当用户鼠标 在标题栏上移动时,判断鼠标是否在按钮区域,如在,将按钮状态m_ButtonState设置为相应的值,然后再处理鼠标左键在非客户区按下时的消息,在消息处理函数中判断m_ButtonState值,根据不同值,执行相应的动作,这栏全实现了标题栏按钮的单击处理;
实现功能 1.新建一个对话框的应用程序 2.添加一些编辑框,文本,按钮等控件,如我们的例程一样,再添加一些位图 3.添加以下的成员变量 private: BOOL m_IsMax; //是否处于最大化状态 int m_BorderWidth; //边框宽度 int m_BorderHeight; //边框高度 int m_CaptionHeight; //标题栏的高度 CString m_Caption; //窗口标题 COLORREF m_CapitonColor; //标题字体颜色 CFont m_CaptionFont; //标题字体 int m_ButtonWidth; //按钮位图宽度 int m_ButtonHeight; //按钮位图高度 BOOL m_FirstShow; //窗口首次被显示 CRect m_OrigonRect;//原始窗口区域 CRect m_IniRect,m_MinRect,m_MaxRect,m_CloseRect;//标题栏按钮的显示区域 CButtonState m_ButtonState; //按钮状态 BOOL m_IsDrawForm;//是否需要绘制窗体
4.添加绘制程序窗口用的自定义函数DrawForm()及DrawFormCaption() void CGkbc8Dlg:rawForm() {//获取窗口设备上下文 CDC* pWindowDC = GetWindowDC(); CBitmap LeftLine; BITMAPINFO bitinfo; CDC memDC; memDC.CreateCompatibleDC(pWindowDC);
CRect Clientrect; GetClientRect(Clientrect);
int leftwidth=0; //左标题的宽度 int rightwidth = 0; //右标题的宽度 int leftlinewidth = 0; //左边线宽度 LeftLine.LoadBitmap(IDB_BITMAP3); //加载右标题 LeftLine.GetObject(sizeof(bitinfo),&bitinfo); rightwidth = bitinfo.bmiHeader.biWidth; LeftLine.DeleteObject();
int x,y; //绘制左边线 //获取位图大小 LeftLine.LoadBitmap(IDB_BITMAP4); LeftLine.GetObject(sizeof(bitinfo),&bitinfo); leftlinewidth = x = bitinfo.bmiHeader.biWidth; y = bitinfo.bmiHeader.biHeight; memDC.SelectObject(&LeftLine); pWindowDC->StretchBlt(1-m_BorderWidth,m_CaptionHeight+1,x+1,Clientrect.Height()+2*m_BorderHeight+5,&memDC,0,0,x,y,SRCCOPY); LeftLine.DeleteObject();
/*****************************绘制左标题**************************************/ LeftLine.LoadBitmap(IDB_BITMAP2); //获取位图大小 LeftLine.GetObject(sizeof(bitinfo),&bitinfo); memDC.SelectObject(&LeftLine); leftwidth = x = bitinfo.bmiHeader.biWidth; y = bitinfo.bmiHeader.biHeight; pWindowDC->StretchBlt(-m_BorderWidth,0,x,m_CaptionHeight+4,&memDC,0,0,x,y,SRCCOPY); LeftLine.DeleteObject(); /*****************************绘制左标题**************************************/
/*****************************绘制中间标题**************************************/ LeftLine.LoadBitmap(IDB_BITMAP1); //获取位图大小 LeftLine.GetObject(sizeof(bitinfo),&bitinfo); memDC.SelectObject(&LeftLine); x = bitinfo.bmiHeader.biWidth; y = bitinfo.bmiHeader.biHeight; pWindowDC->StretchBlt(leftwidth-1,0,Clientrect.Width()-leftwidth-rightwidth ,m_CaptionHeight+4,&memDC,0,0,x,y,SRCCOPY); LeftLine.DeleteObject(); /*****************************绘制中间标题***************************************/
/*****************************绘制右标题**************************************/ LeftLine.LoadBitmap(IDB_BITMAP3); //获取位图大小 LeftLine.GetObject(sizeof(bitinfo),&bitinfo); memDC.SelectObject(&LeftLine); x = bitinfo.bmiHeader.biWidth; y = bitinfo.bmiHeader.biHeight;
pWindowDC->StretchBlt(Clientrect.Width()-x-1,0,x+m_BorderWidth+9,m_CaptionHeight+4,&memDC,0,0,x,y,SRCCOPY); LeftLine.DeleteObject(); /*****************************绘制右标题***************************************/
/*****************************绘制右边框**************************************/ LeftLine.LoadBitmap(IDB_BITMAP4); //获取位图大小 LeftLine.GetObject(sizeof(bitinfo),&bitinfo); memDC.SelectObject(&LeftLine); x = bitinfo.bmiHeader.biWidth; y = bitinfo.bmiHeader.biHeight; pWindowDC->StretchBlt(Clientrect.Width()+m_BorderWidth+2,m_CaptionHeight+1,x+m_BorderWidth,Clientrect.Height()+2*m_BorderHeight+5,&memDC,0,0,x,y,SRCCOPY); LeftLine.DeleteObject(); /*****************************绘制右边框***************************************/
/*****************************绘制底边框**************************************/ LeftLine.LoadBitmap(IDB_BITMAP5); //获取位图大小 LeftLine.GetObject(sizeof(bitinfo),&bitinfo); memDC.SelectObject(&LeftLine); x = bitinfo.bmiHeader.biWidth; y = bitinfo.bmiHeader.biHeight; pWindowDC->StretchBlt(leftlinewidth-m_BorderWidth,Clientrect.Height()+m_CaptionHeight+2,Clientrect.Width()+m_BorderWidth,y+2,&memDC,0,0,x,y,SRCCOPY); LeftLine.DeleteObject(); /*****************************绘制底边框***************************************/
/*****************************绘制初始化按钮**************************************/ LeftLine.LoadBitmap(IDB_BITMAP6); //获取位图大小 LeftLine.GetObject(sizeof(bitinfo),&bitinfo); memDC.SelectObject(&LeftLine); x = bitinfo.bmiHeader.biWidth; y = bitinfo.bmiHeader.biHeight; pWindowDC->StretchBlt(m_IniRect.left,m_IniRect.top,m_IniRect.right,m_IniRect.bottom,&memDC,0,0,x,y,SRCCOPY); LeftLine.DeleteObject(); /*****************************绘制初始化按钮***************************************/
/*****************************绘制最小化按钮**************************************/ LeftLine.LoadBitmap(IDB_BITMAP6); //获取位图大小 LeftLine.GetObject(sizeof(bitinfo),&bitinfo); memDC.SelectObject(&LeftLine); x = bitinfo.bmiHeader.biWidth; y = bitinfo.bmiHeader.biHeight; pWindowDC->StretchBlt(m_MinRect.left,m_MinRect.top,m_MinRect.right,m_MinRect.bottom,&memDC,0,0,x,y,SRCCOPY); LeftLine.DeleteObject(); /*****************************绘制最小化按钮***************************************/
/*****************************绘制最大化按钮**************************************/ LeftLine.LoadBitmap(IDB_BITMAP6); //获取位图大小 LeftLine.GetObject(sizeof(bitinfo),&bitinfo); memDC.SelectObject(&LeftLine); x = bitinfo.bmiHeader.biWidth; y = bitinfo.bmiHeader.biHeight; pWindowDC->StretchBlt(m_MaxRect.left,m_MaxRect.top,m_MaxRect.right,m_MaxRect.bottom,&memDC,0,0,x,y,SRCCOPY); LeftLine.DeleteObject(); /*****************************绘制最大化按钮***************************************/
/*****************************绘制关闭按钮**************************************/ LeftLine.LoadBitmap(IDB_BITMAP6); //获取位图大小 LeftLine.GetObject(sizeof(bitinfo),&bitinfo); memDC.SelectObject(&LeftLine); x = bitinfo.bmiHeader.biWidth; y = bitinfo.bmiHeader.biHeight; pWindowDC->StretchBlt(m_CloseRect.left,m_CloseRect.top,m_CloseRect.right,m_CloseRect.bottom,&memDC,0,0,x,y,SRCCOPY); LeftLine.DeleteObject(); m_IsDrawForm = TRUE; /*****************************绘制关闭按钮***************************************/ ReleaseDC(&memDC); DrawFormCaption();
} void CGkbc8Dlg:rawFormCaption() { if (! m_Caption.IsEmpty()) { CDC* pDC = GetWindowDC(); pDC->SetBkMode(TRANSPARENT); pDC->SetTextColor(m_CapitonColor); pDC->SetTextAlign(TA_CENTER); CRect rect; GetClientRect(rect); pDC->SelectObject(&m_CaptionFont); pDC->TextOut(rect.Width()/2, m_CaptionHeight/3 ,m_Caption); } } 5.实现标题栏按钮状态的处理,我们添加OnNcMouseMove进行实现 void CGkbc8Dlg::OnNcMouseMove(UINT nHitTest, CPoint point) { CDialog::OnNcMouseMove(nHitTest, point); CRect tempIni,tempMin,tempMax,tempClose,ClientRect; CDC* pWindowDC = GetWindowDC(); CDC memDC; memDC.CreateCompatibleDC(pWindowDC);
BITMAPINFO bInfo; CBitmap LeftLine; int x,y;
GetWindowRect(ClientRect); //GetClientRect(); tempIni.CopyRect(CRect(m_IniRect.left+ ClientRect.left,ClientRect.top+m_IniRect.top,m_IniRect.right+m_IniRect.left+ ClientRect.left,m_IniRect.bottom+m_IniRect.top+ClientRect.top)); tempMin.CopyRect(CRect(m_MinRect.left+ ClientRect.left,ClientRect.top+m_MinRect.top,m_MinRect.right+m_MinRect.left+ ClientRect.left,m_MinRect.bottom+m_MinRect.top+ClientRect.top)); tempMax.CopyRect(CRect(m_MaxRect.left+ ClientRect.left,ClientRect.top+m_MaxRect.top,m_MaxRect.right+m_MaxRect.left+ ClientRect.left,m_MaxRect.bottom+m_MaxRect.top+ClientRect.top)); tempClose.CopyRect(CRect(m_CloseRect.left+ ClientRect.left,ClientRect.top+m_CloseRect.top,m_CloseRect.right+m_CloseRect.left+ ClientRect.left,m_CloseRect.bottom+m_CloseRect.top+ClientRect.top)); if (tempIni.PtInRect(point)) //鼠标在初始化按钮上移动时,更改按钮显示的位图 {
LeftLine.LoadBitmap(IDB_BITMAP7); LeftLine.GetObject(sizeof(bInfo),&bInfo); x = bInfo.bmiHeader.biWidth; y = bInfo.bmiHeader.biHeight; memDC.SelectObject(&LeftLine); pWindowDC->StretchBlt(m_IniRect.left,m_IniRect.top,m_IniRect.right,m_IniRect.bottom,&memDC,0,0,x,y,SRCCOPY); m_IsDrawForm = FALSE; m_ButtonState = bsIni; LeftLine.DeleteObject(); } else if(tempMin.PtInRect(point))//鼠标在最小化按钮上移动时,更改按钮显示的位图 { LeftLine.LoadBitmap(IDB_BITMAP7); LeftLine.GetObject(sizeof(bInfo),&bInfo); x = bInfo.bmiHeader.biWidth; y = bInfo.bmiHeader.biHeight; memDC.SelectObject(&LeftLine); pWindowDC->StretchBlt(m_MinRect.left,m_MinRect.top,m_MinRect.right,m_MinRect.bottom,&memDC,0,0,x,y,SRCCOPY); m_IsDrawForm = FALSE; m_ButtonState = bsMin; LeftLine.DeleteObject(); } else if (tempMax.PtInRect(point)) { LeftLine.LoadBitmap(IDB_BITMAP7); LeftLine.GetObject(sizeof(bInfo),&bInfo); x = bInfo.bmiHeader.biWidth; y = bInfo.bmiHeader.biHeight; memDC.SelectObject(&LeftLine); pWindowDC->StretchBlt(m_MaxRect.left,m_MaxRect.top,m_MaxRect.right,m_MaxRect.bottom,&memDC,0,0,x,y,SRCCOPY); m_IsDrawForm = FALSE; if (m_IsMax) {m_ButtonState = bsMax;} else {m_ButtonState = bsRes;} LeftLine.DeleteObject(); } else if (tempClose.PtInRect(point)) { LeftLine.LoadBitmap(IDB_BITMAP7); LeftLine.GetObject(sizeof(bInfo),&bInfo); x = bInfo.bmiHeader.biWidth; y = bInfo.bmiHeader.biHeight; memDC.SelectObject(&LeftLine); pWindowDC->StretchBlt(m_CloseRect.left,m_CloseRect.top,m_CloseRect.right,m_CloseRect.bottom,&memDC,0,0,x,y,SRCCOPY); m_IsDrawForm = FALSE; m_ButtonState = bsClose; LeftLine.DeleteObject(); } else { m_ButtonState = bsNone; if (m_IsDrawForm==FALSE) DrawForm(); } ReleaseDC(&memDC); } 6.处理窗口的WM_NCLBUTTONDOWN消息,当用户在非客户区域单击时,根据按钮的状态执行相应操作 void CGkbc8Dlg::OnNcLButtonDown(UINT nHitTest, CPoint point) { // TODO: Add your message handler code here and/or call default CDialog::OnNcLButtonDown(nHitTest, point); switch (m_ButtonState) { case bsClose: //关闭窗口 { DestroyWindow(); } break; case bsIni: //还原窗口到初始大小和位置 { m_IsMax = TRUE; MoveWindow(m_OrigonRect.left,m_OrigonRect.top,m_OrigonRect.Width(),m_OrigonRect.Height()); } break; case bsMin: // { CWnd* pDesk = GetDesktopWindow(); CRect rect; pDesk->GetClientRect(rect); SetWindowPos(0 ,(rect.Width()-m_OrigonRect.Width())/2,2,m_OrigonRect.Width(),0,SWP_SHOWWINDOW); } break; case bsMax: { m_ButtonState = bsMax; ShowWindow(SW_SHOWMAXIMIZED); m_IsMax = FALSE; } break; case bsRes: { ShowWindow(SW_RESTORE); m_IsMax = TRUE; } break; } }
void CGkbc8Dlg::OnNcPaint() { DrawForm(); m_IsDrawForm = TRUE; // TODO: Add your message handler code here // Do not call CDialog::OnNcPaint() for painting messages } 7.我们在程序初始化函数中OnInitDialog,对我们添加的变量也进行初始化 m_BorderHeight = GetSystemMetrics(SM_CYBORDER); m_BorderWidth = GetSystemMetrics(SM_CXBORDER); m_CaptionHeight = GetSystemMetrics(SM_CYCAPTION);
//获取按钮位图大小 CBitmap bitmap; bitmap.LoadBitmap(IDB_BITMAP6); BITMAPINFO bInfo; bitmap.GetObject(sizeof(bInfo),&bInfo); m_ButtonWidth = bInfo.bmiHeader.biWidth; m_ButtonHeight = bInfo.bmiHeader.biHeight; bitmap.DeleteObject();
CRect rect; GetClientRect(rect); m_IniRect.CopyRect(CRect(8,(m_CaptionHeight+3*m_BorderHeight -m_ButtonHeight)/2,m_ButtonWidth,m_ButtonHeight)); m_MinRect.CopyRect(CRect(rect.Width()-45,(m_CaptionHeight+2*m_BorderHeight -m_ButtonHeight)/2,m_ButtonWidth,m_ButtonHeight)); m_MaxRect.CopyRect(CRect(rect.Width()-32,(m_CaptionHeight+2*m_BorderHeight -m_ButtonHeight)/2,m_ButtonWidth,m_ButtonHeight)); m_CloseRect.CopyRect(CRect(rect.Width()-19,(m_CaptionHeight+2*m_BorderHeight -m_ButtonHeight)/2,m_ButtonWidth,m_ButtonHeight)); m_CaptionFont.CreateFont(14,10,0,0,600,0,0,0,ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FF_ROMAN,"宋体"); m_label1.ModifyStyleEx(0,WS_EX_TRANSPARENT); m_IsDrawForm =FALSE; m_ButtonState=bsNone; m_FirstShow = FALSE; m_IsMax = TRUE; m_CapitonColor =RGB(0,0,255); m_Caption = "系统登录";
DrawForm(); 8.最后是在程序需要重绘的地方,加上我们的窗口绘制函数DrawForm(); void CGkbc8Dlg::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) { CDialog::OnActivate(nState, pWndOther, bMinimized); OnPaint() ; } HBRUSH CGkbc8Dlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { //绘制背景 if (nCtlColor==CTLCOLOR_DLG) { CBitmap bitmap; bitmap.LoadBitmap(IDB_CLIENTBITMAP);
CBrush brush(&bitmap); CRect rect; GetClientRect(rect); pDC->SelectObject(&brush); bitmap.DeleteObject(); pDC->FillRect(rect,&brush); return brush; } else if (nCtlColor ==CTLCOLOR_STATIC) { pDC->SetBkMode(TRANSPARENT); } else return CDialog::OnCtlColor(pDC, pWnd, nCtlColor); return NULL; } BOOL CGkbc8Dlg::OnNcActivate(BOOL bActive) { OnPaint() ; return CDialog::OnNcActivate(bActive); } void CGkbc8Dlg::OnNcPaint() { DrawForm(); m_IsDrawForm = TRUE; } void CGkbc8Dlg::OnPaint() { DrawForm(); m_IsDrawForm = TRUE; } void CGkbc8Dlg::OnShowWindow(BOOL bShow, UINT nStatus) { CDialog::OnShowWindow(bShow, nStatus); if (m_FirstShow==FALSE) { m_FirstShow = TRUE; GetWindowRect(m_OrigonRect); } } void CGkbc8Dlg::OnSize(UINT nType, int cx, int cy) { CDialog::OnSize(nType, cx, cy); // TODO: Add your message handler code here CRect rect; GetClientRect(rect);
m_IniRect.CopyRect(CRect(8,(m_CaptionHeight+3*m_BorderHeight -m_ButtonHeight)/2,m_ButtonWidth,m_ButtonHeight)); m_MinRect.CopyRect(CRect(rect.Width()-45,(m_CaptionHeight+2*m_BorderHeight -m_ButtonHeight)/2,m_ButtonWidth,m_ButtonHeight)); m_MaxRect.CopyRect(CRect(rect.Width()-32,(m_CaptionHeight+2*m_BorderHeight -m_ButtonHeight)/2,m_ButtonWidth,m_ButtonHeight)); m_CloseRect.CopyRect(CRect(rect.Width()-19,(m_CaptionHeight+2*m_BorderHeight -m_ButtonHeight)/2,m_ButtonWidth,m_ButtonHeight)); Invalidate(); }
下面演示下自绘功能实现的整个过程 源码及视频下载 (仅在电脑可见)
|