纯代码编写 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 可以做到。


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

...全文
1700 33 打赏 收藏 转发到动态 举报
AI 作业
写回复
用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,980

社区成员

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

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