登录 用户中心() [退出] 后台管理 注册
   
您的位置: 首页 >> 程序员学前班[不再更新,只读] >> 主题: 重绘标题栏只处理 WM_NCPAINT 是不行的     [回主站]     [分站链接]
标题
重绘标题栏只处理 WM_NCPAINT 是不行的
clq
浏览(1) + 2010-04-16 14:12:05 发表 编辑

关键字:

重绘标题栏只处理 WM_NCPAINT 是不行的

网友意见
"
必须处理的消息:
WM_NCPAINT
WM_NCMOUSEMOVE
WM_NCLBUTTONDOWN
WM_NCLBUTTONUP
WM_NCACTIVATE

如果需要重新计算标题栏宽度 或系统按钮位置等
需要处理的消息
WM_NCCALCSIZE
WM_NCHITTEST

此外还需要处理有关窗体状态的消息
WM_SIZE
WM_WINDOWPOSCHANGED
"

思想是跳出 NC 消息了,但其实还是不对.

clq
2010-4-16 14:13:11 发表 编辑

在我自己的经验看,还要有处理 OnMoving 的.

clq
2010-6-2 10:32:13 发表 编辑

右键仍然会出现旧按钮,要处理 OnInitMenuPopup 即 WM_INITMENUPOPUP 消息.
来自 http://blog.sina.com.cn/s/blog_50a118190100afny.html
--------------------------------------------------

VC 实现 自绘 窗体 标题栏 非客户区 上

(2008-08-04 10:45:13)

1.准备工作。
(1)得到文件夹中的位图句柄:
首先要准备相应图片。
HBITMAP bitmap;
bitmap=(HBITMAP)::LoadImage(AfxGetInstanceHandle(),
    "skin//Test.bmp",
    IMAGE_BITMAP,
    0,
    0,
    LR_DEFAULTSIZE|LR_LOADFROMFILE);

CBitmap cbmp;
cbmp.Attach(bitmap);
      其中,skin//Test.bmp为文件路径。

(2)关于非客户区的消息:
ON_WM_NCPAINT()//绘非客户区时。
ON_WM_NCACTIVATE()//非客户区有焦点和失去焦点时。
ON_WM_NCCALCSIZE()//计算窗体尺寸时。

(3)改变标题栏尺寸:
  重写ON_WM_NCCALCSIZE()消息响应函数。
void CMYSkinDlg::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp)
{
//重设标题栏高度。m_nCaptionHeight在PreSubclassWindow中计算。
lpncsp->rgrc[0].top+=m_nCaptionHeight-GetSystemMetrics(SM_CYCAPTION);
CDialog::OnNcCalcSize(bCalcValidRects, lpncsp);
}

(4)非客户区的鼠标动作:
  相关消息:
ON_WM_NCLBUTTONDOWN()//鼠标下。
ON_WM_NCLBUTTONUP()//鼠标上。
ON_WM_NCMOUSEMOVE()//鼠标悬停。

(5)屏蔽最大最小关闭消息:
在WindowProc中:
LRESULT CMYSkinDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_NCHITTEST)
    {
     LRESULT lRet = CDialog::WindowProc(message, wParam, lParam);
     //屏蔽最大最小关闭消息.
     if (lRet==HTZOOM || lRet == HTMINBUTTON || lRet == HTCLOSE)
      return HTCAPTION;//视为标题栏动作。
     else
      return lRet;
    }
...
2.程序和注释:
(1)用户变量和函数.
protected:
CBrush m_brBG;//对话框背景颜色,在OnInitDialog 中初始化,在OnCtlColor中作为返回值.
CString m_strCaption;//标题.
CRect m_rtWnd;//整个窗体Rect.
int     m_nCaptionHeight;//标题栏高度.
CRect m_rtButtons;//最大,最小,关闭按钮.
CRect m_rtIcon;//图标.
CRect m_rtButtMin;//最小.
CRect m_rtButtMax;//最大.
CRect m_rtButtExit;//关闭.
CRect m_rtButtMaxM;
CRect m_rtButtMinM;
CRect m_rtButtExitM;
CRect m_bmRt;//Bitmap所在的Rect.
BOOL    m_bNCActive;//窗体活动.

bool FillRtWithBmp(CString bmpFileName,CDC *pDC,CRect rt);//用Bitmap添满整个rt.
bool FillWithBmpRtUL(CString bmpFileName,CDC *pDC,CPoint pt);//pt为Bitmap的左上.
bool FillWithBmpRtUR(CString bmpFileName,CDC *pDC, CPoint pt);//pt为Bitmap的右上.
bool FillButton(CString bmpButtonName, CDC *pDC, CPoint pt,int intState);//
void DrawNC(CDC* pDC);//画非客户区.
(2)显示之前计算从图片计算标题栏高度:
void CMYSkinDlg::PreSubclassWindow()
{
//得到标题栏图片高度。
CString bmpFileName="C2";
HBITMAP bitmap;
bitmap=(HBITMAP)::LoadImage(AfxGetInstanceHandle(),
    "skin//"+_T(bmpFileName)+".bmp",
    IMAGE_BITMAP,
    0,
    0,
    LR_DEFAULTSIZE|LR_LOADFROMFILE);

BITMAP bm;
CBitmap cbmp;
cbmp.Attach(bitmap);
cbmp.GetBitmap(&bm);
cbmp.DeleteObject();
m_nCaptionHeight=bm.bmHeight-4;

CDialog::PreSubclassWindow();
}
(3)重写OnNcCalCsize:
void CMYSkinDlg::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp)
{
//重设标题栏高度。m_nCaptionHeight在PreSubclassWindow中计算。
lpncsp->rgrc[0].top+=m_nCaptionHeight-GetSystemMetrics(SM_CYCAPTION);
CDialog::OnNcCalcSize(bCalcValidRects, lpncsp);
}
(4)绘非客户区:
void CMYSkinDlg::OnNcPaint()
{
CDC* pWinDC=GetWindowDC();
if (pWinDC) DrawNC(pWinDC);//函数实现略。
ReleaseDC(pWinDC);
}
(5)对非客户区焦点情况的处理:
BOOL CMYSkinDlg::OnNcActivate(BOOL bActive)
{
m_bNCActive=bActive;//在DrawNC中有体现。//初始时设NC区为活动.
//防止在任务栏右键图标时出现最大最小关闭
OnNcPaint();//实际源程序中有细节的考虑。
return true;
}
(6)响应鼠标在非客户区的事件:
鼠标在非客户区按下:
void CMYSkinDlg::OnNcLButtonDown(UINT nHitTest, CPoint point)
{
//检测最小,最大和关闭按钮是否按下,然后更换图片.
...
if(!IsZoomed())//防止在最大化后能拖动.
    CDialog::OnNcLButtonDown(nHitTest,point);
}
//OnNcLButtonUp中触发最大最小关闭:
void CMYSkinDlg::OnNcLButtonUp(UINT nHitTest, CPoint point)
{
if (m_rtButtExit.PtInRect(point))
    SendMessage(WM_CLOSE);
else if (m_rtButtMin.PtInRect(point))
    SendMessage(WM_SYSCOMMAND, SC_MINIMIZE, MAKELPARAM(point.x, point.y) );
else if (m_rtButtMax.PtInRect(point))
{
    if (IsZoomed())
     SendMessage(WM_SYSCOMMAND, SC_RESTORE, MAKELPARAM(point.x, point.y));
    else
     SendMessage(WM_SYSCOMMAND, SC_MAXIMIZE, MAKELPARAM(point.x, point.y) );
}
}
//鼠标在非客户区悬停:
void CMYSkinDlg::OnNcMouseMove(UINT nHitTest, CPoint point)
{
//检测最小,最大和关闭按钮是否有鼠标悬停,然后更换相应图片.
...
}

(7)屏蔽单击程序非客户系统原有图标矩形时出现的系统菜单或动作:
UINT CMYSkinDlg::OnNcHitTest(CPoint point)
{
CRect tst(2,2,m_nCaptionHeight+4,m_nCaptionHeight+4);
tst.OffsetRect(m_rtWnd.TopLeft());//原图标屏幕位置
if(tst.PtInRect(point))//最大最小关闭按钮位置.
    return HTCAPTION;
else if(m_rtButtMin.PtInRect(point)||
     m_rtButtMax.PtInRect(point)||
     m_rtButtExit.PtInRect(point))
    return HTSYSMENU;//使此区域能够响应OnNcLButtonUp
else
    return CDialog::OnNcHitTest(point);
}

(8)系统菜单的显示和隐藏:
为了使重绘工作顺利进行而不影响程序外在表现,要对系统菜单显示和隐藏, 如在OnNcActivate中有这样的程序片段:
...
if(bActive)
{
    ModifyStyle(0, WS_SYSMENU);
    OnNcPaint();
}
else
{
    ModifyStyle(WS_SYSMENU, 0);
    OnNcPaint();
}
...
又如,在OnCreate中:
...
this->ModifyStyle(WS_SYSMENU, 0);//防止在任务栏右单击时出现最大最小关闭.
...

(9)对系统最大最小关闭图标依然出现的处理:
  虽然用户取消了NC区系统的重绘,但是系统仍然对最大最小关闭图标重绘(主要表现在用户右单击任务栏图标时),这里的处理方法如下:
void CMYSkinDlg::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)
{
//CDialog::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);
if (bSysMenu) OnNcPaint();//防止在任务栏右键图标时窗口出现最大最小关闭
}




总数:2 页次:1/1 首页 尾页  
总数:2 页次:1/1 首页 尾页  


所在合集/目录



发表评论:
文本/html模式切换 插入图片 文本/html模式切换


附件:



NEWBT官方QQ群1: 276678893
可求档连环画,漫画;询问文本处理大师等软件使用技巧;求档softhub软件下载及使用技巧.
但不可"开车",严禁国家敏感话题,不可求档涉及版权的文档软件.
验证问题说明申请入群原因即可.

Copyright © 2005-2020 clq, All Rights Reserved
版权所有
桂ICP备15002303号-1