纯代码编写 skin 关于 WM_NCPAINT ,WM_NCCALCSIZE 的问题请教!

fox1999 2008-04-15 08:02:42
我现在只是想做一个 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 可以做到。


以上几点疑问,希望能在你有空的时间,给我一点指点,多谢了。

...全文
1691 33 打赏 收藏 转发到动态 举报
写回复
用AI写文章
33 条回复
切换为时间正序
请发表友善的回复…
发表回复
sstower 2012-06-13
  • 打赏
  • 举报
回复
不错,收藏了
davidcao007 2010-07-17
  • 打赏
  • 举报
回复
谁有代码了啊
发我一份感谢,感谢
davidcao007@163.com
MFCJCK 2009-07-28
  • 打赏
  • 举报
回复
一年前的帖子,启发很大,多谢各位
starwork 2008-07-11
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 darkduck9989 的回复:]
GDI+中也可以用Bitblt
我这下了Skin 5.0代码,你在网上找,如果还找不到就留个邮箱
[/Quote]


能不能给我一份: CNSTARWORK AT 126.COM,谢谢了(AT=@)
F42001 2008-05-04
  • 打赏
  • 举报
回复
谁有skin5.0的代码发我一份,谢谢所有的兄弟了。
F42001 2008-05-04
  • 打赏
  • 举报
回复
fox1999发我一份skin5.0的代码
F42001 2008-05-04
  • 打赏
  • 举报
回复
谁有skin5.0代码,请发我一份。一直对这个很感兴趣。
邮箱:dxd_09101011@163.com
谢谢。
fox1999 2008-05-02
  • 打赏
  • 举报
回复
感動呀
hehenihao158 2008-05-01
  • 打赏
  • 举报
回复
mark
xiaofeixia203 2008-05-01
  • 打赏
  • 举报
回复
21楼的fafa_cai实在,我喜欢!!!虽然你现在还不是专家头衔,但我感觉你还是比较牛。
小弟尚有几个问题需要请教,不知能否帮忙?
paerxiushi 2008-05-01
  • 打赏
  • 举报
回复
2楼的, happyparrot ,高人终于出来了,连续6年的潜水张于出来了,有他在,csdn社区就有希望。
meiZiNick 2008-05-01
  • 打赏
  • 举报
回复
支持搂主,收藏
海忠 2008-04-30
  • 打赏
  • 举报
回复
我现在对您的问题一一作个回答。

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 上海勇进软件有限公司)
fox1999 2008-04-21
  • 打赏
  • 举报
回复
我找到作者了,他發了一份給我,多謝各位了
fox1999 2008-04-19
  • 打赏
  • 举报
回复
darkduck9989 :
我看了你的那個帖子,也用了baidu. google 來搜 skin+5.0.rar 也沒搜到,只有你的那個貼子

貼子中的下載地方已經失效了。能不能發給我一份?多謝了 foxbat123@126.com
darkduck9989 2008-04-18
  • 打赏
  • 举报
回复
我不发你邮箱了,这个作者真的很厚道,不支持说不过去,csdn应该不少人看过的,感谢作者分享
baidu -> skin+5.0.rar
http://topic.csdn.net/t/20060926/12/5048699.html
Eleven 2008-04-18
  • 打赏
  • 举报
回复
up
fox1999 2008-04-18
  • 打赏
  • 举报
回复
GDI+中也可以用Bitblt
-------------------
GDI+ 是可以用 BitBlt, 但我的是 png, BitBlt 就不透明了
fox1999 2008-04-18
  • 打赏
  • 举报
回复
to darkduck9989

發我的郵箱吧。 foxbat123@126.com 多謝了
darkduck9989 2008-04-17
  • 打赏
  • 举报
回复
感觉很像skin++的设计思路,可下一份skin++代码研究下,其实主要是两部分,1 消息分配 2 绘制
加载更多回复(12)

15,978

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 界面
社区管理员
  • 界面
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧