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


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

...全文
1764 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)
源码直接下载地址: https://pan.quark.cn/s/b2e30c4b4277 依据所提供的文件资料,可以总结出以下核心内容: 1. 华硕玩家国度x79 R4G主板属于高端级别的主板,归类于华硕玩家国度系列中的RAMPAGE IV GENE型号。该主板主要面向高端用户及游戏爱好者,具有卓越性能的特点。 2. 华硕玩家国度x79 R4G主板的使用指南采用简体中文版本,并以PDF格式发布。用户手册全面地阐述了该主板的操作方法和各项功能。 3. 版权声明明确指出,本手册包含的所有内容均受到著作权法的保护。未经华硕电脑股份有限公司(简称“华硕”)的许可,禁止进行任何形式的复制、剽窃、翻译或分发。 4. 免责声明具体说明,华硕提供的用户手册依照其发布时的状态呈现,不提供任何明示或暗示的保证。用户使用手册所面临的风险需自行承担,且华硕不对使用手册后的任何结果或信息的精确性或可靠性提供保证。 5. 用户手册中强调,使用本手册后可能引发的风险和损失,涵盖但不限于利益损失、业务中断、数据遗失或其他经济上的损失,华硕及其授权人员、雇员等均不承担相应责任。 6. 华硕拥有随时更新用户手册的权力。当产品规格或驱动程序发生变化时,用户手册将进行相应的修订。用户可以通过华硕的客户服务网站或直接联络华硕电脑客户关怀中心以获取最新版本的信息。 7. 第三方产品名称或内容的所有权和知识产权归属于各自的所有者,并受到相关法律法规的保护。 8. 在华硕的保修政策中,若产品经历过未经华硕授权的维修、规格调整、部件更换或其他未授权操作,或者产品序列号模糊不清或遗失,产品将不再享受华硕的保修和服务。 9. 华硕供应的主板及显卡产品在中国大陆地区(不包括港澳台地区)实施三年免费保修服务及全国联保服务...

15,976

社区成员

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

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