查了很多资料都找不到直接重写ListBox滚动条的方法只能曲线救国先自己重绘一个带皮肤的滚动条然后让它取代ListBox现有的滚动条 老习惯先传个效果图你觉得感兴趣就继续看下去不喜欢的话就此打住懒得耽误你宝贵的时间嘿嘿 注意此图中的滚动条宽度明显小于ListBox本身滚动条的宽度我目前只顾着实现功能了毕竟宽度调整相当简单哈 下面简单介绍下重绘系统滚动条的详细步骤: 在项目中添加新项用户控件我们命名为CustomScrollbarcs 准备几张图片添加进项目资源作为滚动条重绘时要用的背景我用的图片如下: uparrowpng资源名称为uparrow 滚动条的上箭头 ThumbBottompng资源名称为ThumbBottom 滚动条中间滑道的背景 ThumbMiddlepng资源名称为ThumbMiddle 滚动条的中间的拖动块 downarrowpng资源名称为downarrow 滚动条的下箭头 然后就是利用上面图片做背景重画滚动条背景了直接给出CustomScrollbarcs的代码吧 Code using System; using SystemCollectionsGeneric; using SystemComponentModel; using SystemDrawing; using SystemData; using SystemText; using SystemWindowsForms; using SystemWindowsFormsDesign; using SystemDiagnostics; namespace Winamp { [Designer(typeof(ScrollbarControlDesigner))] public partial class CustomScrollbar : UserControl { protected Color moChannelColor = ColorEmpty; 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 = ; protected int moSmallChange = ; protected int moMinimum = ; protected int moMaximum = ; protected int moValue = ; private int nClickPoint; protected int moThumbTop = ; 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 = (thisHeight (UpArrowImageHeight + DownArrowImageHeight)); float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight; int nThumbHeight = (int)fThumbHeight; if (nThumbHeight > nTrackHeight) { nThumbHeight = nTrackHeight; fThumbHeight = nTrackHeight; } if (nThumbHeight < ) { nThumbHeight = ; fThumbHeight = ; } return nThumbHeight; } public CustomScrollbar() { InitializeComponent(); SetStyle(ControlStylesResizeRedraw true); SetStyle(ControlStylesAllPaintingInWmPaint true); SetStyle(ControlStylesDoubleBuffer true); moChannelColor = ColorFromArgb( ); UpArrowImage = BASSSkinuparrow;//上箭头 DownArrowImage = BASSSkindownarrow;//下肩头 ThumbBottomImage = BASSSkinThumbBottom; ThumbMiddleImage = BASSSkinThumbMiddle; thisWidth = UpArrowImageWidth;//px baseMinimumSize = new Size(UpArrowImageWidth UpArrowImageHeight + DownArrowImageHeight + GetThumbHeight()); } [EditorBrowsable(EditorBrowsableStateAlways) Browsable(true) DefaultValue(false) Category(Behavior) Description(LargeChange)] public int LargeChange { get { return moLargeChange; } set { moLargeChange = value; Invalidate(); } } [EditorBrowsable(EditorBrowsableStateAlways) Browsable(true) DefaultValue(false) Category(Behavior) Description(SmallChange)] public int SmallChange { get { return moSmallChange; } set { moSmallChange = value; Invalidate(); } } [EditorBrowsable(EditorBrowsableStateAlways) Browsable(true) DefaultValue(false) Category(Behavior) Description(Minimum)] public int Minimum { get { return moMinimum; } set { moMinimum = value; Invalidate(); } } [EditorBrowsable(EditorBrowsableStateAlways) Browsable(true) DefaultValue(false) Category(Behavior) Description(Maximum)] public int Maximum { get { return moMaximum; } set { moMaximum = value; Invalidate(); } } [EditorBrowsable(EditorBrowsableStateAlways) Browsable(true) DefaultValue(false) Category(Behavior) Description(Value)] public int Value { get { return moValue; } set { moValue = value; int nTrackHeight = (thisHeight (UpArrowImageHeight + DownArrowImageHeight)); float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight; int nThumbHeight = (int)fThumbHeight; if (nThumbHeight > nTrackHeight) { nThumbHeight = nTrackHeight; fThumbHeight = nTrackHeight; } if (nThumbHeight < ) { nThumbHeight = ; fThumbHeight = ; } //figure out value int nPixelRange = nTrackHeight nThumbHeight; int nRealRange = (Maximum Minimum) LargeChange; float fPerc = f; if (nRealRange != ) { fPerc = (float)moValue / (float)nRealRange; } float fTop = fPerc * nPixelRange; moThumbTop = (int)fTop; Invalidate(); } } [EditorBrowsable(EditorBrowsableStateAlways) Browsable(true) DefaultValue(false) Category(Skin) Description(Channel Color)] public Color ChannelColor { get { return moChannelColor; } set { moChannelColor = value; } } [EditorBrowsable(EditorBrowsableStateAlways) Browsable(true) DefaultValue(false) Category(Skin) Description(Up Arrow Graphic)] public Image UpArrowImage { get { return moUpArrowImage; } set { moUpArrowImage = value; } } [EditorBrowsable(EditorBrowsableStateAlways) Browsable(true) DefaultValue(false) Category(Skin) Description(Up Arrow Graphic)] public Image DownArrowImage { get { return moDownArrowImage; } set { moDownArrowImage = value; } } [EditorBrowsable(EditorBrowsableStateAlways) Browsable(true) DefaultValue(false) Category(Skin) Description(Up Arrow Graphic)] public Image ThumbBottomImage { get { return moThumbBottomImage; } set { moThumbBottomImage = value; } } [EditorBrowsable(EditorBrowsableStateAlways) 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) { eGraphicsInterpolationMode = SystemDrawingDrawingDInterpolationModeNearestNeighbor; if (UpArrowImage != null) { eGraphicsDrawImage(UpArrowImage new Rectangle(new Point( ) new Size(thisWidth UpArrowImageHeight))); } Brush oBrush = new SolidBrush(moChannelColor); Brush oWhiteBrush = new SolidBrush(ColorFromArgb( )); // 函数名: rectangle //功 能: 画一个矩形 //用 法: void far rectangle(int left int top int right int bottom); //draw channel left and right border colors eGraphicsFillRectangle(oWhiteBrush new Rectangle( UpArrowImageHeight (thisHeight DownArrowImageHeight))); eGraphicsFillRectangle(oWhiteBrush new Rectangle(thisWidth UpArrowImageHeight (thisHeight DownArrowImageHeight))); //draw channel //eGraphicsFillRectangle(oBrush new Rectangle( UpArrowImageHeight thisWidth (thisHeightDownArrowImageHeight))); eGraphicsDrawImage(ThumbBottomImage new Rectangle( UpArrowImageHeight thisWidth (thisHeight DownArrowImageHeight))); //draw thumb int nTrackHeight = (thisHeight (UpArrowImageHeight + DownArrowImageHeight)); float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight; int nThumbHeight = (int)fThumbHeight; if (nThumbHeight > nTrackHeight) { nThumbHeight = nTrackHeight; fThumbHeight = nTrackHeight; } //MessageBoxShow(nThumbHeightToString()); if (nThumbHeight < ) { nThumbHeight = ; fThumbHeight = ; } //DebugWriteLine(nThumbHeightToString()); //float fSpanHeight = (fThumbHeight (ThumbMiddleImageHeight + ThumbTopImageHeight + ThumbBottomImageHeight)) / f; //int nSpanHeight = (int)fSpanHeight; int nTop = moThumbTop;// nTop += UpArrowImageHeight;//px //draw top画上面的按钮 //eGraphicsDrawImage(ThumbTopImage new Rectangle( nTop thisWidth ThumbTopImageHeight)); //nTop += ThumbTopImageHeight;//px //draw top span //Rectangle rect = new Rectangle( nTop thisWidth nSpanHeight); //eGraphicsDrawImage(ThumbTopSpanImage f(float)nTop (float)thisWidthf (float) fSpanHeight*); // nTop += nSpanHeight;//px //draw middle eGraphicsDrawImage(ThumbMiddleImage new Rectangle( nTop thisWidth ThumbMiddleImageHeight)); //nTop += ThumbMiddleImageHeight; //draw top span //rect = new Rectangle( nTop thisWidth nSpanHeight*); //eGraphicsDrawImage(ThumbBottomSpanImage rect); //nTop += nSpanHeight; //draw bottom //eGraphicsDrawImage(ThumbBottomImage new Rectangle( nTop thisWidth nSpanHeight)); if (DownArrowImage != null) { eGraphicsDrawImage(DownArrowImage new Rectangle(new Point( (thisHeight DownArrowImageHeight)) new Size(thisWidth DownArrowImageHeight))); } } public override bool AutoSize { get { return baseAutoSize; } set { baseAutoSize = value; if (baseAutoSize) { thisWidth = moUpArrowImageWidth; } } } private void InitializeComponent() { thisSuspendLayout(); // // CustomScrollbar // thisName = CustomScrollbar; thisMouseDown += new SystemWindowsFormsMouseEventHandler(thisCustomScrollbar_MouseDown); thisMouseMove += new SystemWindowsFormsMouseEventHandler(thisCustomScrollbar_MouseMove); thisMouseUp += new SystemWindowsFormsMouseEventHandler(thisCustomScrollbar_MouseUp); thisResumeLayout(false); } private void CustomScrollbar_MouseDown(object sender MouseEventArgs e) { Point ptPoint = thisPointToClient(CursorPosition); int nTrackHeight = (thisHeight (UpArrowImageHeight + DownArrowImageHeight)); float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight; int nThumbHeight = (int)fThumbHeight; if (nThumbHeight > nTrackHeight) { nThumbHeight = nTrackHeight; fThumbHeight = nTrackHeight; } if (nThumbHeight < ) { nThumbHeight = ; fThumbHeight = ; } int nTop = moThumbTop; nTop += UpArrowImageHeight; Rectangle thumbrect = new Rectangle(new Point( nTop) new Size(ThumbMiddleImageWidth nThumbHeight)); if (thumbrectContains(ptPoint)) { //hit the thumb nClickPoint = (ptPointY nTop); //MessageBoxShow(ConvertToString((ptPointY nTop))); thismoThumbDown = true; } Rectangle uparrowrect = new Rectangle(new Point( ) new Size(UpArrowImageWidth UpArrowImageHeight)); if (uparrowrectContains(ptPoint)) { int nRealRange = (Maximum Minimum) LargeChange; int nPixelRange = (nTrackHeight nThumbHeight); if (nRealRange > ) { if (nPixelRange > ) { if ((moThumbTop SmallChange) < ) moThumbTop = ; else moThumbTop = SmallChange; //figure out value float fPerc = (float)moThumbTop / (float)nPixelRange; float fValue = fPerc * (Maximum LargeChange); moValue = (int)fValue; DebugWriteLine(moValueToString()); if (ValueChanged != null) ValueChanged(this new EventArgs()); if (Scroll != null) Scroll(this new EventArgs()); Invalidate(); } } } Rectangle downarrowrect = new Rectangle(new Point( UpArrowImageHeight + nTrackHeight) new Size(UpArrowImageWidth UpArrowImageHeight)); if (downarrowrectContains(ptPoint)) { int nRealRange = (Maximum Minimum) LargeChange; int nPixelRange = (nTrackHeight nThumbHeight); if (nRealRange > ) { if (nPixelRange > ) { 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; DebugWriteLine(moValueToString()); if (ValueChanged != null) ValueChanged(this new EventArgs()); if (Scroll != null) Scroll(this new EventArgs()); Invalidate(); } } } } private void CustomScrollbar_MouseUp(object sender MouseEventArgs e) { thismoThumbDown = false; thismoThumbDragging = false; } private void MoveThumb(int y) { int nRealRange = Maximum Minimum; int nTrackHeight = (thisHeight (UpArrowImageHeight + DownArrowImageHeight)); float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight; int nThumbHeight = (int)fThumbHeight; if (nThumbHeight > nTrackHeight) { nThumbHeight = nTrackHeight; fThumbHeight = nTrackHeight; } if (nThumbHeight < ) { nThumbHeight = ; fThumbHeight = ; } int nSpot = nClickPoint; int nPixelRange = (nTrackHeight nThumbHeight); if (moThumbDown && nRealRange > ) { if (nPixelRange > ) { int nNewThumbTop = y (UpArrowImageHeight + nSpot); if (nNewThumbTop < ) { moThumbTop = nNewThumbTop = ; } else if (nNewThumbTop > nPixelRange) { moThumbTop = nNewThumbTop = nPixelRange; } else { moThumbTop = y (UpArrowImageHeight + nSpot); } //figure out value float fPerc = (float)moThumbTop / (float)nPixelRange; float fValue = fPerc * (Maximum LargeChange); moValue = (int)fValue; DebugWriteLine(moValueToString()); ApplicationDoEvents(); Invalidate(); } } } private void CustomScrollbar_MouseMove(object sender MouseEventArgs e) { if (moThumbDown == true) { thismoThumbDragging = true; } if (thismoThumbDragging) { MoveThumb(eY); } if (ValueChanged != null) ValueChanged(this new EventArgs()); if (Scroll != null) Scroll(this new EventArgs()); } } internal class ScrollbarControlDesigner : SystemWindowsFormsDesignControlDesigner { public override SelectionRules SelectionRules { get { SelectionRules selectionRules = baseSelectionRules; PropertyDescriptor propDescriptor = TypeDescriptorGetProperties(thisComponent)[AutoSize]; if (propDescriptor != null) { bool autoSize = (bool)propDescriptorGetValue(thisComponent); if (autoSize) { selectionRules = SelectionRulesVisible | SelectionRulesMoveable | SelectionRulesBottomSizeable | SelectionRulesTopSizeable; } else { selectionRules = SelectionRulesVisible | SelectionRulesAllSizeable | SelectionRulesMoveable; } } return selectionRules; } } } } 目前只想简单实现滚动条中上箭头/下箭头/滑道/拖动块的重写所以以上代码中OnPaint函数里的部分内容被我注释了好了这个滚动条控件已经做好了一个控件而已你应该会使用它我就不罗嗦了 接下来就是怎么用它来控制ListBox的内容滚动的问题了这需要调用API函数来实现同时又不能设置ListBox无滚动条因为ListBox没有滚动条也就没有滚动的事件可捕获那就达不到滚动的效果了 在你的窗体里拖一个listbox控件和一个上边我们制作好的用户控件分明命名为listBox和customScrollbar 然后往listBox中随便多弄写内容使之出现滚动条即可调整customScrollbar的位置使之覆盖在listBox的滚动条上呵呵这方法不错吧? 然后我们定义一下WinAPI代码如下 Code public class WinAPI { [StructLayout(LayoutKindSequential)] 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 = SB_VERT = SB_CTL = } public enum fMask { SIF_ALL SIF_DISABLENOSCROLL = X SIF_PAGE = X SIF_POS = X SIF_RANGE = X SIF_TRACKPOS = X } public static int MakeLong(short lowPart short highPart) { return (int)(((ushort)lowPart) | (uint)(highPart << )); } public const int SB_THUMBTRACK = ; public const int WM_HSCROLL = x; public const int WM_VSCROLL = x; [DllImport(userdll EntryPoint = GetScrollInfo)] public static extern bool GetScrollInfo(IntPtr hwnd int fnBar ref SCROLLINFO lpsi); [DllImport(userdll EntryPoint = SetScrollInfo)] public static extern int SetScrollInfo(IntPtr hwnd int fnBar [In] ref SCROLLINFO lpsi bool fRedraw); [DllImport(Userdll CharSet = CharSetAuto EntryPoint = SendMessage)] static extern IntPtr SendMessage(IntPtr hWnd uint Msg IntPtr wParam IntPtr lParam); [DllImport(userdll SetLastError = true)] public static extern bool PostMessage(IntPtr hWnd uint Msg long wParamint 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; } enum ScrollInfoMask { SIF_RANGE = x SIF_PAGE = x SIF_POS = x SIF_DISABLENOSCROLL = x SIF_TRACKPOS = x SIF_ALL = SIF_RANGE + SIF_PAGE + SIF_POS + SIF_TRACKPOS } enum ScrollBarDirection { SB_HORZ = SB_VERT = SB_CTL = SB_BOTH = } public SCROLLINFO tvImageListScrollInfo { get { SCROLLINFO si = new SCROLLINFO(); sicbSize = (uint)MarshalSizeOf(si); sifMask = (int)(ScrollInfoMaskSIF_DISABLENOSCROLL | ScrollInfoMaskSIF_ALL); WinAPIGetScrollInfo(listBoxHandle (int)ScrollBarDirectionSB_VERT ref si); return si; } } //当鼠标滚动时设置该滚动条 private void SetImageListScroll() { SCROLLINFO info = tvImageListScrollInfo; if (infonMax > ) { int pos = infonPos ; if (pos >= ) { customScrollbarValue = pos; } } } 定义customScrollbar的滚动事件函数customScrollbar_Scroll实现在滚动条滚动的同时发消息给listBox使之同步滚动 Code private void customScrollbar_Scroll(object sender EventArgs m) { //当滚动条滚动时通知控件也跟着滚动吧 SCROLLINFO info = tvImageListScrollInfo; infonPos = customScrollbarValue; WinAPISetScrollInfo(listBoxHandle (int)ScrollBarDirectionSB_VERT ref info true); WinAPIPostMessage(listBoxHandle WinAPIWM_VSCROLL WinAPIMakeLong((short)WinAPISB_THUMBTRACK (short)(infonPos)) ); } |