C# 高仿腾讯QQ (窗口皮肤美化)(附测试源码)

  首写这篇文章之前先跟大家说声抱歉,我很少写这方面的文章,所以一直不敢动手,之前的文章确实不带源的,因为当时只是想做为自己初次开发的记录过程,打算程序开发完后再来贴源的。不过从现在开始,我觉定还是把自己每次写的控件实例写出来,和大家一起探讨研究,这样也可增加自己学习经验。

  在这里先跟大家说一下,由于我也是菜鸟型人物,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点了,先睡了,改天有空再更新!如果大家有兴趣请加群 57218890

 

源码下载

 

 Sorry ,发现网站的服务器出了问题上,空间里面的数据全没了,链过来的文件已全失效,请等待恢复。如果大家愿意,请进

QQ群 57218890 里面都有备份,以后有更新也会传上去,在这里跟大家说一下!

转载于:https://www.cnblogs.com/Along729/archive/2010/12/05/Along.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值