您的位置:首页 > 其它

谈WinForm窗体重绘

2013-04-10 09:11 148 查看
谈WinForm窗体重绘

在工作之余花了较长的时间终于将LiuZhenHong.Controls 1.x升级到2.0。在这一过程中拜读了许多大师的博文,从中也学到了很多的知识。在此想就窗体重绘向大家简单谈谈自己的观点和实现。

WinForm程序员或多或少的都想过重绘窗体的外观,尤其是在XP时代。我在实现LiuZhenHong.Controls 2.0时也遇到了这样的问题。于是直接海搜,发现网上关于窗体重绘的代码还真不少。但我发现他们的实现方法大相径庭,都是将窗体(Form)设置为无边框类型(None),然后在重写展现矩形框(DisplayRectangle),贴上事先截取好的按钮图片和标题栏图片,这样便从展现的角度实现了窗体的重绘。乍一看确实效果还可以,但是在很多细节方面就会出现一些瑕疵,如:右击标题栏无法弹出系统的快捷菜单,无法很好的控制窗体尺寸的自由拉升等等。

那为什么会出现这些问题呢?其实,我个人理解是因为我们没有真正理解窗体重绘的概念。 所谓窗体重绘:其实就是重新绘制窗体原有的渲染方式,而不修改窗体的外观属性,由此看来上述做法可谓是南辕北辙。举个不恰当的例子吧,一个小伙子来到理发店对理发师说帮我换个炫酷发型,于是理发师直接将其剃个光头给他戴上一个炫酷的假发便草草了事。要知道窗体重绘区都携带着自己对应的信息,就像每个人的头发都可以提取DNA信息一样。其实我个人认为无边框窗体主要是为实现异形窗体而存在的。

下面我就向大家简单介绍一下窗体结构组成:从图一我们可以看出窗体的关键是重绘“标题区”和“点击区”,即:窗体的非客户区,与非客户区相对应的是客户区(即:灰色的内部面状区域)。要知道窗体的客户区和非客户区一样也有对应的绘制、单击等操作,只是客户区我们可以通过对应的事件来捕获,而非客户区就有点棘手了。要知道窗体事件的来源其实质是消息的传递,即先有的鼠标单击消息,经过解析和处理才会有对应的鼠标单击事件。知道这一点我们便可以通过重写WndProc函数来截获窗体消息,进而获取非客户区重绘所需的所有信息。在CodeProject官网里还是可以找到一些大牛们的类似作品。



图一

下面我将简单地做一个做重绘窗体标题区的小例子供大家参考(效果图如:图二)。至于如何做到尽善尽美还有待大家更深入的探索和研究,这也就是窗体重绘真正难点的所在。

public partial class Form2 : Form

{

[DllImport("user32", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]

public static extern IntPtr GetWindowDC(IntPtr hWnd);

[DllImport("user32", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]

public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

public Form2()

{

InitializeComponent();

}

protected override void WndProc(ref Message m)

{

base.WndProc(ref m);

//

switch (m.Msg)

{

case 0x0085://WM_NCPAINT 非客户区重绘

this.WndNCPaint(m.HWnd);

return;

default:

break;

}

}

private bool WndNCPaint(IntPtr iHWnd)

{

try

{

IntPtr iHandle = GetWindowDC(iHWnd);//非客户区获取句柄

Graphics g = Graphics.FromHdc(iHandle);//获取Graphics对象

//

g.FillRectangle

(

Brushes.Pink,

new Rectangle(System.Windows.Forms.SystemInformation.FrameBorderSize.Width,

System.Windows.Forms.SystemInformation.FrameBorderSize.Width,

this.Width - 2 * System.Windows.Forms.SystemInformation.FrameBorderSize.Width,

System.Windows.Forms.SystemInformation.CaptionHeight)

);

//

g.Dispose();//释放

ReleaseDC(iHWnd, iHandle);//释放句柄

}

catch { return false; }

//

return true;

}

}



图二

相关链接:

Winforms SkinFramework窗体重绘源码下载地址: http://www.codeproject.com/Articles/61485/Winforms-SkinFramework
点击打开链接

LiuZhenHong.Controls 2.0第三方控件Demo下载地址: http://download.csdn.net/download/ll_zz_hh_/5237692
点击打开链接
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: