谈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官网里还是可以找到一些大牛们的类似作品。
![](http://b160.photo.store.qq.com/psb?/62622aae-15fd-4d83-9d3d-4f1656927882/YEltt.LswwEjqwwHqO3QDKYc6.ACxAX.mt5QgcTl94Q!/b/dK1Pal.eFgAA&bo=nAIEAgAAAAABAL8!)
图一
下面我将简单地做一个做重绘窗体标题区的小例子供大家参考(效果图如:图二)。至于如何做到尽善尽美还有待大家更深入的探索和研究,这也就是窗体重绘真正难点的所在。
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;
}
}
![](http://b161.photo.store.qq.com/psb?/62622aae-15fd-4d83-9d3d-4f1656927882/69KRqwxTLA87jAI9KOKHcCPzxXYqkhZJTcc7fCRAF2M!/b/dNZf*l*RFQAA&bo=dALkAQAAAAABALQ!)
图二
相关链接:
Winforms SkinFramework窗体重绘源码下载地址: http://www.codeproject.com/Articles/61485/Winforms-SkinFramework
点击打开链接。
LiuZhenHong.Controls 2.0第三方控件Demo下载地址: http://download.csdn.net/download/ll_zz_hh_/5237692
点击打开链接。
在工作之余花了较长的时间终于将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
点击打开链接。
相关文章推荐
- 重绘Winform窗体
- 介绍一款非常出色的WinForm窗体重绘GUI类库源码
- WinForm经典窗体皮肤[重绘]
- 重绘Winform窗体
- winform 在mdi窗口重绘界面时,mdi挡住主窗体,导致鼠标拖动缩放窗体大小失效的解决方法随笔
- 非常出色的一款WinForm窗体重绘GUI类库源码
- winform中窗体显示和传值
- WINFORM如何禁止调整窗体大小
- WinForm,窗体靠近屏幕边缘自动隐藏
- 深入Windows窗体原理及控件重绘技巧
- C#WinForm利用DataGridView创作高级查询窗体
- 比较经典的为C# Winform程序设置登录窗体先启动,成功后再启动主窗口
- 在2015中使用V12版本的ReportView控件,会导致winform窗体不能正常打开
- [转]C#WinForm窗体事件执行次序
- winform窗体绑定监控键盘事件
- C#WinForm中怎么设置窗体不可以拉大和拖动,不可以拖动窗体的位置,让他固定不动啊?
- winform 如何绘制窗体? - what a mess
- WPF加载Winform窗体时 报错:子控件不能为顶级窗体
- 如何在多线程中调用winform窗体控件
- winform 窗体换皮肤,IrisSkin2.dll的用法