您的位置:首页 > 编程语言 > C#

C#仿QQ皮肤-Label与ListBox 控件实现----寻求滚动条的解决方案

2010-11-16 10:23 706 查看
C#仿QQ皮肤-实现原理系列文章导航
http://www.cnblogs.com/sufei/archive/2010/03/10/1682847.html



大家还是先来看看效果吧







这次之所以一次写两个控件,其实主要是因为Label控件实在是太简单了没有必要放放一个文章里写,所以就一次性来了。

Label控件我就不再多说了,我直接把代码贴一下吧因为就几行代码,相信大家一眼就能看明白了。






代码

using System;
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实现





咱们从第一行代码就要吧看出来是继承自系统控件而来的。

public class ListBox : System.Windows.Forms.ListBox

所以本身就具备了系统的ListBox的一些特性。老方法我们先来看看WndProc方法的实现








代码

protected override void WndProc(ref System.Windows.Forms.Message m)
{
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;
}
}



这边的实现方法基本上和之前的控件一个样,所以我就不再多说原理了,大家随便看一下前几次的文章就明白了。

下面我们来看一下怎么样换皮肤的事件

也就是说在换皮肤的时候我们应该做那些工作








代码

protected override void OnDrawItem(DrawItemEventArgs e)
{
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;
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的方法吧,我都定义出来了直接用就行了






代码

public class Win32API
{
[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);
}





最后一步控件同步效果






代码

SCROLLINFO info = tvImageListScrollInfo;
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: