C#仿QQ皮肤----基窗体FormBase与基用户控件FormBase1的实现
博客园原文章 C#仿QQ皮肤----基窗体FormBase与基用户控件FormBase1的实现
C#仿QQ皮肤-实现原理系列文章导航
http://www.cnblogs.com/sufei/archive/2010/03/10/1682847.html
哎,这两个项目有点紧把文章给荒废了,这周努力一把多出两篇吧!
上次说到把总体层次的说完了 http://www.cnblogs.com/sufei/archive/2010/03/20/1690624.html ,接下来就应该细细的说说是怎么实现的了,今天的主要是分析一下基窗体FormBase与基用户控件FormBase1的实现
前面我说过了这个窗体是为了实现添加修改等弹出窗体而设计的最常用的窗体之一,他在继承过后有一个固定的大小,是为了方便排版,如果所有窗体的大小都 不动的话正好跟主窗体配合是合适的,这个我是设计在程序里的,给不会排版的朋友以方便,当然您也是可以自己修改的,也就是说不管你怎么处理,只要是用我的控件就算是不做任何处理,也不是很难看,呵呵。
因为我的每个窗体和控件可能都 会多多少少的用到不少Windows的API,特别是Windows消息这一块的,我把常用的放到了一下类里共享给大家吧,不过没有过多的注释,因为这些在网上都 有大家只要Google一下就OK了,哎,听说Google走了,那就Bing吧,呵呵
类文件
usingSystem.Collections.Generic;
usingSystem.Text;
usingSystem.Runtime.InteropServices;
usingSystem.Drawing;
usingSystem.Globalization;
namespaceCRD.Common
{
publicstaticclassWin32
{
publicconstintMF_REMOVE=0x1000;
publicconstintSC_RESTORE=0xF120;//还原
publicconstintSC_MOVE=0xF010;//移动
publicconstintSC_SIZE=0xF000;//大小
publicconstintSC_MINIMIZE=0xF020;//最小化
publicconstintSC_MAXIMIZE=0xF030;//最大化
publicconstintSC_CLOSE=0xF060;//关闭
publicconstintWM_SYSCOMMAND=0x0112;
publicconstintWM_COMMAND=0x0111;
publicconstintGW_HWNDFIRST=0;
publicconstintGW_HWNDLAST=1;
publicconstintGW_HWNDNEXT=2;
publicconstintGW_HWNDPREV=3;
publicconstintGW_OWNER=4;
publicconstintGW_CHILD=5;
publicconstintWM_NCCALCSIZE=0x83;
publicconstintWM_WINDOWPOSCHANGING=0x46;
publicconstintWM_PAINT=0xF;
publicconstintWM_CREATE=0x1;
publicconstintWM_NCCREATE=0x81;
publicconstintWM_NCPAINT=0x85;
publicconstintWM_PRINT=0x317;
publicconstintWM_DESTROY=0x2;
publicconstintWM_SHOWWINDOW=0x18;
publicconstintWM_SHARED_MENU=0x1E2;
publicconstintHC_ACTION=0;
publicconstintWH_CALLWNDPROC=4;
publicconstintGWL_WNDPROC=-4;
publicconstintWS_SYSMENU=0x80000;
publicconstintWS_SIZEBOX=0x40000;
publicconstintWS_MAXIMIZEBOX=0x10000;
publicconstintWS_MINIMIZEBOX=0x20000;
[DllImport("user32.dll",CharSet=CharSet.Auto)]
publicstaticexternintSetWindowLong(IntPtrhWnd,intIndex,intValue);
[DllImport("user32.dll",CharSet=CharSet.Auto)]
publicstaticexternintGetWindowLong(IntPtrhWnd,intIndex);
[DllImport("user32")]
publicstaticexternIntPtrGetSystemMenu(IntPtrhwnd,intflag);
[DllImport("user32")]
publicstaticexternintTrackPopupMenu(inthMenu,intwFlags,intx,inty,intnReserved,IntPtrhwnd,intlprc);
[DllImport("user32")]
publicstaticexternintSendMessage(IntPtrhwnd,intmsg,intwp,intlp);
[DllImport("user32")]
publicstaticexternintReleaseCapture();
[DllImport("gdi32.dll")]
publicstaticexternintCreateRoundRectRgn(intx1,inty1,intx2,inty2,intx3,inty3);
[DllImport("user32.dll")]
publicstaticexternintSetWindowRgn(IntPtrhwnd,inthRgn,BooleanbRedraw);
publicconstintCS_DROPSHADOW=0x20000;
[DllImport("user32.dll",CharSet=CharSet.Auto)]
publicstaticexternintSetClassLong(IntPtrhwnd,intnIndex,intdwNewLong);
[DllImport("user32.dll",CharSet=CharSet.Auto)]
publicstaticexternintGetClassLong(IntPtrhwnd,intnIndex);
publicstructMENUINFO
{
publicintcbSize;
publicuintfMask;
publicintdwStyle;
publicintcyMax;
publicinthbrBack;
publicintdwContextHelpID;
publicintdwMenuData;
}
[DllImport("gdi32")]
publicstaticexternintCreatePatternBrush(inthBitmap);
[DllImport("user32")]
publicstaticexternintSetMenuInfo(IntPtrhMenu,refMENUINFOmi);
[DllImport("user32.dll",EntryPoint="ShowWindow",CharSet=CharSet.Auto)]
publicstaticexternintShowWindow(IntPtrhwnd,intnCmdShow);
[DllImport("kernel32.dll")]
publicstaticexternboolSetProcessWorkingSetSize(IntPtrprocess,intminSize,intmaxSize);
publicconstintGCW_ATOM=-32;
publicconstintGCL_CBCLSEXTRA=-20;
publicconstintGCL_CBWNDEXTRA=-18;
publicconstintGCL_HBRBACKGROUND=-10;
publicconstintGCL_HCURSOR=-12;
publicconstintGCL_HICON=-14;
publicconstintGCL_HMODULE=-16;
publicconstintGCL_MENUNAME=-8;
publicconstintGCL_STYLE=-26;
publicconstintGCL_WNDPROC=-24;
[DllImport("user32",EntryPoint="GetClassLong")]
publicstaticexternintGetClassLong(inthwnd,intnIndex);
[DllImport("user32",EntryPoint="SetClassLong")]
publicstaticexternintSetClassLong(inthwnd,intnIndex,intdwNewLong);
publicconstintWM_SETREDRAW=0x000B;
publicconstintWM_USER=0x400;
publicconstintEM_GETEVENTMASK=(WM_USER+59);
publicconstintEM_SETEVENTMASK=(WM_USER+69);
[DllImport("user32.dll")]
publicexternstaticboolLockWindowUpdate(IntPtrhWndLock);
[DllImport("User32.dll",CharSet=CharSet.Auto)]
publicstaticexternIntPtrGetWindowDC(IntPtrhandle);
[DllImport("User32.dll",CharSet=CharSet.Auto)]
publicstaticexternIntPtrReleaseDC(IntPtrhandle,IntPtrhDC);
[DllImport("Gdi32.dll",CharSet=CharSet.Auto)]
publicstaticexternIntPtrCreateCompatibleDC(IntPtrhdc);
[DllImport("User32.dll",CharSet=CharSet.Auto)]
publicstaticexternintGetClassName(IntPtrhwnd,char[]className,intmaxCount);
[DllImport("User32.dll",CharSet=CharSet.Auto)]
publicstaticexternIntPtrGetWindow(IntPtrhwnd,intuCmd);
[DllImport("User32.dll",CharSet=CharSet.Auto)]
publicstaticexternboolIsWindowVisible(IntPtrhwnd);
[DllImport("user32",CharSet=CharSet.Auto)]
publicstaticexternintGetClientRect(IntPtrhwnd,refRECTlpRect);
[DllImport("user32",CharSet=CharSet.Auto)]
publicstaticexternintGetClientRect(IntPtrhwnd,[In,Out]refRectanglerect);
[DllImport("user32",CharSet=CharSet.Auto)]
publicstaticexternboolMoveWindow(IntPtrhwnd,intX,intY,intnWidth,intnHeight,boolbRepaint);
[DllImport("user32",CharSet=CharSet.Auto)]
publicstaticexternboolUpdateWindow(IntPtrhwnd);
[DllImport("user32",CharSet=CharSet.Auto)]
publicstaticexternboolInvalidateRect(IntPtrhwnd,refRectanglerect,boolbErase);
[DllImport("user32",CharSet=CharSet.Auto)]
publicstaticexternboolValidateRect(IntPtrhwnd,refRectanglerect);
[DllImport("user32.dll",CharSet=CharSet.Auto)]
publicstaticexternboolGetWindowRect(IntPtrhWnd,[In,Out]refRectanglerect);
[StructLayout(LayoutKind.Sequential)]
publicstructRECT
{
publicintLeft;
publicintTop;
publicintRight;
publicintBottom;
}
[StructLayout(LayoutKind.Sequential)]
publicstructWINDOWPOS
{
publicIntPtrhwnd;
publicIntPtrhwndAfter;
publicintx;
publicinty;
publicintcx;
publicintcy;
publicuintflags;
}
[StructLayout(LayoutKind.Sequential)]
publicstructNCCALCSIZE_PARAMS
{
publicRECTrgc;
publicWINDOWPOSwndpos;
}
[StructLayout(LayoutKind.Sequential)]
publicstructtagSCROLLINFO
{
publicuintcbSize;
publicuintfMask;
publicintnMin;
publicintnMax;
publicuintnPage;
publicintnPos;
publicintnTrackPos;
}
publicenumfnBar
{
SB_HORZ=0,
SB_VERT=1,
SB_CTL=2
}
publicenumfMask
{
SIF_ALL,
SIF_DISABLENOSCROLL=0X0010,
SIF_PAGE=0X0002,
SIF_POS=0X0004,
SIF_RANGE=0X0001,
SIF_TRACKPOS=0X0008
}
publicstaticintMakeLong(shortlowPart,shorthighPart)
{
return(int)(((ushort)lowPart)|(uint)(highPart<<16));
}
publicconstintSB_THUMBTRACK=5;
publicconstintWM_HSCROLL=0x114;
publicconstintWM_VSCROLL=0x115;
[DllImport("user32.dll",EntryPoint="GetScrollInfo")]
publicstaticexternboolGetScrollInfo(IntPtrhwnd,intfnBar,refSCROLLINFOlpsi);
[DllImport("user32.dll",EntryPoint="SetScrollInfo")]
publicstaticexternintSetScrollInfo(IntPtrhwnd,intfnBar,[In]refSCROLLINFOlpsi,boolfRedraw);
[DllImport("User32.dll",CharSet=CharSet.Auto,EntryPoint="SendMessage")]
staticexternIntPtrSendMessage(IntPtrhWnd,uintMsg,IntPtrwParam,IntPtrlParam);
[DllImport("user32.dll",SetLastError=true)]
publicstaticexternboolPostMessage(IntPtrhWnd,uintMsg,longwParam,intlParam);
publicstructSCROLLINFO
{
publicuintcbSize;
publicuintfMask;
publicintnMin;
publicintnMax;
publicuintnPage;
publicintnPos;
publicintnTrackPos;
}
publicenumScrollInfoMask
{
SIF_RANGE=0x1,
SIF_PAGE=0x2,
SIF_POS=0x4,
SIF_DISABLENOSCROLL=0x8,
SIF_TRACKPOS=0x10,
SIF_ALL=SIF_RANGE+SIF_PAGE+SIF_POS+SIF_TRACKPOS
}
publicenumScrollBarDirection
{
SB_HORZ=0,
SB_VERT=1,
SB_CTL=2,
SB_BOTH=3
}
[DllImport("user32.dll",CharSet=CharSet.Auto,ExactSpelling=true)]
publicstaticexternboolGetClientRect(HandleRefhWnd,[In,Out]refRECTrect);
[StructLayout(LayoutKind.Sequential)]
publicclassSYSTEMTIME
{
publicshortwYear;
publicshortwMonth;
publicshortwDayOfWeek;
publicshortwDay;
publicshortwHour;
publicshortwMinute;
publicshortwSecond;
publicshortwMilliseconds;
publicoverridestringToString()
{
return("[SYSTEMTIME:"+this.wDay.ToString(CultureInfo.InvariantCulture)+"/"+this.wMonth.ToString(CultureInfo.InvariantCulture)+"/"+this.wYear.ToString(CultureInfo.InvariantCulture)+""+this.wHour.ToString(CultureInfo.InvariantCulture)+":"+this.wMinute.ToString(CultureInfo.InvariantCulture)+":"+this.wSecond.ToString(CultureInfo.InvariantCulture)+"]");
}
}
[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Auto)]
publicclassSYSTEMTIMEARRAY
{
publicshortwYear1;
publicshortwMonth1;
publicshortwDayOfWeek1;
publicshortwDay1;
publicshortwHour1;
publicshortwMinute1;
publicshortwSecond1;
publicshortwMilliseconds1;
publicshortwYear2;
publicshortwMonth2;
publicshortwDayOfWeek2;
publicshortwDay2;
publicshortwHour2;
publicshortwMinute2;
publicshortwSecond2;
publicshortwMilliseconds2;
}
}
}
这个类的使用方法其实很简单,大家看下下面的代码就明白了
其实说白了就是一个实体类,呵呵Win32.WS_SYSMENU这样就行了。
下面开始一步一步的来实现吧
第一步.先建一个名称为FormBase的窗体,这个过程相信没有人不会吧,我就不写了;
第二步.把窗体变为无边框并且设置其大小为580, 364,我把要修改的属性一一的罗列一下吧!!!
就只有这几个属性需要修改一下,别的都 是默认的就行了;
第三步.我们来处理一下我们要定义这样几个变量,是处理加载窗体是默认皮肤的
privateSkinColor_currentSkinColor=SkinColor.Default;
//设置窗体无边框
privateFormBorderStyle_formBorderStyle=FormBorderStyle.None;
//得到一个值表示是否重绘
privatebool_isRedrawSuspended;
//当前应用的皮肤
publicSkinColorCurrentSkinColor
{
get{return_currentSkinColor;}
set{_currentSkinColor=value;}
}
第一行是取得系统默认的皮肤;
第二行是设置窗体无边框的这个咱们已经用属性设置过了, 我是不放心才写了一下,呵呵大家可以只写代码的;
第三行是定义一个变量指示是否要重绘;
第四行的是定义当前皮肤属性,方便取和设置;
第四步,FormBorderStyle和FormBorderStyle这个两属性我们需要定义一下
因为我们的窗体是无边框的所以FormBorderStyle这个属性我们也不希望能被使用都随时改变,可能为影响美难,所以我在这里禁止使用,也 就是说不让它出现在
属性窗体中,这个是怎么设置的呢,其实Ms做的很文件,只要一行代码就可以了
[EditorBrowsable(EditorBrowsableState.Never)]
publicnewFormBorderStyleFormBorderStyle
{
get{returnbase.FormBorderStyle;}
set{base.FormBorderStyle=value;}
}
有了这几行代码我们不管怎么样改变窗体他都会是无标题的了,那我们怎么设置样式呢,别急看下面的代码
//[Browsable(false)]
//指定事件或是属性是否显示在属性窗口中
[Browsable(true)]
publicFormBorderStyleFormStyle
{
get{return_formBorderStyle;}
set{_formBorderStyle=value;}
}
有个这个属性我们不就能设置了吗?
好现在窗体的样式 基本上实现了
还有两个地方也要改一下不过是常用的大家看下代码吧
,重写OnLoad事件和OnResize事件
publicboolIsRedrawSuspended
{
get{return_isRedrawSuspended;}
}
//构造函数
publicFormBase()
{
this.SetStyle(ControlStyles.DoubleBuffer|ControlStyles.AllPaintingInWmPaint,true);
InitializeComponent();
}
第五步
为什么要重写呢,OnResize事件重写的目的是留出边框的大小,而OnLoad的重写是为了应用皮肤我处理一下消息
我都 写在了代码里下面是这个事件的代码
protectedoverridevoidOnLoad(EventArgse)
{
Win32.SetWindowLong(this.Handle,-16,Win32.WS_SYSMENU+Win32.WS_SIZEBOX+Win32.WS_MAXIMIZEBOX+Win32.WS_MINIMIZEBOX);
intRgn=Win32.CreateRoundRectRgn(3,3,this.Width-2,this.Height-2,7,7);
Win32.SetWindowRgn(this.Handle,Rgn,true);
this.PerformReSetFormBitmap();
base.OnLoad(e);
if(this!=Shared.MainForm&&this.CurrentSkinColor!=Shared.CurrentSkinColor)
{
Shared.ChangeSkinColor(Shared.CurrentSkinColor,this,true);
}
}
//重写的OnResize事件
protectedoverridevoidOnResize(EventArgse)
{
base.OnResize(e);
intRgn=Win32.CreateRoundRectRgn(3,3,this.Width-2,this.Height-2,7,7);
Win32.SetWindowRgn(this.Handle,Rgn,true);
}
第六步,设置窗体的图片
方法很简单,直接 看代码应该理我容易理解
publicvoidPerformReSetFormBitmap()
{
try
{
this.SuspendRedraw();
ReSetFormBitmap();
}
catch
{
throw;
}
finally
{
this.ResumeRedraw();
}
}
publicvirtualvoidReSetFormBitmap()
{
}
第七步,设置窗体背景
跟上面的实现 方法是一样的
publicvoidPerformChangeBackgroundStripe(BackgroundStripebackgroundStripe)
{
try
{
ChangeBackgroundStripe(backgroundStripe);
}
catch
{
throw;
}
finally
{
this.ResumeRedraw();
}
}
publicvirtualvoidChangeBackgroundStripe(BackgroundStripebackgroundStripe)
{
this.CurrentSkinColor=Shared.CurrentSkinColor;
}
第七八步,设置的默认皮肤
跟上面的实现 方法是一样的,这三个实现方法是一样的,在这里不在多解释了
publicvoidPerformChangeSkinColor()
{
PerformChangeSkinColor(SkinColor.Undefault);
}
//设置皮肤色
publicvoidPerformChangeSkinColor(SkinColorskinColor)
{
try
{
this.SuspendRedraw();
ChangeSkinColor(skinColor);
}
catch
{
throw;
}
finally
{
this.ResumeRedraw();
}
}
最后一步,就是当修改皮肤是我们要做什么了
其实也不是很难的,只要调用一些方法就可以,大家如果 想知道 每个方法的意思 的话,可以自己转到定义去看, 当然在说到皮肤控件是我会一一说明 的
实现 代码
publicvirtualvoidChangeSkinColor(SkinColorskinColor)
{
if(this.CurrentSkinColor!=skinColor)
{
this.ReSetFormBitmap();
if(skinColor!=SkinColor.Undefault)
{
Shared.ChangeSkinColor(skinColor,this);
}
}
else
{
this.ReSetFormBitmap();
Shared.ChangeControlsSkinColor(this);
}
this.CurrentSkinColor=Shared.CurrentSkinColor;
}
这个实体基本上就是这样实现 的,FormBase跟窗体的实现 是一样的,只是在新建的时候创建的是用户控件,实现 的方法没有二样,
有了这个窗体就为了们实现FunctionFormBase这个窗体打下了基础,下一次的文章我会接着说FunctionFormBase这个窗体的实现 也就是常用的添加,删除的小窗体,先看看效果吧!!!
效果就是这样的,
下面是这个窗体实现的所有代码
usingSystem.Collections.Generic;
usingSystem.ComponentModel;
usingSystem.Data;
usingSystem.Drawing;
usingSystem.Text;
usingSystem.Windows.Forms;
usingSystem.IO;
usingCRD.Common;
namespaceCRD.WinUI.Forms
{
///<summary>
///常用的窗体之一,用于添加修改等弹出窗体
///</summary>
publicpartialclassFormBase:Form
{
//默认的肤色这是一个枚举
privateSkinColor_currentSkinColor=SkinColor.Default;
//设置窗体无边框
privateFormBorderStyle_formBorderStyle=FormBorderStyle.None;
//得到一个值表示是否重绘
privatebool_isRedrawSuspended;
//当前应用的皮肤
publicSkinColorCurrentSkinColor
{
get{return_currentSkinColor;}
set{_currentSkinColor=value;}
}
//指定方法或是属性是否可以在编辑器中查看Never始终不能,Always始终是可以的,Advanced只有高级用户才能查看
[EditorBrowsable(EditorBrowsableState.Never)]
publicnewFormBorderStyleFormBorderStyle
{
get{returnbase.FormBorderStyle;}
set{base.FormBorderStyle=value;}
}
//指定事件或是属性是否显示在属性窗口中
//[Browsable(false)]
//指定事件或是属性是否显示在属性窗口中
[Browsable(true)]
publicFormBorderStyleFormStyle
{
get{return_formBorderStyle;}
set{_formBorderStyle=value;}
}
//得到一个值表示是否重绘
publicboolIsRedrawSuspended
{
get{return_isRedrawSuspended;}
}
//构造函数
publicFormBase()
{
this.SetStyle(ControlStyles.DoubleBuffer|ControlStyles.AllPaintingInWmPaint,true);
InitializeComponent();
}
//重写的OnLoad事件
protectedoverridevoidOnLoad(EventArgse)
{
Win32.SetWindowLong(this.Handle,-16,Win32.WS_SYSMENU+Win32.WS_SIZEBOX+Win32.WS_MAXIMIZEBOX+Win32.WS_MINIMIZEBOX);
intRgn=Win32.CreateRoundRectRgn(3,3,this.Width-2,this.Height-2,7,7);
Win32.SetWindowRgn(this.Handle,Rgn,true);
this.PerformReSetFormBitmap();
base.OnLoad(e);
if(this!=Shared.MainForm&&this.CurrentSkinColor!=Shared.CurrentSkinColor)
{
Shared.ChangeSkinColor(Shared.CurrentSkinColor,this,true);
}
}
//重写的OnResize事件
protectedoverridevoidOnResize(EventArgse)
{
base.OnResize(e);
intRgn=Win32.CreateRoundRectRgn(3,3,this.Width-2,this.Height-2,7,7);
Win32.SetWindowRgn(this.Handle,Rgn,true);
}
#region//设置用户控件的图片ReSetFormBitmap
//设置用户控件的图片
publicvoidPerformReSetFormBitmap()
{
try
{
this.SuspendRedraw();
ReSetFormBitmap();
}
catch
{
throw;
}
finally
{
this.ResumeRedraw();
}
}
publicvirtualvoidReSetFormBitmap()
{
}
#endregion
#region//设置用户控件背景ChangeBackgroundStripe
//设置用户控件背景
publicvoidPerformChangeBackgroundStripe(BackgroundStripebackgroundStripe)
{
try
{
ChangeBackgroundStripe(backgroundStripe);
}
catch
{
throw;
}
finally
{
this.ResumeRedraw();
}
&n