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 里面都有备份,以后有更新也会传上去,在这里跟大家说一下!
网站:http://www.8timer.com
出处:http://www.cnblogs.com/Along729/
关于作者:专注于项目架构、WINFORM开发、WEB开发。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,在文章页面位置给出原文连接,如有问题,可以通过bpd729@163.com 联系我,非常感谢。