C#仿QQ皮肤-实现原理系列文章导航
http://www.cnblogs.com/sufei/archive/2010/03/10/1682847.html
大家还是先来看看效果吧
这次之所以一次写两个控件,其实主要是因为Label控件实在是太简单了没有必要放放一个文章里写,所以就一次性来了。
Label控件我就不再多说了,我直接把代码贴一下吧因为就几行代码,相信大家一眼就能看明白了。
using System.Collections.Generic;
using System.Text;
namespace CRD.WinUI.Misc
{
public class Label:System.Windows.Forms.Label
{
public Label()
: base ()
{
this .BackColor = System.Drawing.Color.Transparent;
}
}
}
ListBox实现
咱们从第一行代码就要吧看出来是继承自系统控件而来的。
所以本身就具备了系统的ListBox的一些特性。老方法我们先来看看WndProc方法的实现
{
IntPtr hDC = IntPtr.Zero;
Graphics gdc = null ;
switch (m.Msg)
{
case 133 :
hDC = Win32.GetWindowDC(m.HWnd);
gdc = Graphics.FromHdc(hDC);
Win32.SendMessage( this .Handle, WM_ERASEBKGND, hDC.ToInt32(), 0 );
SendPrintClientMsg();
Win32.SendMessage( this .Handle, WM_PAINT, 0 , 0 );
OverrideControlBorder(gdc);
m.Result = (IntPtr) 1 ;
Win32.ReleaseDC(m.HWnd, hDC);
gdc.Dispose();
break ;
case WM_PAINT:
base .WndProc( ref m);
hDC = Win32.GetWindowDC(m.HWnd);
gdc = Graphics.FromHdc(hDC);
OverrideControlBorder(gdc);
Win32.ReleaseDC(m.HWnd, hDC);
gdc.Dispose();
break ;
default :
base .WndProc( ref m);
break ;
}
}
这边的实现方法基本上和之前的控件一个样,所以我就不再多说原理了,大家随便看一下前几次的文章就明白了。
下面我们来看一下怎么样换皮肤的事件
也就是说在换皮肤的时候我们应该做那些工作
{
Graphics g = e.Graphics;
// 绘制区域
Rectangle r = e.Bounds;
Font fn = null ;
if (e.Index >= 0 )
{
if (e.State == DrawItemState.None)
{
// 设置字体、字符串格式、对齐方式
fn = e.Font;
string s = ( string ) this .Items[e.Index];
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Near;
// 根据不同的状态用不同的颜色表示
if (e.State == (DrawItemState.NoAccelerator | DrawItemState.NoFocusRect))
{
e.Graphics.FillRectangle( new SolidBrush(Color.Red), r);
e.Graphics.DrawString(s, fn, new SolidBrush(Color.Black), r, sf);
e.DrawFocusRectangle();
}
else
{
e.Graphics.FillRectangle( new SolidBrush(Color.White), r);
e.Graphics.DrawString(s, fn, new SolidBrush(Shared.FontColor), r, sf);
e.DrawFocusRectangle();
}
}
else
{
fn = e.Font;
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Near;
string s = ( string ) this .Items[e.Index];
e.Graphics.FillRectangle( new SolidBrush(Shared.ControlBackColor), r);
e.Graphics.DrawString(s, fn, new SolidBrush(Shared.FontColor), r, sf);
}
}
}
其实这些都不是今天要说的重点,这个控件的实现基础跟之前的一些控件基本上是一样的,像Textbox就和这个差不多,
唯一我想说的是滚动条的实现,不多说了下面开始吧
滚动条的实现
如上面的图片大家已经看到了,图片在我的源代码里都有,我在这里就不多说了,一起来看是怎么实现 的吧,先说说思路,
第一步,先制做一个自己的滚动条,随便做只要自己感觉漂亮就可以,第二步就是,利用Api把Listbox现有的滚动条用现在的滚动条代替,第三步,让现有的滚动条和系统的滚动条实现同步即可。
我实现滚动条的代码,大家也可以自己写这里只是一个参考吧
看一下效果
看一下代码吧,具体的素材大家到我源代码里面找吧,呵呵
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using System.Diagnostics;
namespace CRD.WinUI.Misc
{
[Designer( typeof (ScrollbarControlDesigner))]
public partial class CustomScrollbar : UserControl
{
protected Color moChannelColor = Color.Empty;
protected Image moUpArrowImage = null ; // 上箭头
// protected Image moUpArrowImage_Over = null;
// protected Image moUpArrowImage_Down = null;
protected Image moDownArrowImage = null ; // 下箭头
// protected Image moDownArrowImage_Over = null;
// protected Image moDownArrowImage_Down = null;
protected Image moThumbArrowImage = null ;
protected Image moThumbTopImage = null ;
protected Image moThumbTopSpanImage = null ;
protected Image moThumbBottomImage = null ;
protected Image moThumbBottomSpanImage = null ;
protected Image moThumbMiddleImage = null ;
protected int moLargeChange = 10 ;
protected int moSmallChange = 1 ;
protected int moMinimum = 0 ;
protected int moMaximum = 100 ;
protected int moValue = 0 ;
private int nClickPoint;
protected int moThumbTop = 0 ;
protected bool moAutoSize = false ;
private bool moThumbDown = false ;
private bool moThumbDragging = false ;
public new event EventHandler Scroll = null ;
public event EventHandler ValueChanged = null ;
private int GetThumbHeight()
{
int nTrackHeight = ( this .Height - (UpArrowImage.Height + DownArrowImage.Height));
float fThumbHeight = (( float )LargeChange / ( float )Maximum) * nTrackHeight;
int nThumbHeight = ( int )fThumbHeight;
if (nThumbHeight > nTrackHeight)
{
nThumbHeight = nTrackHeight;
fThumbHeight = nTrackHeight;
}
if (nThumbHeight < 56 )
{
nThumbHeight = 56 ;
fThumbHeight = 56 ;
}
return nThumbHeight;
}
public CustomScrollbar()
{
InitializeComponent();
SetStyle(ControlStyles.ResizeRedraw, true );
SetStyle(ControlStyles.AllPaintingInWmPaint, true );
SetStyle(ControlStyles.DoubleBuffer, true );
moChannelColor = Color.FromArgb( 51 , 166 , 3 );
UpArrowImage = Bitmap.FromStream(Shared.AssemblyWinUI.GetManifestResourceStream( " CRD.WinUI.Resources.Common.scroll.uparrow.png " ), true , false ); // BASSSkin.uparrow; // 上箭头
DownArrowImage = Bitmap.FromStream(Shared.AssemblyWinUI.GetManifestResourceStream( " CRD.WinUI.Resources.Common.scroll.downarrow.png " ), true , false ); // BASSSkin.downarrow; // 下肩头
ThumbBottomImage = Bitmap.FromStream(Shared.AssemblyWinUI.GetManifestResourceStream( " CRD.WinUI.Resources.Common.scroll.ThumbBottom.png " ), true , false ); // BASSSkin.ThumbBottom;
ThumbMiddleImage = Bitmap.FromStream(Shared.AssemblyWinUI.GetManifestResourceStream( " CRD.WinUI.Resources.Common.scroll.ThumbMiddle.png " ), true , false ); // BASSSkin.ThumbMiddle;
this .Width = UpArrowImage.Width; // 18px
base .MinimumSize = new Size(UpArrowImage.Width, UpArrowImage.Height + DownArrowImage.Height + GetThumbHeight());
}
[EditorBrowsable(EditorBrowsableState.Always), Browsable( true ), DefaultValue( false ), Category( " Behavior " ), Description( " LargeChange " )]
public int LargeChange
{
get { return moLargeChange; }
set
{
moLargeChange = value;
Invalidate();
}
}
[EditorBrowsable(EditorBrowsableState.Always), Browsable( true ), DefaultValue( false ), Category( " Behavior " ), Description( " SmallChange " )]
public int SmallChange
{
get { return moSmallChange; }
set
{
moSmallChange = value;
Invalidate();
}
}
[EditorBrowsable(EditorBrowsableState.Always), Browsable( true ), DefaultValue( false ), Category( " Behavior " ), Description( " Minimum " )]
public int Minimum
{
get { return moMinimum; }
set
{
moMinimum = value;
Invalidate();
}
}
[EditorBrowsable(EditorBrowsableState.Always), Browsable( true ), DefaultValue( false ), Category( " Behavior " ), Description( " Maximum " )]
public int Maximum
{
get { return moMaximum; }
set
{
moMaximum = value;
Invalidate();
}
}
[EditorBrowsable(EditorBrowsableState.Always), Browsable( true ), DefaultValue( false ), Category( " Behavior " ), Description( " Value " )]
public int Value
{
get { return moValue; }
set
{
moValue = value;
int nTrackHeight = ( this .Height - (UpArrowImage.Height + DownArrowImage.Height));
float fThumbHeight = (( float )LargeChange / ( float )Maximum) * nTrackHeight;
int nThumbHeight = ( int )fThumbHeight;
if (nThumbHeight > nTrackHeight)
{
nThumbHeight = nTrackHeight;
fThumbHeight = nTrackHeight;
}
if (nThumbHeight < 56 )
{
nThumbHeight = 56 ;
fThumbHeight = 56 ;
}
// figure out value
int nPixelRange = nTrackHeight - nThumbHeight;
int nRealRange = (Maximum - Minimum) - LargeChange;
float fPerc = 0.0f ;
if (nRealRange != 0 )
{
fPerc = ( float )moValue / ( float )nRealRange;
}
float fTop = fPerc * nPixelRange;
moThumbTop = ( int )fTop;
Invalidate();
}
}
[EditorBrowsable(EditorBrowsableState.Always), Browsable( true ), DefaultValue( false ), Category( " Skin " ), Description( " Channel Color " )]
public Color ChannelColor
{
get { return moChannelColor; }
set { moChannelColor = value; }
}
[EditorBrowsable(EditorBrowsableState.Always), Browsable( true ), DefaultValue( false ), Category( " Skin " ), Description( " Up Arrow Graphic " )]
public Image UpArrowImage
{
get { return moUpArrowImage; }
set { moUpArrowImage = value; }
}
[EditorBrowsable(EditorBrowsableState.Always), Browsable( true ), DefaultValue( false ), Category( " Skin " ), Description( " Up Arrow Graphic " )]
public Image DownArrowImage
{
get { return moDownArrowImage; }
set { moDownArrowImage = value; }
}
[EditorBrowsable(EditorBrowsableState.Always), Browsable( true ), DefaultValue( false ), Category( " Skin " ), Description( " Up Arrow Graphic " )]
public Image ThumbBottomImage
{
get { return moThumbBottomImage; }
set { moThumbBottomImage = value; }
}
[EditorBrowsable(EditorBrowsableState.Always), Browsable( true ), DefaultValue( false ), Category( " Skin " ), Description( " Up Arrow Graphic " )]
public Image ThumbMiddleImage
{
get { return moThumbMiddleImage; }
set { moThumbMiddleImage = value; }
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
if (UpArrowImage != null )
{
e.Graphics.DrawImage(UpArrowImage, new Rectangle( new Point( 0 , 0 ), new Size( this .Width, UpArrowImage.Height)));
}
Brush oBrush = new SolidBrush(moChannelColor);
Brush oWhiteBrush = new SolidBrush(Color.FromArgb( 255 , 255 , 255 ));
// 函数名: rectangle
// 功 能: 画一个矩形
// 用 法: void far rectangle(int left, int top, int right, int bottom);
// draw channel left and right border colors
e.Graphics.FillRectangle(oWhiteBrush, new Rectangle( 0 , UpArrowImage.Height, 1 , ( this .Height - DownArrowImage.Height)));
e.Graphics.FillRectangle(oWhiteBrush, new Rectangle( this .Width - 1 , UpArrowImage.Height, 1 , ( this .Height - DownArrowImage.Height)));
// draw channel
// e.Graphics.FillRectangle(oBrush, new Rectangle(1, UpArrowImage.Height, this.Width-2, (this.Height-DownArrowImage.Height)));
e.Graphics.DrawImage(ThumbBottomImage, new Rectangle( 0 , UpArrowImage.Height, this .Width, ( this .Height - DownArrowImage.Height)));
// draw thumb
int nTrackHeight = ( this .Height - (UpArrowImage.Height + DownArrowImage.Height));
float fThumbHeight = (( float )LargeChange / ( float )Maximum) * nTrackHeight;
int nThumbHeight = ( int )fThumbHeight;
if (nThumbHeight > nTrackHeight)
{
nThumbHeight = nTrackHeight;
fThumbHeight = nTrackHeight;
}
// MessageBox.Show(nThumbHeight.ToString());
if (nThumbHeight < 56 )
{
nThumbHeight = 56 ;
fThumbHeight = 56 ;
}
// Debug.WriteLine(nThumbHeight.ToString());
// float fSpanHeight = (fThumbHeight - (ThumbMiddleImage.Height + ThumbTopImage.Height + ThumbBottomImage.Height)) / 2.0f;
// int nSpanHeight = (int)fSpanHeight;
int nTop = moThumbTop; // 0
nTop += UpArrowImage.Height; // 9px
// draw top画上面的按钮
// e.Graphics.DrawImage(ThumbTopImage, new Rectangle(0, nTop, this.Width, ThumbTopImage.Height));
// nTop += ThumbTopImage.Height; // 10px
// draw top span
// Rectangle rect = new Rectangle(1, nTop, this.Width - 2, nSpanHeight);
// e.Graphics.DrawImage(ThumbTopSpanImage, 1.0f,(float)nTop, (float)this.Width-2.0f, (float) fSpanHeight*2);
// nTop += nSpanHeight; // 11px
// draw middle
e.Graphics.DrawImage(ThumbMiddleImage, new Rectangle( 0 , nTop, this .Width, ThumbMiddleImage.Height));
// nTop += ThumbMiddleImage.Height;
// draw top span
// rect = new Rectangle(1, nTop, this.Width - 2, nSpanHeight*2);
// e.Graphics.DrawImage(ThumbBottomSpanImage, rect);
// nTop += nSpanHeight;
// draw bottom
// e.Graphics.DrawImage(ThumbBottomImage, new Rectangle(1, nTop, this.Width - 2, nSpanHeight));
if (DownArrowImage != null )
{
e.Graphics.DrawImage(DownArrowImage, new Rectangle( new Point( 0 , ( this .Height - DownArrowImage.Height)), new Size( this .Width, DownArrowImage.Height)));
}
}
public override bool AutoSize
{
get
{
return base .AutoSize;
}
set
{
base .AutoSize = value;
if ( base .AutoSize)
{
this .Width = moUpArrowImage.Width;
}
}
}
private void InitializeComponent()
{
this .SuspendLayout();
//
// CustomScrollbar
//
this .Name = " CustomScrollbar " ;
this .MouseDown += new System.Windows.Forms.MouseEventHandler( this .CustomScrollbar_MouseDown);
this .MouseMove += new System.Windows.Forms.MouseEventHandler( this .CustomScrollbar_MouseMove);
this .MouseUp += new System.Windows.Forms.MouseEventHandler( this .CustomScrollbar_MouseUp);
this .ResumeLayout( false );
}
private void CustomScrollbar_MouseDown( object sender, MouseEventArgs e)
{
Point ptPoint = this .PointToClient(Cursor.Position);
int nTrackHeight = ( this .Height - (UpArrowImage.Height + DownArrowImage.Height));
float fThumbHeight = (( float )LargeChange / ( float )Maximum) * nTrackHeight;
int nThumbHeight = ( int )fThumbHeight;
if (nThumbHeight > nTrackHeight)
{
nThumbHeight = nTrackHeight;
fThumbHeight = nTrackHeight;
}
if (nThumbHeight < 56 )
{
nThumbHeight = 56 ;
fThumbHeight = 56 ;
}
int nTop = moThumbTop;
nTop += UpArrowImage.Height;
Rectangle thumbrect = new Rectangle( new Point( 1 , nTop), new Size(ThumbMiddleImage.Width, nThumbHeight));
if (thumbrect.Contains(ptPoint))
{
// hit the thumb
nClickPoint = (ptPoint.Y - nTop);
// MessageBox.Show(Convert.ToString((ptPoint.Y - nTop)));
this .moThumbDown = true ;
}
Rectangle uparrowrect = new Rectangle( new Point( 1 , 0 ), new Size(UpArrowImage.Width, UpArrowImage.Height));
if (uparrowrect.Contains(ptPoint))
{
int nRealRange = (Maximum - Minimum) - LargeChange;
int nPixelRange = (nTrackHeight - nThumbHeight);
if (nRealRange > 0 )
{
if (nPixelRange > 0 )
{
if ((moThumbTop - SmallChange) < 0 )
moThumbTop = 0 ;
else
moThumbTop -= SmallChange;
// figure out value
float fPerc = ( float )moThumbTop / ( float )nPixelRange;
float fValue = fPerc * (Maximum - LargeChange);
moValue = ( int )fValue;
Debug.WriteLine(moValue.ToString());
if (ValueChanged != null )
ValueChanged( this , new EventArgs());
if (Scroll != null )
Scroll( this , new EventArgs());
Invalidate();
}
}
}
Rectangle downarrowrect = new Rectangle( new Point( 1 , UpArrowImage.Height + nTrackHeight), new Size(UpArrowImage.Width, UpArrowImage.Height));
if (downarrowrect.Contains(ptPoint))
{
int nRealRange = (Maximum - Minimum) - LargeChange;
int nPixelRange = (nTrackHeight - nThumbHeight);
if (nRealRange > 0 )
{
if (nPixelRange > 0 )
{
if ((moThumbTop + SmallChange) > nPixelRange)
moThumbTop = nPixelRange;
else
moThumbTop += SmallChange;
// figure out value
float fPerc = ( float )moThumbTop / ( float )nPixelRange;
float fValue = fPerc * (Maximum - LargeChange);
moValue = ( int )fValue;
Debug.WriteLine(moValue.ToString());
if (ValueChanged != null )
ValueChanged( this , new EventArgs());
if (Scroll != null )
Scroll( this , new EventArgs());
Invalidate();
}
}
}
}
private void CustomScrollbar_MouseUp( object sender, MouseEventArgs e)
{
this .moThumbDown = false ;
this .moThumbDragging = false ;
}
private void MoveThumb( int y)
{
int nRealRange = Maximum - Minimum;
int nTrackHeight = ( this .Height - (UpArrowImage.Height + DownArrowImage.Height));
float fThumbHeight = (( float )LargeChange / ( float )Maximum) * nTrackHeight;
int nThumbHeight = ( int )fThumbHeight;
if (nThumbHeight > nTrackHeight)
{
nThumbHeight = nTrackHeight;
fThumbHeight = nTrackHeight;
}
if (nThumbHeight < 56 )
{
nThumbHeight = 56 ;
fThumbHeight = 56 ;
}
int nSpot = nClickPoint;
int nPixelRange = (nTrackHeight - nThumbHeight);
if (moThumbDown && nRealRange > 0 )
{
if (nPixelRange > 0 )
{
int nNewThumbTop = y - (UpArrowImage.Height + nSpot);
if (nNewThumbTop < 0 )
{
moThumbTop = nNewThumbTop = 0 ;
}
else if (nNewThumbTop > nPixelRange)
{
moThumbTop = nNewThumbTop = nPixelRange;
}
else
{
moThumbTop = y - (UpArrowImage.Height + nSpot);
}
// figure out value
float fPerc = ( float )moThumbTop / ( float )nPixelRange;
float fValue = fPerc * (Maximum - LargeChange);
moValue = ( int )fValue;
Debug.WriteLine(moValue.ToString());
Application.DoEvents();
Invalidate();
}
}
}
private void CustomScrollbar_MouseMove( object sender, MouseEventArgs e)
{
if (moThumbDown == true )
{
this .moThumbDragging = true ;
}
if ( this .moThumbDragging)
{
MoveThumb(e.Y);
}
if (ValueChanged != null )
ValueChanged( this , new EventArgs());
if (Scroll != null )
Scroll( this , new EventArgs());
}
}
internal class ScrollbarControlDesigner : System.Windows.Forms.Design.ControlDesigner
{
public override SelectionRules SelectionRules
{
get
{
SelectionRules selectionRules = base .SelectionRules;
PropertyDescriptor propDescriptor = TypeDescriptor.GetProperties( this .Component)[ " AutoSize " ];
if (propDescriptor != null )
{
bool autoSize = ( bool )propDescriptor.GetValue( this .Component);
if (autoSize)
{
selectionRules = SelectionRules.Visible | SelectionRules.Moveable | SelectionRules.BottomSizeable | SelectionRules.TopSizeable;
}
else
{
selectionRules = SelectionRules.Visible | SelectionRules.AllSizeable | SelectionRules.Moveable;
}
}
return selectionRules;
}
}
}
}
关于一些Api的方法吧,我都定义出来了直接用就行了
{
[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);
}
最后一步控件同步效果
info.nPos = customScrollbar1.Value;
Win32API.SetScrollInfo(listBox1.Handle, ( int )ScrollBarDirection.SB_VERT, ref info, true );
Win32API.PostMessage(listBox1.Handle, Win32API.WM_VSCROLL, Win32API.MakeLong(( short )Win32API.SB_THUMBTRACK, ( short )(info.nPos) ), 0 );
好了,现在我们拉一个控件到窗体上,就是我图1中的效果了。中间还有一些不好的地方,我争取改正,
也希望大家多多提建议,
我个人感觉这种方法不是什么很好的方法,如果是用C++来写的话会方便很多,但不知道c#是怎么写的,小弟确实不知道,还希望能得大家的帮助,一起来解决这个问题
其实我在网上也找了不少的资料,有些方法清空是抄别别人的,不过效果是实现 的,但总是感觉 不理想,不是自己想要的,也希望能通过这篇文章收集到一些好的解决方案,欢迎大家提供资源和解决方法,小弟在些谢过。
欢迎大家转载,如有转载请注明文章来自: http://sufei.cnblogs.com/
签名:做一番一生引以为豪的事业;在有生之年报答帮过我的人;并有能力帮助需要帮助的人;
QQ:361983679 Email:sufei.1013@163.com MSN:sufei.1013@163.com