在这里先跟大家说一下,由于我也是菜鸟型人物,C#、Winform完全是因为兴趣爱好而自学的,所以很不专业,里面的一些说明、注释都是跟据我自己的理解来说明的,如果因为我的错误而对大家的造成误导,在这里我表示歉意,同时我希望大家能指出来,我会予以改正。
我现们现在进入正题(基本以后用到GDI+会很多,所以GDI要学习一下,虽然我也不怎么会,但建议去看下,推荐一个网站:点击进入)
效果如果:
一.说明:
1.提取QQ2010版的皮肤数据:因为我的程序皮肤是基于QQ的皮肤,所以我们要先提取出QQ的皮肤文件(当然,你也可以自己用PS做皮肤)。QQ的皮肤文件在QQ安装目录的一个名为Res.rdb打包文件里,要提取里同的皮肤文件,我要先解压他(工具:RDB打包解包工具)图如下。
[基本上以后控件美化都会用到里面的皮肤文件]
2.窗口皮肤制作概要说明:QQ的窗口看上去是有光泽效果的,制作光泽效果是其实是一张半透明的PNG图片画在在窗口区域里。例如图
看是去是不是有点明白了,所以我们要做的就是根据要求选一个透明的PNG图片,根据窗口大小画上去。
二.制作(详细的自己看里面代码)
1.在工程里新建一个(AlBaseForm.cs)代码窗口
类文件
// 作者:阿龙(Along)
// QQ号:646494711
// QQ群:57218890
// 网站: http://www.8timer.com
// 博客: http://www.cnblogs.com/Along729/
// 声明:未经作者许可,任何人不得发布出售该源码,请尊重别人的劳动成果,谢谢大家支持
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using AlSkin.AlClass;
namespace AlSkin.AlForm
{
public partial class AlBaseForm : Form
{
#region 声明
private Bitmap _BacklightImg; // 窗体光泽背景图片
private Rectangle _BacklightLTRB; // 窗体光泽重绘边界
private int _RgnRadius = 4 ; // 设置窗口圆角
private int Rgn;
private Graphics g;
private bool _IsResize = true ; // 是否允许改变窗口大小
private FormSystemBtn _FormSystemBtnSet = FormSystemBtn.SystemAll;
private Bitmap btn_closeImg = ImageObject.GetResBitmap( " AlSkin.AlSkinImg.AlFormImg.btn_close.png " );
private Bitmap btn_maxImg = ImageObject.GetResBitmap( " AlSkin.AlSkinImg.AlFormImg.btn_max.png " );
private Bitmap btn_miniImg = ImageObject.GetResBitmap( " AlSkin.AlSkinImg.AlFormImg.btn_mini.png " );
private Bitmap btn_restoreImg = ImageObject.GetResBitmap( " AlSkin.AlSkinImg.AlFormImg.btn_restore.png " );
// 枚举系统按钮状态
public enum FormSystemBtn
{
SystemAll = 0 ,
SystemNo = 1 ,
btn_close = 2 ,
btn_miniAndbtn_close = 3 ,
btn_maxAndbtn_close = 4
}
#endregion
#region 构造函数
public AlBaseForm()
{
InitializeComponent();
this .SetStyle(ControlStyles.UserPaint, true ); // 自绘
this .SetStyle(ControlStyles.DoubleBuffer, true ); // 双缓冲
this .SetStyle(ControlStyles.ResizeRedraw, true ); // 调整大小时重绘
this .SetStyle(ControlStyles.AllPaintingInWmPaint, true ); // 禁止擦除背景.
this .SetStyle(ControlStyles.OptimizedDoubleBuffer, true ); // 双缓冲
// this.SetStyle(ControlStyles.Opaque, true); // 如果为真,控件将绘制为不透明,不绘制背景
this .SetStyle(ControlStyles.SupportsTransparentBackColor, true ); // 透明效果
SystemBtnSet();
}
#endregion
#region 属性
[DefaultValue( 4 )]
[CategoryAttribute( " 阿龙窗口属性 " ), Description( " 设置窗口圆角半径 " )]
public int RgnRadius
{
get { return this ._RgnRadius; }
set {
_RgnRadius = value;
this .Invalidate();
}
}
[CategoryAttribute( " 阿龙窗口属性 " ), Description( " 设置窗体光泽背景 " )]
public Bitmap BacklightImg
{
get { return this ._BacklightImg; }
set {
_BacklightImg = value;
this .Invalidate();
}
}
[CategoryAttribute( " 阿龙窗口属性 " ), Description( " 设置窗体光泽背景重绘边界,例如 10,10,10,10 " )]
public Rectangle BacklightLTRB
{
get { return this ._BacklightLTRB; }
set {
_BacklightLTRB = value;
if (_BacklightLTRB != Rectangle.Empty)
{
this .Invalidate();
}
}
}
[DefaultValue( true )]
[CategoryAttribute( " 阿龙窗口属性 " ), Description( " 是否允许改变窗口大小 " )]
public bool IsResize
{
get { return this ._IsResize; }
set { _IsResize = value;}
}
[CategoryAttribute( " 阿龙窗口属性 " ), Description( " 系统按钮设置 " )]
public FormSystemBtn FormSystemBtnSet
{
get
{
return _FormSystemBtnSet;
}
set
{
_FormSystemBtnSet = value;
this .Invalidate();
}
}
#endregion
#region 重写方法
protected override void OnInvalidated(InvalidateEventArgs e)
{
SetReion();
SystemBtnSet();
base .OnInvalidated(e);
}
// 重绘窗口
protected override void OnPaint(PaintEventArgs e)
{
try
{
g = e.Graphics;
g.SmoothingMode = SmoothingMode.HighQuality; // 高质量
g.PixelOffsetMode = PixelOffsetMode.HighQuality; // 高像素偏移质量
ImageDrawRect.DrawRect(g, _BacklightImg, ClientRectangle, Rectangle.FromLTRB(_BacklightLTRB.X, _BacklightLTRB.Y, _BacklightLTRB.Width, _BacklightLTRB.Height), 1 , 1 );
}
catch
{ }
}
// 重载WndProc方法
protected override void WndProc( ref Message m)
{
try
{
switch (m.Msg)
{
// 窗体客户区以外的重绘消息,一般是由系统负责处理
case Win32.WM_NCPAINT:
break ;
// 画窗体被激活或者没有被激活时的样子 // http://blog.csdn.net/commandos/archive/2007/11/27/1904558.aspx
case Win32.WM_NCACTIVATE:
if (m.WParam == (IntPtr)Win32.WM_FALSE)
{
m.Result = (IntPtr)Win32.WM_TRUE;
}
break ;
// 在需要计算窗口客户区的大小和位置时发送。通过处理这个消息,应用程序可以在窗口大小或位置改变时控制客户区的内容
case Win32.WM_NCCALCSIZE:
break ;
// 鼠标移动,按下或释放都会执行该消息
case Win32.WM_NCHITTEST:
WM_NCHITTEST( ref m);
break ;
default :
base .WndProc( ref m);
break ;
}
}
catch { }
}
#endregion
#region 方法
protected void SystemBtnSet()
{
switch (( int )_FormSystemBtnSet)
{
case 0 :
btn_close.BackImg = btn_closeImg;
btn_close.Location = new Point( this .Width - 43 , 6 );
btn_mini.BackImg = btn_miniImg;
btn_mini.Location = new Point( this .Width - 93 , 6 );
btn_max.BackImg = btn_maxImg;
btn_restore.BackImg = btn_restoreImg;
if (WindowState == FormWindowState.Normal)
{
btn_max.Location = new Point( this .Width - 68 , 6 );
btn_restore.Location = new Point( this .Width - 68 , - 20 );
}
else
{
btn_max.Location = new Point( this .Width - 68 , - 20 );
btn_restore.Location = new Point( this .Width - 68 , 6 );
}
break ;
case 1 :
btn_close.BackImg = btn_closeImg;
btn_close.Location = new Point( this .Width - 43 , - 20 );
btn_max.BackImg = btn_maxImg;
btn_max.Location = new Point( this .Width - 68 , - 20 );
btn_mini.BackImg = btn_miniImg;
btn_mini.Location = new Point( this .Width - 93 , - 20 );
btn_restore.BackImg = btn_restoreImg;
btn_restore.Location = new Point( this .Width - 68 , - 20 );
break ;
case 2 :
btn_close.BackImg = btn_closeImg;
btn_close.Location = new Point( this .Width - 43 , 6 );
btn_max.BackImg = btn_maxImg;
btn_max.Location = new Point( this .Width - 68 , - 20 );
btn_mini.BackImg = btn_miniImg;
btn_mini.Location = new Point( this .Width - 93 , - 20 );
btn_restore.BackImg = btn_restoreImg;
btn_restore.Location = new Point( this .Width - 68 , - 20 );
break ;
case 3 :
btn_close.BackImg = btn_closeImg;
btn_close.Location = new Point( this .Width - 43 , 6 );
btn_max.BackImg = btn_maxImg;
btn_max.Location = new Point( this .Width - 68 , - 20 );
btn_mini.BackImg = btn_miniImg;
btn_mini.Location = new Point( this .Width - 68 , 6 );
btn_restore.BackImg = btn_restoreImg;
btn_restore.Location = new Point( this .Width - 68 , - 20 );
break ;
case 4 :
btn_close.BackImg = btn_closeImg;
btn_close.Location = new Point( this .Width - 43 , 6 );
btn_mini.BackImg = btn_miniImg;
btn_mini.Location = new Point( this .Width - 93 , - 20 );
btn_max.BackImg = btn_maxImg;
btn_restore.BackImg = btn_restoreImg;
if (WindowState == FormWindowState.Normal)
{
btn_max.Location = new Point( this .Width - 68 , 6 );
btn_restore.Location = new Point( this .Width - 68 , - 20 );
}
else
{
btn_max.Location = new Point( this .Width - 68 , - 20 );
btn_restore.Location = new Point( this .Width - 68 , 6 );
}
break ;
}
}
/// <summary>
/// 给窗口圆角
/// </summary>
protected void SetReion()
{
Rgn = Win32.CreateRoundRectRgn( 5 , 5 , ClientRectangle.Width - 4 , ClientRectangle.Height - 4 , _RgnRadius, _RgnRadius);
Win32.SetWindowRgn( this .Handle, Rgn, true );
}
private void WM_NCHITTEST( ref Message m)
{
int wparam = m.LParam.ToInt32();
Point point = new Point(Win32.LOWORD(wparam),Win32.HIWORD(wparam));
point = PointToClient(point);
if (_IsResize)
{
if (point.X <= 8 )
{
if (point.Y <= 8 )
m.Result = (IntPtr)Win32.HTTOPLEFT;
else if (point.Y > Height - 8 )
m.Result = (IntPtr)Win32.HTBOTTOMLEFT;
else
m.Result = (IntPtr)Win32.HTLEFT;
}
else if (point.X >= Width - 8 )
{
if (point.Y <= 8 )
m.Result = (IntPtr)Win32.HTTOPRIGHT;
else if (point.Y >= Height - 8 )
m.Result = (IntPtr)Win32.HTBOTTOMRIGHT;
else
m.Result = (IntPtr)Win32.HTRIGHT;
}
else if (point.Y <= 8 )
{
m.Result = (IntPtr)Win32.HTTOP;
}
else if (point.Y >= Height - 8 )
m.Result = (IntPtr)Win32.HTBOTTOM;
else
m.Result = (IntPtr)Win32.HTCAPTION;
}
else
{ m.Result = (IntPtr)Win32.HTCAPTION; }
}
#endregion
#region 事件
private void btn_close_Click( object sender, EventArgs e)
{
this .Close();
}
private void btn_mini_Click( object sender, EventArgs e)
{
this .WindowState = FormWindowState.Minimized;
}
private void btn_max_Click( object sender, EventArgs e)
{
this .WindowState = FormWindowState.Maximized;
}
private void btn_restore_Click( object sender, EventArgs e)
{
this .WindowState = FormWindowState.Normal;
}
#endregion
}
}
我先声明几个变量
private Bitmap _BacklightImg; // 窗体光泽背景图片
private Rectangle _BacklightLTRB; // 窗体光泽重绘边界
private int _RgnRadius = 4 ; // 设置窗口圆角
private int Rgn;
private Graphics g;
private bool _IsResize = true ; // 是否允许改变窗口大小
private FormSystemBtn _FormSystemBtnSet = FormSystemBtn.SystemAll;
private Bitmap btn_closeImg = ImageObject.GetResBitmap( " AlSkin.AlSkinImg.AlFormImg.btn_close.png " );
private Bitmap btn_maxImg = ImageObject.GetResBitmap( " AlSkin.AlSkinImg.AlFormImg.btn_max.png " );
private Bitmap btn_miniImg = ImageObject.GetResBitmap( " AlSkin.AlSkinImg.AlFormImg.btn_mini.png " );
private Bitmap btn_restoreImg = ImageObject.GetResBitmap( " AlSkin.AlSkinImg.AlFormImg.btn_restore.png " );
通过自定义一些属性,后期可以定制自己的窗口效果
#region 属性
[DefaultValue( 4 )]
[CategoryAttribute( " 阿龙窗口属性 " ), Description( " 设置窗口圆角半径 " )]
public int RgnRadius
{
get { return this ._RgnRadius; }
set {
_RgnRadius = value;
this .Invalidate();
}
}
[CategoryAttribute( " 阿龙窗口属性 " ), Description( " 设置窗体光泽背景 " )]
public Bitmap BacklightImg
{
get { return this ._BacklightImg; }
set {
_BacklightImg = value;
this .Invalidate();
}
}
[CategoryAttribute( " 阿龙窗口属性 " ), Description( " 设置窗体光泽背景重绘边界,例如 10,10,10,10 " )]
public Rectangle BacklightLTRB
{
get { return this ._BacklightLTRB; }
set {
_BacklightLTRB = value;
if (_BacklightLTRB != Rectangle.Empty)
{
this .Invalidate();
}
}
}
[DefaultValue( true )]
[CategoryAttribute( " 阿龙窗口属性 " ), Description( " 是否允许改变窗口大小 " )]
public bool IsResize
{
get { return this ._IsResize; }
set { _IsResize = value;}
}
[CategoryAttribute( " 阿龙窗口属性 " ), Description( " 系统按钮设置 " )]
public FormSystemBtn FormSystemBtnSet
{
get
{
return _FormSystemBtnSet;
}
set
{
_FormSystemBtnSet = value;
this .Invalidate();
}
}
#endregio
调用API 给窗口圆角
/// <summary>
/// 给窗口圆角
/// </summary>
protected void SetReion()
{
Rgn = Win32.CreateRoundRectRgn( 5 , 5 , ClientRectangle.Width - 4 , ClientRectangle.Height - 4 , _RgnRadius, _RgnRadius);
Win32.SetWindowRgn( this .Handle, Rgn, true );
}
通过重载 OnPaint方法,把带光泽效果的PNG图片图上去
// 重绘窗口
protected override void OnPaint(PaintEventArgs e)
{
try
{
g = e.Graphics;
g.SmoothingMode = SmoothingMode.HighQuality; // 高质量
g.PixelOffsetMode = PixelOffsetMode.HighQuality; // 高像素偏移质量
ImageDrawRect.DrawRect(g, _BacklightImg, ClientRectangle, Rectangle.FromLTRB(_BacklightLTRB.X, _BacklightLTRB.Y, _BacklightLTRB.Width, _BacklightLTRB.Height), 1 , 1 );
}
catch
{ }
}
通过重 重载WndProc方法 拦截窗口消息实现对窗口拖大缩小,系统按钮功能操作
// 重载WndProc方法
protected override void WndProc( ref Message m)
{
try
{
switch (m.Msg)
{
// 窗体客户区以外的重绘消息,一般是由系统负责处理
case Win32.WM_NCPAINT:
break ;
// 画窗体被激活或者没有被激活时的样子 // http://blog.csdn.net/commandos/archive/2007/11/27/1904558.aspx
case Win32.WM_NCACTIVATE:
if (m.WParam == (IntPtr)Win32.WM_FALSE)
{
m.Result = (IntPtr)Win32.WM_TRUE;
}
break ;
// 在需要计算窗口客户区的大小和位置时发送。通过处理这个消息,应用程序可以在窗口大小或位置改变时控制客户区的内容
case Win32.WM_NCCALCSIZE:
break ;
// 鼠标移动,按下或释放都会执行该消息
case Win32.WM_NCHITTEST:
WM_NCHITTEST( ref m);
break ;
default :
base .WndProc( ref m);
break ;
}
}
catch { }
三.窗口功能介绍
通过自定义的属性可以改变窗口的一些效果:
BacklightImg;//窗体光泽PNG图片 可自己定义QQ所有窗口效果基本上可以从这里设置
BacklightLTRB;//窗体光泽重绘边界 一般窗体都要可随意大小化,这时参数可以设置 光泽PNG图,不会随着窗体的大小而变形
FormSystemBtnSet;//窗口系统按钮设定
SystemAll //显示全部
SystemNo//全部不显示
btn_close//只显示关闭按钮
btn_miniAndbtn_close//显示最小化与关闭按钮
btn_maxAndbtn_close //显示最大化与关闭按钮
IsResize;//是否允许改变窗口大小 (这个指限定鼠标拖动放大缩小窗口,完全限制请用FormBorderStyle属性)
RgnRadius;//设置窗口圆角的大小
好了,就写到这里,详细里可以参考源码。
以前做的控件窗口虽然效果有点类似QQ,但不完善,结构比较混乱,我的目标是做出一套完全通用的QQ控件库出来.
有什么错误或意见请回复我,我会予以改正,请大家多支持
哇,测试加发布,就到12点了,先睡了,改天有空再更新!