我现在只是想做一个 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 可以做到。
以上几点疑问,希望能在你有空的时间,给我一点指点,多谢了。
我的做方法 得到窗体的 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 可以做到。
以上几点疑问,希望能在你有空的时间,给我一点指点,多谢了。
和你的思路差不多,用了hook,好像用了双缓冲,没仔细看。我觉得速度还可以,不知是否达到lz的要求。
但在處理透明,半透時時 GDI+ 更方便,但速度上 GDI 更快。有沒有更好的方法
我这下了Skin 5.0代码,你在网上找,如果还找不到就留个邮箱
發我的郵箱吧。 [email protected] 多謝了
-------------------
GDI+ 是可以用 BitBlt, 但我的是 png, BitBlt 就不透明了
baidu -> skin+5.0.rar
http://topic.csdn.net/t/20060926/12/5048699.html
我看了你的那個帖子,也用了baidu. google 來搜 skin+5.0.rar 也沒搜到,只有你的那個貼子貼子中的下載地方已經失效了。能不能發給我一份?多謝了 [email protected]
它在 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 上海勇进软件有限公司)
小弟尚有几个问题需要请教,不知能否帮忙?
邮箱:[email protected]
谢谢。
发我一份感谢,感谢
[email protected]