我现在只是想做一个 skin 的 Form 出来。
我的做方法 得到窗体的 windowProc 指针,把它指向我的新 windowProc,再在我的 WindowProc 里拦 WM_NCxxx 消息,像对本窗口的边框 与栏题栏进行自画。
 
现在的问题有:
1. 诡异的 WM_NCCALCSIZE. 这个消息在 MSDN 上也说的不是很清楚。
          它在 wParam为真或假时 lParam 分别指向的内容不一样。而 MDSN 上也不是说的太说细,测试了很久也不是很明白,找到的一些代码只是说在 wParam 为真时,第一个矩形为窗口的位置,直接把它改小就可以了。但问题是第一次执行程序,居然不触发 WM_NCCALCSIZE 事件。但拉动窗口大小时,它又会触发。
 
2. 同样诡异的 WM_NCPAINT 与 GetDcEx
   这个消息在绘标题栏时触发。wParam 为 NC 区域的 HRGN (MSDN上说的). 但我的测试用 MSDN 上的代码基本就是不行,MSDN 上是用 GetDcEx 来得到 NC 区域的 DC.但我得到的 HDC 基本就不能绘画。最后用笨方法,用 GetWindowDc 得到窗口的 HDC,但手动算出 NC 区域的 HRGN 再 selectObject 把这个 HRGN 放到 HDC 里。
 
3. 更加诡异的 WM_NCHITTEST
 本来以我的想法,在 WM_NCHITTEST 里返回指定的值如 HTCLOSE,表示鼠标在 close 按钮上。我就这样测试,不窗鼠标在哪里,我都返回 HTCLOSE,这时我随便按那里,都是 close 按钮被按下了。但我松开鼠标,这时窗口居然没有被关闭。好呀,我在 WM_NCLBUTTONUP 里wparam = HTCLOSE 时,我 PostMessage( WM_SYSCOMMAND ,SC_CLOSE)。这样居然有时可能,有时又不行。
 
4. 效率如何提高?
  现在我没用双缓冲。每次都直接在窗口HDC 上画,但效果很低,特别时把一部分窗口移到桌面以外,慢慢向里拉时,CPU 占用很高。很时显停止状。想做成双缓冲,但一时也想不到如何做。在窗口大小变化时,内存 DC 如何处理?也跟着变?然后再画出来?这样我想效率也不会提高。
 
5. 边角不规则如何处理?
  现在要求窗口边角是圆边矩形,那还好做点,用 SetWindowRgn 来处理。但对不是很好描述的奇怪点的窗口呢?又要如何处理?我知道 vclskin 可以做到。
 
 
以上几点疑问,希望能在你有空的时间,给我一点指点,多谢了。
 

解决方案 »

  1.   

    不规则窗口,一般是要绘制一张窗口形状的图片,逐行扫描该图片,去除透明色,作为高度为1的矩形,CreateRectRgn,然后CombineRgn把每一行的这些RGN合并起来,就得到了整个不规则形状的RGN.
      

  2.   

    這是我現在做的也許 ringphone 的方法是對的現在最大的問題還是效率,重繪時太慢了
      

  3.   

    http://www.vckbase.com/document/viewdoc/?id=529
    和你的思路差不多,用了hook,好像用了双缓冲,没仔细看。我觉得速度还可以,不知是否达到lz的要求。
      

  4.   

    buyong 找到的資料很好,多謝了
      

  5.   

    感觉很像skin++的设计思路,可下一份skin++代码研究下,其实主要是两部分,1 消息分配 2 绘制
      

  6.   

    Skin++ 哪裡有代碼下???
      

  7.   

    用了雙緩沖,情況有所改善,但我發現 GDI+ 畫 png 的速度比 GDI 畫 bmp 的速度慢,慢了近 3倍了。
    但在處理透明,半透時時 GDI+ 更方便,但速度上 GDI 更快。有沒有更好的方法
      

  8.   

    GDI+中也可以用Bitblt
    我这下了Skin 5.0代码,你在网上找,如果还找不到就留个邮箱
      

  9.   

    to darkduck9989 
     
      發我的郵箱吧。 [email protected] 多謝了
      

  10.   

    GDI+中也可以用Bitblt 
    -------------------
    GDI+ 是可以用 BitBlt,  但我的是 png, BitBlt 就不透明了
      

  11.   

    我不发你邮箱了,这个作者真的很厚道,不支持说不过去,csdn应该不少人看过的,感谢作者分享
    baidu  -> skin+5.0.rar
    http://topic.csdn.net/t/20060926/12/5048699.html
      

  12.   

    darkduck9989 :
      我看了你的那個帖子,也用了baidu. google 來搜 skin+5.0.rar 也沒搜到,只有你的那個貼子貼子中的下載地方已經失效了。能不能發給我一份?多謝了 [email protected]
      

  13.   

    我现在对您的问题一一作个回答。1. 诡异的 WM_NCCALCSIZE. 这个消息在 MSDN 上也说的不是很清楚。 
              它在 wParam为真或假时 lParam 分别指向的内容不一样。而 MDSN 上也不是说的太说细,测试了很久也不是很明白,找到的一些代码只是说在 wParam 为真时,第一个矩形为窗口的位置,直接把它改小就可以了。但问题是第一次执行程序,居然不触发 WM_NCCALCSIZE 事件。但拉动窗口大小时,它又会触发。 
          答:WM_NCCALCSIZE消息就是设置窗体的客户区与非客户区的大小。下面是Skin++的相关代码,你可以参考之。
    LRESULT CSkinObjectBase::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
    switch(msg)
    {
            case WM_NCCALCSIZE:
    return OnNcCalcSize((BOOL)wParam, (NCCALCSIZE_PARAMS *)lParam );
            
            }
    }LRESULT CSkinFrameBase::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS *lpncsp)
    {
    if ( bCalcValidRects )
    {
    CRect oldrect = lpncsp->rgrc[0];
    NcCalcSize(lpncsp->rgrc[0]);
    lpncsp->rgrc[1] = lpncsp->rgrc[0];
    return 0;
    } return Default();
    }void CSkinFrameBase::NcCalcSize(RECT& rect)
    {
    if (HasCaption())
    {
    rect.left +=  m_nBorderLeftWidth;//窗体左边框的宽度
    rect.right -= m_nBorderRightWidth;//窗体右边框的宽度
    rect.top += m_nTitleHeight; //窗体标题栏的高度
    rect.bottom -= m_nBorderBottomHeight;//窗体底边框的高度
    }
            
            。。
    }
      
    2. 同样诡异的 WM_NCPAINT 与 GetDcEx 
       这个消息在绘标题栏时触发。wParam 为 NC 区域的 HRGN (MSDN上说的). 但我的测试用 MSDN 上的代码基本就是不行,MSDN 上是用 GetDcEx 来得到 NC 区域的 DC.但我得到的 HDC 基本就不能绘画。最后用笨方法,用 GetWindowDc 得到窗口的 HDC,但手动算出 NC 区域的 HRGN 再 selectObject 把这个 HRGN 放到 HDC 里。 
       答:在WM_NCPAINT消息中,我们可以通过GetWindowDC获得窗体的非客户区DC,然后在上面任意画图,不必考虑什么HRGN等。参考代码如下:LRESULT CSkinFrameBase::OnNcPaint(HDC hDC)
    {
        CWindowDC dc(m_hWnd);
        DrawTitleBar(&dc);

        return TRUE;
    }
    void CSkinFrameBase::DrawTitleBar(CDC* pDC)
    {
    CRect wr,rClient;
    GetDrawRect(wr,rClient); CDC memDC;
    memDC.CreateCompatibleDC(pDC);
    CBitmap bmpFrame;
    bmpFrame.CreateCompatibleBitmap(pDC,wr.Width(),wr.Height());
    CBitmap* pOldbmp = memDC.SelectObject(&bmpFrame);
    DrawFrame(memDC,!m_bActive,1); CRect rSkinDraw(wr);
    rSkinDraw.bottom = rSkinDraw.top + m_nTitleHeight;

    rSkinDraw.left = m_pFrameBase->bDefaultDraw ? m_nBorderLeftWidth : 0;
    rSkinDraw.right -= m_pFrameBase->bDefaultDraw ? m_nBorderRightWidth : 0; DrawTitleBarText(memDC,rSkinDraw);

    //////////////////////////////////////////////////////////////////////////

    rSkinDraw = wr;
    rSkinDraw.bottom = rSkinDraw.top + m_nTitleHeight;
    DrawSystemButton(&memDC,rSkinDraw);

    int nSavedDC = pDC->SaveDC(); CRect rcClip = GetExcludeClipRect(); pDC->ExcludeClipRect(rcClip); pDC->BitBlt( 0, 0, wr.Width(),wr.Height(), &memDC, 0, 0, SRCCOPY ); pDC->RestoreDC(nSavedDC); memDC.SelectObject(pOldbmp);
    bmpFrame.DeleteObject();
    memDC.DeleteDC();//*/
    }
      
    3. 更加诡异的 WM_NCHITTEST 
     本来以我的想法,在 WM_NCHITTEST 里返回指定的值如 HTCLOSE,表示鼠标在 close 按钮上。我就这样测试,不窗鼠标在哪里,我都返回 HTCLOSE,这时我随便按那里,都是 close 按钮被按下了。但我松开鼠标,这时窗口居然没有被关闭。好呀,我在 WM_NCLBUTTONUP 里wparam = HTCLOSE 时,我 PostMessage( WM_SYSCOMMAND ,SC_CLOSE)。这样居然有时可能,有时又不行。 
        答:你的这个做法似乎看不出哪里不对,可以参考下面的代码:LRESULT CSkinFrameBase::OnNcLButtonUp(UINT nHitTest, CPoint point)
    {
    LRESULT lResult = Default(); if (m_uCustomBtnHitTest != HTNOWHERE)
    {
    ::SendMessage(m_hWndHooked,SM_TITLELBUTTONUP,(WPARAM)m_uCustomBtnHitTest,MAKELPARAM(point.x,point.y));
    m_downHitTest = 0;
    m_moveHitTest = 0;
    OnNcPaint(NULL);
    return lResult;
    }

    switch (nHitTest)
    {
    case HTCLOSE:
    {
      if (m_closeable)
      {
          //应该用postmessage
          lResult = ::PostMessage(m_hWndHooked,WM_SYSCOMMAND,(WPARAM)SC_CLOSE,MAKELPARAM(point.x,point.y));
           return lResult;
       }
    }
    break;
              ................
             }
    }  
    4. 效率如何提高? 
      现在我没用双缓冲。每次都直接在窗口HDC 上画,但效果很低,特别时把一部分窗口移到桌面以外,慢慢向里拉时,CPU 占用很高。很时显停止状。想做成双缓冲,但一时也想不到如何做。在窗口大小变化时,内存 DC 如何处理?也跟着变?然后再画出来?这样我想效率也不会提高。 
       答:效率与双缓冲没有关系,在对窗体进行绘制时必须使用内存DC,否则你的界面会闪烁。同时内存DC是在你绘图时动态创建的,所以窗口改变大小时,它也跟着变化的。  
    5. 边角不规则如何处理? 
      现在要求窗口边角是圆边矩形,那还好做点,用 SetWindowRgn 来处理。但对不是很好描述的奇怪点的窗口呢?又要如何处理?我知道 vclskin 可以做到。 
      答:估计你对SetWindowRgn有些误解,你这个地方的问题关键在于异型区域如何产生的问题。简单的可以使用GDI提供的几个创建形状的区域函数,复杂可以使用根据图片来生成区域。典型的函数CreateRgnFromFile(HBITMAP hBmp,COLORREF color /* = RGB(255,0,255)*/ ),你可以参考使用。
    ===============================================================================
    阙海忠 (CTO Skin++ 开发成员 http://www.uipower.com 上海勇进软件有限公司)
      

  14.   

    2楼的, happyparrot ,高人终于出来了,连续6年的潜水张于出来了,有他在,csdn社区就有希望。
      

  15.   

    21楼的fafa_cai实在,我喜欢!!!虽然你现在还不是专家头衔,但我感觉你还是比较牛。
    小弟尚有几个问题需要请教,不知能否帮忙?
      

  16.   

    谁有skin5.0代码,请发我一份。一直对这个很感兴趣。
    邮箱:[email protected]
    谢谢。
      

  17.   

     fox1999发我一份skin5.0的代码
      

  18.   

    谁有skin5.0的代码发我一份,谢谢所有的兄弟了。
      

  19.   

    能不能给我一份: CNSTARWORK AT 126.COM,谢谢了(AT=@)
      

  20.   

    谁有代码了啊 
    发我一份感谢,感谢
    [email protected]