[原创]WinForm中重绘滚动条以及用重绘的滚动条控制ListBox的滚动
在本人的上一篇随笔<<高仿QQMusic播放器,浅谈WinForm关于UI的制作>>一文中,本人对播放器列表右边的灰色滚动条极为不满意,也影响到整个软件UI的协调性,遂下决心要重绘一个符合自己UI风格的滚动条.
查了很多资料,都找不到直接重写ListBox滚动条的方法,只能曲线救国,先自己重绘一个带皮肤的滚动条,然后让它取代ListBox现有的滚动条.
老习惯,先传个效果图,你觉得感兴趣就继续看下去,不喜欢的话就此打住,懒得耽误你宝
贵的时间,嘿嘿
注意,此图中的滚动条宽度明显小于ListBox本身滚动条的宽度,我目前只顾着实现功能了,毕竟,宽度调整相当简单哈。
下面简单介绍下重绘系统滚动条的详细步骤:
1.在项目中添加新项--用户控件,我们命名为CustomScrollbar.cs
2.准备几张图片添加进项目资源作为滚动条重绘时要用的背景,我用的图片如下:
uparrow.png资源名称为uparrow ,滚动条的上箭头
ThumbBottom.png资源名称为ThumbBottom ,滚动条中间滑道的背景
ThumbMiddle.png资源名称为ThumbMiddle ,滚动条的中间的拖动块
downarrow.png资源名称为downarrow ,滚动条的下箭头
3.然后就是利用上面图片做背景重画滚动条背景了,直接给出CustomScrollbar.cs的代码吧
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Drawing;
5 using System.Data;
6 using System.Text;
7 using System.Windows.Forms;
8 using System.Windows.Forms.Design;
9 using System.Diagnostics;
10 namespace Winamp
11 {
12 [Designer(typeof(ScrollbarControlDesigner))]
13 public partial class CustomScrollbar : UserControl
14 {
15
16 protected Color moChannelColor = Color.Empty;
17 protected Image moUpArrowImage = null;
18 protected Image moDownArrowImage = null;
19 protected Image moThumbArrowImage = null;
20
21 protected Image moThumbTopImage = null;
22 protected Image moThumbTopSpanImage = null;
23 protected Image moThumbBottomImage = null;
24 protected Image moThumbBottomSpanImage = null;
25 protected Image moThumbMiddleImage = null;
26
27 protected int moLargeChange = 10;
28 protected int moSmallChange = 1;
29 protected int moMinimum = 0;
30 protected int moMaximum = 100;
31 protected int moValue = 0;
32 private int nClickPoint;
33
34 protected int moThumbTop = 0;
35
36 protected bool moAutoSize = false;
37
38 private bool moThumbDown = false;
39 private bool moThumbDragging = false;
40
41 public new event EventHandler Scroll = null;
42 public event EventHandler ValueChanged = null;
43
44 private int GetThumbHeight()
45 {
46 int nTrackHeight = (this.Height - (UpArrowImage.Height + DownArrowImage.Height));
47 float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight;
48 int nThumbHeight = (int)fThumbHeight;
49
50 if (nThumbHeight > nTrackHeight)
51 {
52 nThumbHeight = nTrackHeight;
53 fThumbHeight = nTrackHeight;
54 }
55 if (nThumbHeight < 56)
56 {
57 nThumbHeight = 56;
58 fThumbHeight = 56;
59 }
60
61 return nThumbHeight;
62 }
63
64 public CustomScrollbar()
65 {
66
67 InitializeComponent();
68 SetStyle(ControlStyles.ResizeRedraw, true);
69 SetStyle(ControlStyles.AllPaintingInWmPaint, true);
70 SetStyle(ControlStyles.DoubleBuffer, true);
71
72 moChannelColor = Color.FromArgb(51, 166, 3);
73 UpArrowImage = BASSSkin.uparrow;
74 DownArrowImage = BASSSkin.downarrow;
75
76
77 ThumbBottomImage = BASSSkin.ThumbBottom;
78
79 ThumbMiddleImage = BASSSkin.ThumbMiddle;
80
81 this.Width = UpArrowImage.Width;
82 base.MinimumSize = new Size(UpArrowImage.Width, UpArrowImage.Height + DownArrowImage.Height + GetThumbHeight());
83 }
84
85 [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("Behavior"), Description
86
87 ("LargeChange")]
88 public int LargeChange
89 {
90 get { return moLargeChange; }
91 set
92 {
93 moLargeChange = value;
94 Invalidate();
95 }
96 }
97
98 [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("Behavior"), Description
99
100 ("SmallChange")]
101 public int SmallChange
102 {
103 get { return moSmallChange; }
104 set
105 {
106 moSmallChange = value;
107 Invalidate();
108 }
109 }
110
111 [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("Behavior"), Description("Minimum")]
112 public int Minimum
113 {
114 get { return moMinimum; }
115 set
116 {
117 moMinimum = value;
118 Invalidate();
119 }
120 }
121
122 [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("Behavior"), Description("Maximum")]
123 public int Maximum
124 {
125 get { return moMaximum; }
126 set
127 {
128 moMaximum = value;
129 Invalidate();
130 }
131 }
132
133 [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("Behavior"), Description("Value")]
134 public int Value
135 {
136 get { return moValue; }
137 set
138 {
139 moValue = value;
140
141 int nTrackHeight = (this.Height - (UpArrowImage.Height + DownArrowImage.Height));
142 float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight;
143 int nThumbHeight = (int)fThumbHeight;
144
145 if (nThumbHeight > nTrackHeight)
146 {
147 nThumbHeight = nTrackHeight;
148 fThumbHeight = nTrackHeight;
149 }
150 if (nThumbHeight < 56)
151 {
152 nThumbHeight = 56;
153 fThumbHeight = 56;
154 }
155
156
157 int nPixelRange = nTrackHeight - nThumbHeight;
158 int nRealRange = (Maximum - Minimum) - LargeChange;
159 float fPerc = 0.0f;
160 if (nRealRange != 0)
161 {
162 fPerc = (float)moValue / (float)nRealRange;
163
164 }
165
166 float fTop = fPerc * nPixelRange;
167 moThumbTop = (int)fTop;
168
169
170 Invalidate();
171 }
172 }
173
174 [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("Skin"), Description("Channel Color")]
175 public Color ChannelColor
176 {
177 get { return moChannelColor; }
178 set { moChannelColor = value; }
179 }
180
181 [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("Skin"), Description("Up Arrow
182
183 Graphic")]
184 public Image UpArrowImage
185 {
186 get { return moUpArrowImage; }
187 set { moUpArrowImage = value; }
188 }
189
190 [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("Skin"), Description("Up Arrow
191
192 Graphic")]
193 public Image DownArrowImage
194 {
195 get { return moDownArrowImage; }
196 set { moDownArrowImage = value; }
197 }
198
199
200
201
202 [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("Skin"), Description("Up Arrow
203
204 Graphic")]
205 public Image ThumbBottomImage
206 {
207 get { return moThumbBottomImage; }
208 set { moThumbBottomImage = value; }
209 }
210
211
212
213 [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("Skin"), Description("Up Arrow
214
215 Graphic")]
216 public Image ThumbMiddleImage
217 {
218 get { return moThumbMiddleImage; }
219 set { moThumbMiddleImage = value; }
220 }
221
222 protected override void OnPaint(PaintEventArgs e)
223 {
224
225 e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
226
227 if (UpArrowImage != null)
228 {
229 e.Graphics.DrawImage(UpArrowImage, new Rectangle(new Point(0, 0), new Size(this.Width, UpArrowImage.Height)));
230 }
231
232 Brush oBrush = new SolidBrush(moChannelColor);
233 Brush oWhiteBrush = new SolidBrush(Color.FromArgb(255, 255, 255));
234
235 e.Graphics.FillRectangle(oWhiteBrush, new Rectangle(0, UpArrowImage.Height, 1, (this.Height - DownArrowImage.Height)));
236 e.Graphics.FillRectangle(oWhiteBrush, new Rectangle(this.Width - 1, UpArrowImage.Height, 1, (this.Height -
237
238 DownArrowImage.Height)));
239
240
241 e.Graphics.DrawImage(ThumbBottomImage, new Rectangle(0, UpArrowImage.Height, this.Width, (this.Height - DownArrowImage.Height)));
242
243 int nTrackHeight = (this.Height - (UpArrowImage.Height + DownArrowImage.Height));
244 float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight;
245 int nThumbHeight = (int)fThumbHeight;
246
247 if (nThumbHeight > nTrackHeight)
248 {
249 nThumbHeight = nTrackHeight;
250 fThumbHeight = nTrackHeight;
251 }
252
253 if (nThumbHeight < 56)
254 {
255 nThumbHeight = 56;
256 fThumbHeight = 56;
257 }
258
259
260 int nTop = moThumbTop;//0
261 nTop += UpArrowImage.Height;//9px
262
263
264 e.Graphics.DrawImage(ThumbMiddleImage, new Rectangle(0, nTop, this.Width, ThumbMiddleImage.Height));
265
266
267
268 if (DownArrowImage != null)
269 {
270 e.Graphics.DrawImage(DownArrowImage, new Rectangle(new Point(0, (this.Height - DownArrowImage.Height)), new Size(this.Width,
271
272 DownArrowImage.Height)));
273 }
274
275 }
276
277
278 public override bool AutoSize
279 {
280 get
281 {
282 return base.AutoSize;
283 }
284 set
285 {
286 base.AutoSize = value;
287 if (base.AutoSize)
288 {
289 this.Width = moUpArrowImage.Width;
290 }
291 }
292 }
293
294 private void InitializeComponent()
295 {
296 this.SuspendLayout();
297
298 this.Name = "CustomScrollbar";
299 this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.CustomScrollbar_MouseDown);
300 this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.CustomScrollbar_MouseMove);
301 this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.CustomScrollbar_MouseUp);
302 this.ResumeLayout(false);
303
304 }
305
306 private void CustomScrollbar_MouseDown(object sender, MouseEventArgs e)
307 {
308 Point ptPoint = this.PointToClient(Cursor.Position);
309 int nTrackHeight = (this.Height - (UpArrowImage.Height + DownArrowImage.Height));
310 float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight;
311 int nThumbHeight = (int)fThumbHeight;
312
313 if (nThumbHeight > nTrackHeight)
314 {
315 nThumbHeight = nTrackHeight;
316 fThumbHeight = nTrackHeight;
317 }
318 if (nThumbHeight < 56)
319 {
320 nThumbHeight = 56;
321 fThumbHeight = 56;
322 }
323
324 int nTop = moThumbTop;
325 nTop += UpArrowImage.Height;
326
327
328 Rectangle thumbrect = new Rectangle(new Point(1, nTop), new Size(ThumbMiddleImage.Width, nThumbHeight));
329 if (thumbrect.Contains(ptPoint))
330 {
331
332
333 nClickPoint = (ptPoint.Y - nTop);
334
335 this.moThumbDown = true;
336 }
337
338 Rectangle uparrowrect = new Rectangle(new Point(1, 0), new Size(UpArrowImage.Width, UpArrowImage.Height));
339 if (uparrowrect.Contains(ptPoint))
340 {
341
342 int nRealRange = (Maximum - Minimum) - LargeChange;
343 int nPixelRange = (nTrackHeight - nThumbHeight);
344 if (nRealRange > 0)
345 {
346 if (nPixelRange > 0)
347 {
348 if ((moThumbTop - SmallChange) < 0)
349 moThumbTop = 0;
350 else
351 moThumbTop -= SmallChange;
352
353
354 float fPerc = (float)moThumbTop / (float)nPixelRange;
355 float fValue = fPerc * (Maximum - LargeChange);
356
357 moValue = (int)fValue;
358 Debug.WriteLine(moValue.ToString());
359
360 if (ValueChanged != null)
361 ValueChanged(this, new EventArgs());
362
363 if (Scroll != null)
364 Scroll(this, new EventArgs());
365
366 Invalidate();
367 }
368 }
369 }
370
371 Rectangle downarrowrect = new Rectangle(new Point(1, UpArrowImage.Height + nTrackHeight), new Size(UpArrowImage.Width,
372
373 UpArrowImage.Height));
374 if (downarrowrect.Contains(ptPoint))
375 {
376 int nRealRange = (Maximum - Minimum) - LargeChange;
377 int nPixelRange = (nTrackHeight - nThumbHeight);
378 if (nRealRange > 0)
379 {
380 if (nPixelRange > 0)
381 {
382 if ((moThumbTop + SmallChange) > nPixelRange)
383 moThumbTop = nPixelRange;
384 else
385 moThumbTop += SmallChange;
386
387
388 float fPerc = (float)moThumbTop / (float)nPixelRange;
389 float fValue = fPerc * (Maximum - LargeChange);
390
391 moValue = (int)fValue;
392 Debug.WriteLine(moValue.ToString());
393
394 if (ValueChanged != null)
395 ValueChanged(this, new EventArgs());
396
397 if (Scroll != null)
398 Scroll(this, new EventArgs());
399
400 Invalidate();
401 }
402 }
403 }
404 }
405
406 private void CustomScrollbar_MouseUp(object sender, MouseEventArgs e)
407 {
408 this.moThumbDown = false;
409 this.moThumbDragging = false;
410 }
411
412 private void MoveThumb(int y)
413 {
414 int nRealRange = Maximum - Minimum;
415 int nTrackHeight = (this.Height - (UpArrowImage.Height + DownArrowImage.Height));
416 float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight;
417 int nThumbHeight = (int)fThumbHeight;
418
419 if (nThumbHeight > nTrackHeight)
420 {
421 nThumbHeight = nTrackHeight;
422 fThumbHeight = nTrackHeight;
423 }
424 if (nThumbHeight < 56)
425 {
426 nThumbHeight = 56;
427 fThumbHeight = 56;
428 }
429
430 int nSpot = nClickPoint;
431
432 int nPixelRange = (nTrackHeight - nThumbHeight);
433 if (moThumbDown && nRealRange > 0)
434 {
435 if (nPixelRange > 0)
436 {
437 int nNewThumbTop = y - (UpArrowImage.Height + nSpot);
438
439 if (nNewThumbTop < 0)
440 {
441 moThumbTop = nNewThumbTop = 0;
442 }
443 else if (nNewThumbTop > nPixelRange)
444 {
445 moThumbTop = nNewThumbTop = nPixelRange;
446 }
447 else
448 {
449 moThumbTop = y - (UpArrowImage.Height + nSpot);
450 }
451
452
453 float fPerc = (float)moThumbTop / (float)nPixelRange;
454 float fValue = fPerc * (Maximum - LargeChange);
455 moValue = (int)fValue;
456 Debug.WriteLine(moValue.ToString());
457
458 Application.DoEvents();
459
460 Invalidate();
461 }
462 }
463 }
464
465 private void CustomScrollbar_MouseMove(object sender, MouseEventArgs e)
466 {
467 if (moThumbDown == true)
468 {
469 this.moThumbDragging = true;
470 }
471
472 if (this.moThumbDragging)
473 {
474
475 MoveThumb(e.Y);
476 }
477
478 if (ValueChanged != null)
479 ValueChanged(this, new EventArgs());
480
481 if (Scroll != null)
482 Scroll(this, new EventArgs());
483 }
484
485 }
486
487 internal class ScrollbarControlDesigner : System.Windows.Forms.Design.ControlDesigner
488 {
489
490
491
492 public override SelectionRules SelectionRules
493 {
494 get
495 {
496 SelectionRules selectionRules = base.SelectionRules;
497 PropertyDescriptor propDescriptor = TypeDescriptor.GetProperties(this.Component)["AutoSize"];
498 if (propDescriptor != null)
499 {
500 bool autoSize = (bool)propDescriptor.GetValue(this.Component);
501 if (autoSize)
502 {
503 selectionRules = SelectionRules.Visible | SelectionRules.Moveable | SelectionRules.BottomSizeable |
504
505 SelectionRules.TopSizeable;
506 }
507 else
508 {
509 selectionRules = SelectionRules.Visible | SelectionRules.AllSizeable | SelectionRules.Moveable;
510 }
511 }
512 return selectionRules;
513 }
514 }
515 }
516 }
目前只想简单实现滚动条中上箭头/下箭头/滑道/拖动块的重写,所以以上代码中OnPaint函数里的部分内容被我注释了,好了,这个滚动条控件已经做好了,一个控件而已,你应该会使用它,我就不罗嗦了。
接下来就是怎么用它来控制ListBox的内容滚动的问题了,这需要调用API函数来实现,同时又不能设置ListBox无滚动条,因为ListBox没有滚动条也就没有滚动的事件可捕获,那就达不到滚动的效果了。
在你的窗体里拖一个listbox控件和一个上边我们制作好的用户控件,分明命名为listBox和customScrollbar1,
然后往listBox中随便多弄写内容,使之出现滚动条即可。调整customScrollbar1的位置使之覆盖在listBox的滚动条上,呵呵,这方法不错吧?
然后我们定义一下Win32API,代码如下:
定义customScrollbar1的滚动事件函数customScrollbar1_Scroll,实现在滚动条滚动的同时发消息给listBox使之同步滚动
感谢博友Yellowyu在滚动控制方面给予的帮助。
调整了一下滚动条重绘所用到的图片的尺寸,看起来效果好多了!!!