- 积分
- 40165
- 好友
- 记录
- 主题
- 帖子
- 听众
- 收听
|
导读部分
-------------------------------------------------------------------------------------------------------------
C#仿QQ皮肤-实现原理系列文章导航
http://www.sufeinet.com/forum.php?mod=viewthread&tid=2
1.导语
-------------------------------------------------------------------------------------------------------------
哎,这两个月项目有点紧把文章给荒废了,这周努力一把多出两篇吧!上次说到 把总体层次的说完了 http://www.sufeinet.com/forum.php?mod=viewthread&tid=319,接下来就应该细细的说说是怎么实现的了,今天的主要是分析一下基窗体FormBase与基用户控件FormBase1的实现
前面我说过了这个窗体是为了实现添加修改等弹出窗体而设计的最常用的窗体之一,他在继承过后有一个固定的大小,是为了方便排版,如果所有窗体的大小都 不动的话正好跟主窗体配合是合适的,这个我是设计在程序里的,给不会排版的朋友以方便,当然您也是可以自己修改的,也就是说不管你怎么处理,只要是用我的控件就算是不做任何处理,也不是很难看,呵呵。
因为我的每个窗体和控件可能都 会多多少少的用到不少Windows的API,特别是Windows消息这一块的,我把常用的放到了一下类里共享给大家吧,不过没有过多的注释,因为这些在网上都 有大家只要Google一下就OK了,哎,听说Google走了,那就Bing吧,呵呵
类文件
[C#] 纯文本查看 复制代码 using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Globalization;
namespace CRD.Common
{
public static class Win32
{
public const int MF_REMOVE = 0x1000;
public const int SC_RESTORE = 0xF120; //还原
public const int SC_MOVE = 0xF010; //移动
public const int SC_SIZE = 0xF000; //大小
public const int SC_MINIMIZE = 0xF020; //最小化
public const int SC_MAXIMIZE = 0xF030; //最大化
public const int SC_CLOSE = 0xF060; //关闭
public const int WM_SYSCOMMAND = 0x0112;
public const int WM_COMMAND = 0x0111;
public const int GW_HWNDFIRST = 0;
public const int GW_HWNDLAST = 1;
public const int GW_HWNDNEXT = 2;
public const int GW_HWNDPREV = 3;
public const int GW_OWNER = 4;
public const int GW_CHILD = 5;
public const int WM_NCCALCSIZE = 0x83;
public const int WM_WINDOWPOSCHANGING = 0x46;
public const int WM_PAINT = 0xF;
public const int WM_CREATE = 0x1;
public const int WM_NCCREATE = 0x81;
public const int WM_NCPAINT = 0x85;
public const int WM_PRINT = 0x317;
public const int WM_DESTROY = 0x2;
public const int WM_SHOWWINDOW = 0x18;
public const int WM_SHARED_MENU = 0x1E2;
public const int HC_ACTION = 0;
public const int WH_CALLWNDPROC = 4;
public const int GWL_WNDPROC = -4;
public const int WS_SYSMENU = 0x80000;
public const int WS_SIZEBOX = 0x40000;
public const int WS_MAXIMIZEBOX = 0x10000;
public const int WS_MINIMIZEBOX = 0x20000;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SetWindowLong(IntPtr hWnd, int Index, int Value);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetWindowLong(IntPtr hWnd, int Index);
[DllImport("user32")]
public static extern IntPtr GetSystemMenu(IntPtr hwnd, int flag);
[DllImport("user32")]
public static extern int TrackPopupMenu(int hMenu, int wFlags, int x, int y, int nReserved, IntPtr hwnd, int lprc);
[DllImport("user32")]
public static extern int SendMessage(IntPtr hwnd, int msg, int wp, int lp);
[DllImport("user32")]
public static extern int ReleaseCapture();
[DllImport("gdi32.dll")]
public static extern int CreateRoundRectRgn(int x1, int y1, int x2, int y2, int x3, int y3);
[DllImport("user32.dll")]
public static extern int SetWindowRgn(IntPtr hwnd, int hRgn, Boolean bRedraw);
public const int CS_DROPSHADOW = 0x20000;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SetClassLong(IntPtr hwnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetClassLong(IntPtr hwnd, int nIndex);
public struct MENUINFO
{
public int cbSize;
public uint fMask;
public int dwStyle;
public int cyMax;
public int hbrBack;
public int dwContextHelpID;
public int dwMenuData;
}
[DllImport("gdi32")]
public static extern int CreatePatternBrush(int hBitmap);
[DllImport("user32")]
public static extern int SetMenuInfo(IntPtr hMenu, ref MENUINFO mi);
[DllImport("user32.dll", EntryPoint = "ShowWindow", CharSet = CharSet.Auto)]
public static extern int ShowWindow(IntPtr hwnd, int nCmdShow);
[DllImport("kernel32.dll")]
public static extern bool SetProcessWorkingSetSize(IntPtr process, int minSize, int maxSize);
public const int GCW_ATOM = -32;
public const int GCL_CBCLSEXTRA = -20;
public const int GCL_CBWNDEXTRA = -18;
public const int GCL_HBRBACKGROUND = -10;
public const int GCL_HCURSOR = -12;
public const int GCL_HICON = -14;
public const int GCL_HMODULE = -16;
public const int GCL_MENUNAME = -8;
public const int GCL_STYLE = -26;
public const int GCL_WNDPROC = -24;
[DllImport("user32", EntryPoint = "GetClassLong")]
public static extern int GetClassLong(int hwnd, int nIndex);
[DllImport("user32", EntryPoint = "SetClassLong")]
public static extern int SetClassLong(int hwnd, int nIndex, int dwNewLong);
public const int WM_SETREDRAW = 0x000B;
public const int WM_USER = 0x400;
public const int EM_GETEVENTMASK = (WM_USER + 59);
public const int EM_SETEVENTMASK = (WM_USER + 69);
[DllImport("user32.dll")]
public extern static bool LockWindowUpdate(IntPtr hWndLock);
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetWindowDC(IntPtr handle);
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr ReleaseDC(IntPtr handle, IntPtr hDC);
[DllImport("Gdi32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr CreateCompatibleDC(IntPtr hdc);
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern int GetClassName(IntPtr hwnd, char[] className, int maxCount);
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetWindow(IntPtr hwnd, int uCmd);
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern bool IsWindowVisible(IntPtr hwnd);
[DllImport("user32", CharSet = CharSet.Auto)]
public static extern int GetClientRect(IntPtr hwnd, ref RECT lpRect);
[DllImport("user32", CharSet = CharSet.Auto)]
public static extern int GetClientRect(IntPtr hwnd, [In, Out] ref Rectangle rect);
[DllImport("user32", CharSet = CharSet.Auto)]
public static extern bool MoveWindow(IntPtr hwnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
[DllImport("user32", CharSet = CharSet.Auto)]
public static extern bool UpdateWindow(IntPtr hwnd);
[DllImport("user32", CharSet = CharSet.Auto)]
public static extern bool InvalidateRect(IntPtr hwnd, ref Rectangle rect, bool bErase);
[DllImport("user32", CharSet = CharSet.Auto)]
public static extern bool ValidateRect(IntPtr hwnd, ref Rectangle rect);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern bool GetWindowRect(IntPtr hWnd, [In, Out] ref Rectangle rect);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[StructLayout(LayoutKind.Sequential)]
public struct WINDOWPOS
{
public IntPtr hwnd;
public IntPtr hwndAfter;
public int x;
public int y;
public int cx;
public int cy;
public uint flags;
}
[StructLayout(LayoutKind.Sequential)]
public struct NCCALCSIZE_PARAMS
{
public RECT rgc;
public WINDOWPOS wndpos;
}
[StructLayout(LayoutKind.Sequential)]
public struct tagSCROLLINFO
{
public uint cbSize;
public uint fMask;
public int nMin;
public int nMax;
public uint nPage;
public int nPos;
public int nTrackPos;
}
public enum fnBar
{
SB_HORZ = 0,
SB_VERT = 1,
SB_CTL = 2
}
public enum fMask
{
SIF_ALL,
SIF_DISABLENOSCROLL = 0X0010,
SIF_PAGE = 0X0002,
SIF_POS = 0X0004,
SIF_RANGE = 0X0001,
SIF_TRACKPOS = 0X0008
}
public static int MakeLong(short lowPart, short highPart)
{
return (int)(((ushort)lowPart) | (uint)(highPart << 16));
}
public const int SB_THUMBTRACK = 5;
public const int WM_HSCROLL = 0x114;
public const int WM_VSCROLL = 0x115;
[DllImport("user32.dll", EntryPoint = "GetScrollInfo")]
public static extern bool GetScrollInfo(IntPtr hwnd, int fnBar, ref SCROLLINFO lpsi);
[DllImport("user32.dll", EntryPoint = "SetScrollInfo")]
public static extern int SetScrollInfo(IntPtr hwnd, int fnBar, [In] ref SCROLLINFO lpsi, bool fRedraw);
[DllImport("User32.dll", CharSet = CharSet.Auto, EntryPoint = "SendMessage")]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool PostMessage(IntPtr hWnd, uint Msg, long wParam, int lParam);
public struct SCROLLINFO
{
public uint cbSize;
public uint fMask;
public int nMin;
public int nMax;
public uint nPage;
public int nPos;
public int nTrackPos;
}
public enum ScrollInfoMask
{
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
}
public enum ScrollBarDirection
{
SB_HORZ = 0,
SB_VERT = 1,
SB_CTL = 2,
SB_BOTH = 3
}
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern bool GetClientRect(HandleRef hWnd, [In, Out] ref RECT rect);
[StructLayout(LayoutKind.Sequential)]
public class SYSTEMTIME
{
public short wYear;
public short wMonth;
public short wDayOfWeek;
public short wDay;
public short wHour;
public short wMinute;
public short wSecond;
public short wMilliseconds;
public override string ToString()
{
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)]
public class SYSTEMTIMEARRAY
{
public short wYear1;
public short wMonth1;
public short wDayOfWeek1;
public short wDay1;
public short wHour1;
public short wMinute1;
public short wSecond1;
public short wMilliseconds1;
public short wYear2;
public short wMonth2;
public short wDayOfWeek2;
public short wDay2;
public short wHour2;
public short wMinute2;
public short wSecond2;
public short wMilliseconds2;
}
}
}
这个类的使用方法其实很简单,大家看下下面的代码就明白了
[C#] 纯文本查看 复制代码 Win32.SetWindowLong(this.Handle, -16, Win32.WS_SYSMENU + Win32.WS_SIZEBOX + Win32.WS_MAXIMIZEBOX + Win32.WS_MINIMIZEBOX);
其实说白了就是一个实体类,呵呵Win32.WS_SYSMENU 这样就行了。
下面开始一步一步的来实现吧
第一步.先建一个名称为FormBase的窗体,这个过程相信没有人不会吧,我就不写了;
第二步.把窗体变为无边框并且设置其大小为580, 364,我把要修改的属性一一的罗列一下吧!!!
就只有这几个属性需要修改一下,别的都 是默认的就行了;
第三步.我们来处理一下我们要定义这样几个变量,是处理加载窗体是默认皮肤的
[C#] 纯文本查看 复制代码 //默认的肤色 这是一个枚举
private SkinColor _currentSkinColor = SkinColor.Default;
//设置窗体无边框
private FormBorderStyle _formBorderStyle = FormBorderStyle.None;
//得到一个值表示 是否重绘
private bool _isRedrawSuspended;
//当前应用的皮肤
public SkinColor CurrentSkinColor
{
get { return _currentSkinColor; }
set { _currentSkinColor = value; }
}
第一行是取得系统默认的皮肤;
第二行是设置窗体无边框的这个咱们已经用属性设置过了, 我是不放心才写了一下,呵呵大家可以只写代码的;
第三行是定义一个变量指示是否要重绘;
第四行的是定义当前皮肤属性,方便取和设置;
第四步,FormBorderStyle和FormBorderStyle这个两属性我们需要定义一下
因为我们的窗体是无边框的所以FormBorderStyle这个属性我们也不希望能被使用都随时改变,可能为影响美难,所以我在这里禁止使用,也 就是说不让它出现在
属性窗体中,这个是怎么设置的呢,其实Ms做的很文件,只要一行代码就可以了
[C#] 纯文本查看 复制代码 //指定方法或是属性是否可以在编辑器中查看Never始终不能,Always始终是可以的,Advanced只有高级用户才能查看
[EditorBrowsable(EditorBrowsableState.Never)]
public new FormBorderStyle FormBorderStyle
{
get { return base.FormBorderStyle; }
set { base.FormBorderStyle = value; }
}
有了这几行代码我们不管怎么样改变窗体他都会是无标题的了,那我们怎么设置样式呢,别急看下面的代码
[C#] 纯文本查看 复制代码 //指定事件或是属性是否显示在属性窗口中
//[Browsable(false)]
//指定事件或是属性是否显示在属性窗口中
[Browsable(true)]
public FormBorderStyle FormStyle
{
get { return _formBorderStyle; }
set { _formBorderStyle = value; }
}
有个这个属性我们不就能设置了吗?
好现在窗体的样式 基本上实现了
还有两个地方也要改一下不过是常用的大家看下代码吧
[C#] 纯文本查看 复制代码 //得到一个值表示 是否重绘
public bool IsRedrawSuspended
{
get { return _isRedrawSuspended; }
}
//构造函数
public FormBase()
{
this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
InitializeComponent();
}
第五步,重写OnLoad事件和OnResize事件
为什么要重写呢,OnResize事件重写的目的是留出边框的大小,而OnLoad的重写是为了应用皮肤我处理一下消息
我都 写在了代码里下面是这个事件的代码[C#] 纯文本查看 复制代码 //重写的OnLoad事件
protected override void OnLoad(EventArgs e)
{
Win32.SetWindowLong(this.Handle, -16, Win32.WS_SYSMENU + Win32.WS_SIZEBOX + Win32.WS_MAXIMIZEBOX + Win32.WS_MINIMIZEBOX);
int Rgn = 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事件
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
int Rgn = Win32.CreateRoundRectRgn(3, 3, this.Width - 2, this.Height - 2, 7, 7);
Win32.SetWindowRgn(this.Handle, Rgn, true);
}
第六步,设置窗体的图片
方法很简单,直接 看代码应该理我容易理解
[C#] 纯文本查看 复制代码 //设置用户控件的图片
public void PerformReSetFormBitmap()
{
try
{
this.SuspendRedraw();
ReSetFormBitmap();
}
catch
{
throw;
}
finally
{
this.ResumeRedraw();
}
}
public virtual void ReSetFormBitmap()
{
}
第七步,设置窗体背景
跟上面的实现 方法是一样的
[C#] 纯文本查看 复制代码 //设置用户控件背景
public void PerformChangeBackgroundStripe(BackgroundStripe backgroundStripe)
{
try
{
ChangeBackgroundStripe(backgroundStripe);
}
catch
{
throw;
}
finally
{
this.ResumeRedraw();
}
}
public virtual void ChangeBackgroundStripe(BackgroundStripe backgroundStripe)
{
this.CurrentSkinColor = Shared.CurrentSkinColor;
}
第七八步,设置的默认皮肤
跟上面的实现 方法是一样的,这三个实现方法是一样的,在这里不在多解释了
[C#] 纯文本查看 复制代码 #region //设置皮肤色ChangeSkinColor
public void PerformChangeSkinColor()
{
PerformChangeSkinColor(SkinColor.Undefault);
}
//设置皮肤色
public void PerformChangeSkinColor(SkinColor skinColor)
{
try
{
this.SuspendRedraw();
ChangeSkinColor(skinColor);
}
catch
{
throw;
}
finally
{
this.ResumeRedraw();
}
}
最后一步,就是当修改皮肤是我们要做什么了
其实也不是很难的,只要调用一些方法就可以,大家如果 想知道 每个方法的意思 的话,可以自己转到定义去看, 当然在说到皮肤控件是我会一一说明 的
实现 代码
[C#] 纯文本查看 复制代码 //修改皮肤色时
public virtual void ChangeSkinColor(SkinColor skinColor)
{
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这个窗体的实现 也就是常用的添加,删除的小窗体,先看看效果吧!!!
效果就是这样的,
下面是这个窗体实现的所有代码
[C#] 纯文本查看 复制代码 using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using CRD.Common;
namespace CRD.WinUI.Forms
{
/// <summary>
/// 常用的窗体之一,用于添加修改等弹出窗体
/// </summary>
public partial class FormBase : Form
{
//默认的肤色 这是一个枚举
private SkinColor _currentSkinColor = SkinColor.Default;
//设置窗体无边框
private FormBorderStyle _formBorderStyle = FormBorderStyle.None;
//得到一个值表示 是否重绘
private bool _isRedrawSuspended;
//当前应用的皮肤
public SkinColor CurrentSkinColor
{
get { return _currentSkinColor; }
set { _currentSkinColor = value; }
}
//指定方法或是属性是否可以在编辑器中查看Never始终不能,Always始终是可以的,Advanced只有高级用户才能查看
[EditorBrowsable(EditorBrowsableState.Never)]
public new FormBorderStyle FormBorderStyle
{
get { return base.FormBorderStyle; }
set { base.FormBorderStyle = value; }
}
//指定事件或是属性是否显示在属性窗口中
//[Browsable(false)]
//指定事件或是属性是否显示在属性窗口中
[Browsable(true)]
public FormBorderStyle FormStyle
{
get { return _formBorderStyle; }
set { _formBorderStyle = value; }
}
//得到一个值表示 是否重绘
public bool IsRedrawSuspended
{
get { return _isRedrawSuspended; }
}
//构造函数
public FormBase()
{
this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
InitializeComponent();
}
//重写的OnLoad事件
protected override void OnLoad(EventArgs e)
{
Win32.SetWindowLong(this.Handle, -16, Win32.WS_SYSMENU + Win32.WS_SIZEBOX + Win32.WS_MAXIMIZEBOX + Win32.WS_MINIMIZEBOX);
int Rgn = 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事件
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
int Rgn = Win32.CreateRoundRectRgn(3, 3, this.Width - 2, this.Height - 2, 7, 7);
Win32.SetWindowRgn(this.Handle, Rgn, true);
}
#region //设置用户控件的图片ReSetFormBitmap
//设置用户控件的图片
public void PerformReSetFormBitmap()
{
try
{
this.SuspendRedraw();
ReSetFormBitmap();
}
catch
{
throw;
}
finally
{
this.ResumeRedraw();
}
}
public virtual void ReSetFormBitmap()
{
}
#endregion
#region //设置用户控件背景ChangeBackgroundStripe
//设置用户控件背景
public void PerformChangeBackgroundStripe(BackgroundStripe backgroundStripe)
{
try
{
ChangeBackgroundStripe(backgroundStripe);
}
catch
{
throw;
}
finally
{
this.ResumeRedraw();
}
}
public virtual void ChangeBackgroundStripe(BackgroundStripe backgroundStripe)
{
this.CurrentSkinColor = Shared.CurrentSkinColor;
}
#endregion
#region //设置皮肤色ChangeSkinColor
public void PerformChangeSkinColor()
{
PerformChangeSkinColor(SkinColor.Undefault);
}
//设置皮肤色
public void PerformChangeSkinColor(SkinColor skinColor)
{
try
{
this.SuspendRedraw();
ChangeSkinColor(skinColor);
}
catch
{
throw;
}
finally
{
this.ResumeRedraw();
}
}
//修改皮肤色时
public virtual void ChangeSkinColor(SkinColor skinColor)
{
if (this.CurrentSkinColor != skinColor)
{
this.ReSetFormBitmap();
if (skinColor != SkinColor.Undefault)
{
Shared.ChangeSkinColor(skinColor, this);
}
}
else
{
this.ReSetFormBitmap();
Shared.ChangeControlsSkinColor(this);
}
this.CurrentSkinColor = Shared.CurrentSkinColor;
}
#endregion
#region Suspend / Resume Controls Painting
public void SuspendRedraw()
{
_isRedrawSuspended = true;
SuspendRedraw(this);
}
public void SuspendRedraw(Control control)
{
if (DesignMode) return;
}
public void ResumeRedraw()
{
_isRedrawSuspended = false;
ResumeRedraw(this);
}
public void ResumeRedraw(Control control)
{
if (DesignMode) return;
}
public void LockWindowUpdate(bool lockUpdate)
{
Shared.LockWindowUpdate(this, lockUpdate);
}
#endregion
}
}
|
|