自绘窗体(Dialog)的实现,关于标题栏的绘制,基本上都是主动在标题栏重新绘制,
为了绘制效果的好看,避免系统默认自动绘制标题栏按钮(最大化,最小化,关闭按钮),一般都是对该窗体的属性用SetWindowLong来重新设置其样式,屏蔽WS_SYSMENU,WS_MINIMIZEBOX,WS_MAXIMIZEBOX等属性并做记录,然后在绘制的时候进行绘制,此方法可以得到很好的绘制效果。本人亦采用以上方法实现,但是由于屏蔽了以上属性,当程序在任务栏被鼠标左键和右键点击的时候,作出的反应就没有了弹出系统菜单的效果。 尝试解决过程描述(附注):
1.依旧采用屏蔽属性方式,希望截获鼠标相关消息,主动弹出系统菜单,
但是用Spy++跟踪窗口消息,未屏蔽时从任务栏点击窗口图标到激活显示消息如下:
<00001> 00510644 S WM_WINDOWPOSCHANGING lpwp:0012FA84
<00002> 00510644 R WM_WINDOWPOSCHANGING
<00003> 00510644 S WM_WINDOWPOSCHANGED lpwp:0012FA84
<00004> 00510644 R WM_WINDOWPOSCHANGED
<00005> 00510644 S WM_ACTIVATEAPP fActive:True dwThreadID:00000E88
<00006> 00510644 R WM_ACTIVATEAPP
<00007> 00510644 S WM_NCACTIVATE fActive:True
<00008> 00510644 S .WM_GETICON fType:False
<00009> 00510644 R .WM_GETICON hicon:0B6E0687
<00010> 00510644 S .WM_GETTEXT cchTextMax:256 lpszText:0012E3E8
<00011> 00510644 R .WM_GETTEXT cchCopied:8 lpszText:0012ED50 ("SkinTestDlg")
<00012> 00510644 R WM_NCACTIVATE
<00013> 00510644 S WM_ACTIVATE fActive:WA_ACTIVE fMinimized:False hwndPrevious:(null)
<00014> 00510644 S .WM_ACTIVATETOPLEVEL fActive:True dwThreadID:0012F6A8
<00015> 00510644 R .WM_ACTIVATETOPLEVEL
<00016> 00510644 S ..WM_CTLCOLORBTN hdcButton:1B011103 hwndButton:003406A4
<00017> 00510644 R ..WM_CTLCOLORBTN hBrush:01100060
<00018> 00510644 R WM_ACTIVATE
<00019> 00510644 S WM_KICKIDLE
<00020> 00510644 R WM_KICKIDLE
未曾截获与鼠标相关的消息,猜测应该是系统与窗口的交互以WM_ACTIVEAPP等激活消息
为主,然后执行一系列关联的操作,因此要处理似乎比较繁琐,此法可行性不高;2.尝试不修改窗口属性方式,希望截获系统绘制消息,屏蔽其实现或者立刻刷新绘制的办法而达到良好的绘制效果,据调试,鼠标在窗口标题栏左键按下后(系统按钮自动绘制覆盖我们自己绘制的按钮),于是想当然的在鼠标消息WM_NCLBUTTONDOWN处理后立刻调用刷新绘制函数,未能达到效果,原因是该函数不是一个立刻返回的函数,其返回需要等待鼠标释放后才返回,即便在按下过程中移动鼠标也不会返回,证实方法:
TRACE("WM_NCLBUTTONDOWN start\n");
CDialog::OnNcLButtonDown(wParam, lParam);
TRACE("WM_NCLBUTTONDOWN  end\n");
这两行输出消息的输出以鼠标按下,释放为基准,因此需要在函数返回后立刻绘制也没用,因为这过程中一直显示系统按钮。本人尝试跟踪进入默认CDialog::OnNcLButtonDown()函数处理,其调用的是CWnd::Deafult()来处理的,亦是相当繁复的流程了,此法亦未果.本人为这个问题调了2天了,反复尝试均不得效,无法可施,唯有看是不是有高手指点,不吝赐教。或给代码历程,不尽感激,E-Mail:[email protected]最好能在这里讨论,以便日后其他同行遇到同类问题好得方案。^_^

解决方案 »

  1.   

    创建窗口时,加上WS_SYSMENU
    当鼠标移到关闭等按钮上时SetCapture,
    之后把所有的处理放到OnLButtonDown等函数中,
    我尝试过,效果非常理想
      

  2.   

    http://www.vckbase.com/vckbase/default.aspx
    第44期
      

  3.   

    我刚刚又试了一下,重载OnNcHitTest
    OnNcHitTest(CPoint point)
    {
    UINT uHitResult; uHitResult = CFrameWnd::OnNcHitTest(point); if(uHitResult == HTSYSMENU || uHitResult == HTMINBUTTON || uHitResult == HTMAXBUTTON || uHitResult == HTCLOSE)
    {
    uHitResult = HTCAPTION;
    } return uHitResult;
    }即可根本解决
      

  4.   

    to xianglitian(向立天) :
    重写WM_NCHITTEST消息的确能使得点击窗口按钮位置时候,系统不绘制默认按钮,但是情况并非如此简单,我推测您是在SDI下测试的,但在Dlg和MDI下,运行程序后第一次点击标题栏还会出现绘制系统默认按钮的现象,因此,需要处理这一问题.并且我搜索了一下这个问题,依旧CSDN有2个帖子跟我的问题基本一致:
    http://topic.csdn.net/t/20051222/21/4476070.html
    http://topic.csdn.net/t/20020304/15/554014.html据以上情况所述,我们可以大胆推断,一开始运行程序的时候首次点击标题栏应该发送不一样的消息,系统做特别处理,因此如果能找到这一消息,估计就好处理了,不过方案与实情也不应该拘礼与此,软件开发的奥秘在于发掘内部机制,可我凿子还是不够锋利,
    至今似乎未有所得,因此还是望有经验的高手不吝赐教,以解我等之困惑!
      

  5.   

    问题终于尘埃落定,原来是windows对绘制处理的一个操作(XP才增加的消息),猜测是一个只有微软内部才知道的BUG处理,其处理方式是通过向标题栏发送以下消息以解决余留问题,但我们重写后未曾予以适当的处理,故出现如题所述的现象。用SPY++跟踪消息的时候发现这个怪异的[unknow]类型消息,于是尝试查阅MSDN,未有涉及,尝试直接屏蔽后得满意效果,欣喜之余google:
        /* 0x00A0 */
        "WM_NCMOUSEMOVE", /* 0x00A0 */
        "WM_NCLBUTTONDOWN", /* 0x00A1 */
        "WM_NCLBUTTONUP", /* 0x00A2 */
        "WM_NCLBUTTONDBLCLK", /* 0x00A3 */
        "WM_NCRBUTTONDOWN", /* 0x00A4 */
        "WM_NCRBUTTONUP", /* 0x00A5 */
        "WM_NCRBUTTONDBLCLK", /* 0x00A6 */
        "WM_NCMBUTTONDOWN", /* 0x00A7 */
        "WM_NCMBUTTONUP", /* 0x00A8 */
        "WM_NCMBUTTONDBLCLK", /* 0x00A9 */
        NULL, 
        "WM_NCXBUTTONDOWN",
        "WM_NCXBUTTONUP",
        "WM_NCXBUTTONDBLCLK",
        "WM_NCUAHDRAWCAPTION", /* 0x00AE */
        "WM_NCUAHDRAWFRAME", /* 0x00AF */。。
    附录XP下的消息跟踪截断:
    <00353> 001D060E S WM_KICKIDLE
    <00354> 001D060E R WM_KICKIDLE
    <00355> 001D060E S WM_NCHITTEST xPos:476 yPos:178
    <00356> 001D060E R WM_NCHITTEST nHittest:HTCAPTION
    <00357> 001D060E S WM_MOUSEACTIVATE hwndTopLevel:001D060E nHittest:HTCAPTION uMsg:WM_LBUTTONDOWN
    <00358> 001D060E R WM_MOUSEACTIVATE fuActivate:MA_NOACTIVATE
    <00359> 001D060E S WM_SETCURSOR hwnd:001D060E nHittest:HTCAPTION wMouseMsg:WM_LBUTTONDOWN
    <00360> 001D060E R WM_SETCURSOR fHaltProcessing:False
    <00361> 001D060E P WM_NCLBUTTONDOWN nHittest:HTCAPTION xPos:476 yPos:178
    <00362> 001D060E S WM_WINDOWPOSCHANGING lpwp:0012F3FC
    <00363> 001D060E R WM_WINDOWPOSCHANGING
    <00364> 001D060E S WM_WINDOWPOSCHANGED lpwp:0012F3FC
    <00365> 001D060E R WM_WINDOWPOSCHANGED
    <00366> 001D060E S WM_ACTIVATEAPP fActive:True dwThreadID:00000000
    <00367> 001D060E R WM_ACTIVATEAPP
    <00368> 001D060E S WM_NCACTIVATE fActive:True
    <00369> 001D060E S .WM_GETICON fType:False
    <00370> 001D060E R .WM_GETICON hicon:7406065D
    <00371> 001D060E S .WM_GETTEXT cchTextMax:256 lpszText:0012DD5C
    <00372> 001D060E R .WM_GETTEXT cchCopied:8 lpszText:0012E6C4 ("SkinTest")
    <00373> 001D060E R WM_NCACTIVATE
    <00374> 001D060E S WM_ACTIVATE fActive:WA_CLICKACTIVE fMinimized:False hwndPrevious:(null)
    <00375> 001D060E S .WM_ACTIVATETOPLEVEL fActive:True dwThreadID:0012F01C
    <00376> 001D060E R .WM_ACTIVATETOPLEVEL
    <00377> 001D060E S ..WM_CTLCOLORBTN hdcButton:E3011CFE hwndButton:00340624
    <00378> 001D060E R ..WM_CTLCOLORBTN hBrush:01100060
    <00379> 001D060E R WM_ACTIVATE
    <00380> 001D060E S message:0x00AE [Unknown] wParam:00001000 lParam:00000000
    <00381> 001D060E S .WM_GETICON fType:False
    <00382> 001D060E R .WM_GETICON hicon:7406065D
    <00383> 001D060E S .WM_GETTEXT cchTextMax:256 lpszText:0012DDB8
    <00384> 001D060E R .WM_GETTEXT cchCopied:8 lpszText:0012E720 ("SkinTest")
    <00385> 001D060E R message:0x00AE [Unknown] lResult:00000001
    <00386> 001D060E S message:0x00AE [Unknown] wParam:00001000 lParam:00000000
    <00387> 001D060E S .WM_GETICON fType:False
    <00388> 001D060E R .WM_GETICON hicon:7406065D解决方案:
    截获以下2个消息,作抛弃或OnNcPaint()处理则可。
           0x00AE://WM_NCUAHDRAWCAPTION
            0x00AF://WM_NCUAHDRAWFRAME希望对以后处理窗体自绘的同行们有微薄作用, Have FUN!  ^_^
      

  6.   

    谢谢楼主,屏蔽0x00AE和0x00AFLRESULT CTalkDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
    {
    // TODO: 在此添加专用代码和/或调用基类
    if(message==0x00AE ||message==0x00AF)
    {
    // AfxMessageBox(_T("aaaa"));
    return TRUE;
    }
    return CDialog::DefWindowProc(message, wParam, lParam);
    }
      

  7.   

    11楼正解,不过还有一个问题,
    我拦截了WM_ACTIVATE和WM_NCACTIVATE消息,对WM_NCPAINT消息不做处理进行测试,刚打开的时候标题栏是空白一片,但是当窗口失去焦点又重新得到的时候,标题栏又重新画了出来,不知道这是在哪儿画的,请高手指点
      

  8.   

       DWORD dwStyle = pT->GetStyle();
       if( dwStyle & WS_VISIBLE ) 
       pT->SetWindowLong(GWL_STYLE, (dwStyle & ~WS_VISIBLE));
       
       pT->DefWindowProc(uMsg, wParam, lParam);
       
       if( dwStyle & WS_VISIBLE ) 
      pT->SetWindowLong(GWL_STYLE, dwStyle);这两个消息的确是令人讨厌的重绘了caption等,方法最好不是屏蔽,而是如上代码,暂时的设置window不可见,再调用DefWindowProc,而后再改回来。
      

  9.   

    win7 有同样的问题,但根本收不到 if(message==0x00AE ||message==0x00AF)消息