VC++中对话框界面重绘2-对话框自身的重绘

时间:2022-12-16 14:37:06

在对话框重绘设计与实现过程中,一般需要绘制的对话框区域主要有标题部分、边框部分和客户区部分。具体的区域划分如下图所示。

VC++中对话框界面重绘2-对话框自身的重绘

既然要对多个区域进行位图显示输出,所以我们先封装一个bmp位图显示输出函数如下:

void CCTestDlg::ShowBmp(int x,int y,int w,int h,int nID)

{//nID 表示位图资源的ID

    CRect winRC;

    CDC* pDC=GetWindowDC();

    CDC memDC;

    memDC.CreateCompatibleDC(pDC);

    BITMAPINFO bmpInfo;

    CBitmap bmp; 

    GetWindowRect(&winRC);

    bmp.LoadBitmap(nID);

    bmp.GetObject(sizeof(BITMAPINFO),&bmpInfo);

    int nBmpCX = bmpInfo.bmiHeader.biWidth;

    int nBmpCY = bmpInfo.bmiHeader.biHeight;

    memDC.SelectObject(bmp);

    pDC->StretchBlt(x,y,w,h,

       &memDC,0,0,nBmpCX,nBmpCY,SRCCOPY);//在窗口中绘制位图

    bmp.DeleteObject();

    ReleaseDC(pDC);

}

(1)对各个区域进行位图输出重绘。由于标题栏以及边框主要都是非客户区域绘制,因此应该在WM_NCPAINT 消息中绘制。当然得先通过添加资源的方式将所用到的bmp位图资源导入到项目中。

首先定义一些常量值,表示对话框各个组成区域部分。代码如下:

 

#define LEFTTITLE 1//左标题

#define MIDTITLE 1//中间标题

#define RIGHTTITLE 1//右标题

#define MINBUTTON 1//右标题

#define MAXBUTTON 1//右标题

#define CLOSEBUTTON 1//右标题

#define APPICON 1 //程序icon图标

#define LEFTBAR 1 //左边框

#define RIGHTBAR 1 //右边边框

#define BOTTOMBAR 1 //底边框

在 WM_NCPAINT消息对于的 方法OnNcPaint()中调用对话框绘制方法SetFace()。该方法的功能就是绘制对话框各个区域的位图。主要代码如下:

void CCTestDlg::SetFact()

{

    // TODO: 在此添加控件通知处理程序代码

    int nFrameCY = GetSystemMetrics(SM_CYFIXEDFRAME);//获取对话框边框的高度

    int nFrameCX = GetSystemMetrics(SM_CXDLGFRAME);//获取对话边框的宽度

    int m_nBorderCY;

    int m_nBorderCX;

    int m_nTitleBarCY ;

    int m_nTitleBarCX;

    if(GetStyle()&WS_BORDER)//获取对话框是否有边框

    {

        m_nBorderCY = GetSystemMetrics(SM_CYBORDER) + nFrameCY;

        m_nBorderCX = GetSystemMetrics(SM_CXBORDER) +nFrameCX;

    }

    else

    {

        m_nBorderCX = nFrameCX;

        m_nBorderCY = nFrameCY;

    }

    m_nTitleBarCY = GetSystemMetrics(SM_CYCAPTION) + m_nBorderCY;//计算标题栏高度

    m_nTitleBarCX =m_nBorderCX;

    CRect winRect,factRect;

    GetWindowRect(&winRect); //获取窗口区域

    factRect.CopyRect(CRect(0,0,winRect.Width(),winRect.Height()));

    CWindowDC windowsDC(this);//获取窗口设备上下文

    //获取整个MFC窗口的高度和宽度

    int winCX = winRect.Width();

    int winCY = winRect.Height();          

    if(LEFTTITLE)

    {//绘制对话框左标题栏位图

        ShowBmp(0,0,100,m_nTitleBarCY,IDB_RIGHTTITLE);

    }      

    if(RIGHTTITLE)

    {//绘制对话框右标题栏位图

        ShowBmp(winCX-100,0,100,m_nTitleBarCY,IDB_RIGHTTITLE);

    }      

    if(MIDTITLE)

    {//绘制对话框中标题栏位图

       

        ShowBmp(100,0,winCX-200,m_nTitleBarCY,IDB_MIDTITLE);

    }  

    if(LEFTBAR)

{//绘制对话框左边框位图                  ShowBmp(0,m_nTitleBarCY,m_nBorderCX,factRect.Height()-m_nBorderCY,IDB_LEFTBAR);

    }

    if(BOTTOMBAR)

    {//绘制对话框底边框位图     ShowBmp(m_nBorderCX,winCY-m_nBorderCX,winCX-2*m_nBorderCX,m_nBorderCX,IDB_BOTTOMBAR);

    }  

    if(RIGHTBAR)

    {//绘制对话框左边框位图    ShowBmp(winCX-m_nBorderCX,m_nTitleBarCY,m_nBorderCX,factRect.Height()-m_nBorderCY,IDB_RIGHTBAR);

    }  

    if(MINBUTTON)

    {//给对话框绘制最小化按钮

        ShowBmp(winCX-3-24-3-24-3-24,1,24,24,IDB_MINBUTTON);

    }  

    if(MAXBUTTON)

    {//给对话框绘制最大化按钮

        ShowBmp(winCX-3-24-3-24,1,24,24,IDB_MAXBUTTON);

    }  

    if(CLOSEBUTTON)

    {//给对话框绘制关闭按钮

        ShowBmp(winCX-3-24,1,24,24,IDB_CLOSEBUTTON);

    }

    ReleaseDC(&windowsDC);

    DrawTitleBarText();//输出标题栏文本

}

上面代码中最后的绘制对话框标题文本的方法DrawTitleBarText()的主要代码如下:

CString strTitle ="自绘窗口标题栏和边框";

    CDC* pDC= GetWindowDC();//获取窗口设备上下文

    pDC->SetBkMode(TRANSPARENT);//设置透明的背景模式

    pDC->SetTextColor(RGB(255,255,255));//设置文本颜色

    pDC->SetTextAlign(TA_CENTER);//设置文本对齐方式

    CRect rect;

    GetClientRect(&rect);//获取窗口客户区域

    CSize szText = pDC->GetTextExtent(strTitle);//获取文本高度

    pDC->TextOut(rect.Width()/2,3,strTitle,20);//在窗口中输出文本

    ReleaseDC(pDC);//释放窗口设备上下文

绘制后的效果图如下图所示。

VC++中对话框界面重绘2-对话框自身的重绘

在完成对话框相应区域的位图后,并没有完成任务,还需要处理标题栏按钮的热点效果,以及按钮的单击事件。首先得处理鼠标在非客户区域移动时的事件,即WM_NCMOUSEMOVE消息,在其消息处理函数中判断当前的鼠标点是否位于标题栏的按钮区域,如果是则设置按钮的热点效果,并且记录当前的按钮状态,及鼠标点在哪个按钮上。同样的,处理对话框非客户区域的单击事件,即WM_NCLBUTTONDOWN消息,在其消息处理函数中完成单击事件操作。主要代码如下:

void CCTestDlg::OnNcMouseMove(UINT nHitTest, CPoint point)

{

    // TODO: 在此添加消息处理程序代码和/或调用默认值

    CRect minRC,maxRC,closeRC,winRC;

   

    GetWindowRect(&winRC);

   

    closeRC.CopyRect(CRect(winRC.Width()-27,1,winRC.Width()-27+24,1+24));  

    maxRC.CopyRect(CRect(winRC.Width()-27*2,1,winRC.Width()-27*2+24,1+24));

    minRC.CopyRect(CRect(winRC.Width()-27*3,1,winRC.Width()-27*3+24,1+24));

    point.Offset(-winRC.left,-winRC.top);//由于point为屏幕坐标,这里将其转换为窗口坐标

    if(closeRC.PtInRect(point)) //判断鼠标是否在关闭按钮区域上

    {      

        ShowBmp(winRC.Width()-3-24,1,24,24,IDB_CLOSEBUTTON2);

    }

    else if(maxRC.PtInRect(point)) //判断鼠标是否在最大化按钮区域上

    {

        ShowBmp(winRC.Width()-27*2,1,24,24,IDB_MAXBUTTON2);

    }

    else if(minRC.PtInRect(point)) //判断鼠标是否在最小化按钮区域上

    {

        ShowBmp(winRC.Width()-27*3,1,24,24,IDB_MINBUTTON2);

    }

    else//鼠标没有在标题栏的按钮区域上

    {      

        ShowBmp(winRC.Width()-3-24-54,1,24,24,IDB_MINBUTTON);

        ShowBmp(winRC.Width()-3-24-27,1,24,24,IDB_MAXBUTTON);

        ShowBmp(winRC.Width()-3-24,1,24,24,IDB_CLOSEBUTTON);

    }

}

添加热点效果后的效果如下图所示。

VC++中对话框界面重绘2-对话框自身的重绘