前提

入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章。

开源地址:

如果觉得写的还行,请点个 star 支持一下吧

欢迎前来交流探讨: 企鹅群568015492 

目录

准备工作

此控件在基础上调整修改,特此感谢

开始

添加一个用户组件,命名tabcontrolext,继承自tabcontrol

几个重写属性

 1  private color _backcolor = color.white;
 2         [browsable(true)]
 3         [editorbrowsable(editorbrowsablestate.always)]
 4         [defaultvalue(typeof(color), "white")]
 5         public override color backcolor
 6         {
 7             get { return _backcolor; }
 8             set
 9             {
10                 _backcolor = value;
11                 base.invalidate(true);
12             }
13         }
14 
15         private color _bordercolor = color.fromargb(232, 232, 232);
16         [defaultvalue(typeof(color), "232, 232, 232")]
17         [description("tabcontorl边框色")]
18         public color bordercolor
19         {
20             get { return _bordercolor; }
21             set
22             {
23                 _bordercolor = value;
24                 base.invalidate(true);
25             }
26         }
27 
28         private color _headselectedbackcolor = color.fromargb(255, 85, 51);
29         [defaultvalue(typeof(color), "255, 85, 51")]
30         [description("tabpage头部选中后的背景颜色")]
31         public color headselectedbackcolor
32         {
33             get { return _headselectedbackcolor; }
34             set { _headselectedbackcolor = value; }
35         }
36 
37         private color _headselectedbordercolor = color.fromargb(232, 232, 232);
38         [defaultvalue(typeof(color), "232, 232, 232")]
39         [description("tabpage头部选中后的边框颜色")]
40         public color headselectedbordercolor
41         {
42             get { return _headselectedbordercolor; }
43             set { _headselectedbordercolor = value; }
44         }
45 
46         private color _headerbackcolor = color.white;
47         [defaultvalue(typeof(color), "white")]
48         [description("tabpage头部默认背景颜色")]
49         public color headerbackcolor
50         {
51             get { return _headerbackcolor; }
52             set { _headerbackcolor = value; }
53         }

重写背景

 1 protected override void onpaintbackground(painteventargs pevent)
 2         {
 3             if (this.designmode == true)
 4             {
 5                 lineargradientbrush backbrush = new lineargradientbrush(
 6                             this.bounds,
 7                             systemcolors.controllightlight,
 8                             systemcolors.controllight,
 9                             lineargradientmode.vertical);
10                 pevent.graphics.fillrectangle(backbrush, this.bounds);
11                 backbrush.dispose();
12             }
13             else
14             {
15                 this.painttransparentbackground(pevent.graphics, this.clientrectangle);
16             }
17         }
18  /// <summary>
19         ///  tabcontorl 背景色设置
20         /// </summary>
21         /// <param name="g"></param>
22         /// <param name="cliprect"></param>
23         protected void painttransparentbackground(graphics g, rectangle cliprect)
24         {
25             if ((this.parent != null))
26             {
27                 cliprect.offset(this.location);
28                 painteventargs e = new painteventargs(g, cliprect);
29                 graphicsstate state = g.save();
30                 g.smoothingmode = smoothingmode.highspeed;
31                 try
32                 {
33                     g.translatetransform((float)-this.location.x, (float)-this.location.y);
34                     this.invokepaintbackground(this.parent, e);
35                     this.invokepaint(this.parent, e);
36                 }
37                 finally
38                 {
39                     g.restore(state);
40                     cliprect.offset(-this.location.x, -this.location.y);
41                     //新加片段,待测试
42                     using (solidbrush brush = new solidbrush(_backcolor))
43                     {
44                         cliprect.inflate(1, 1);
45                         g.fillrectangle(brush, cliprect);
46                     }
47                 }
48             }
49             else
50             {
51                 system.drawing.drawing2d.lineargradientbrush backbrush = new system.drawing.drawing2d.lineargradientbrush(this.bounds, systemcolors.controllightlight, systemcolors.controllight, system.drawing.drawing2d.lineargradientmode.vertical);
52                 g.fillrectangle(backbrush, this.bounds);
53                 backbrush.dispose();
54             }
55         }

重绘

1  protected override void onpaint(painteventargs e)
2         {
3             // paint the background 
4             base.onpaint(e);
5             this.painttransparentbackground(e.graphics, this.clientrectangle);
6             this.paintallthetabs(e);
7             this.paintthetabpageborder(e);
8             this.painttheselectedtab(e);
9         }

辅助函数

  1 private void paintallthetabs(system.windows.forms.painteventargs e)
  2         {
  3             if (this.tabcount > 0)
  4             {
  5                 for (int index = 0; index < this.tabcount; index++)
  6                 {
  7                     this.painttab(e, index);
  8                 }
  9             }
 10         }
 11 
 12         private void painttab(system.windows.forms.painteventargs e, int index)
 13         {
 14             graphicspath path = this.gettabpath(index);
 15             this.painttabbackground(e.graphics, index, path);
 16             this.painttabborder(e.graphics, index, path);
 17             this.painttabtext(e.graphics, index);
 18             this.painttabimage(e.graphics, index);
 19         }
 20 
 21         /// <summary>
 22         /// 设置选项卡头部颜色
 23         /// </summary>
 24         /// <param name="graph"></param>
 25         /// <param name="index"></param>
 26         /// <param name="path"></param>
 27         private void painttabbackground(system.drawing.graphics graph, int index, system.drawing.drawing2d.graphicspath path)
 28         {
 29             rectangle rect = this.gettabrect(index);
 30             system.drawing.brush buttonbrush = new system.drawing.drawing2d.lineargradientbrush(rect, _headerbackcolor, _headerbackcolor, lineargradientmode.vertical);  //非选中时候的 tabpage 页头部背景色
 31             graph.fillpath(buttonbrush, path);
 32             //if (index == this.selectedindex)
 33             //{
 34             //    //buttonbrush = new system.drawing.solidbrush(_headselectedbackcolor);
 35             //    graph.drawline(new pen(_headerbackcolor), rect.right+2, rect.bottom, rect.left + 1, rect.bottom);
 36             //}
 37             buttonbrush.dispose();
 38         }
 39 
 40         /// <summary>
 41         /// 设置选项卡头部边框色
 42         /// </summary>
 43         /// <param name="graph"></param>
 44         /// <param name="index"></param>
 45         /// <param name="path"></param>
 46         private void painttabborder(system.drawing.graphics graph, int index, system.drawing.drawing2d.graphicspath path)
 47         {
 48             pen borderpen = new pen(_bordercolor);// tabpage 非选中时候的 tabpage 头部边框色
 49             if (index == this.selectedindex)
 50             {
 51                 borderpen = new pen(_headselectedbordercolor); // tabpage 选中后的 tabpage 头部边框色
 52             }
 53             graph.drawpath(borderpen, path);
 54             borderpen.dispose();
 55         }
 56 
 57         private void painttabimage(system.drawing.graphics g, int index)
 58         {
 59             image tabimage = null;
 60             if (this.tabpages[index].imageindex > -1 && this.imagelist != null)
 61             {
 62                 tabimage = this.imagelist.images[this.tabpages[index].imageindex];
 63             }
 64             else if (this.tabpages[index].imagekey.trim().length > 0 && this.imagelist != null)
 65             {
 66                 tabimage = this.imagelist.images[this.tabpages[index].imagekey];
 67             }
 68             if (tabimage != null)
 69             {
 70                 rectangle rect = this.gettabrect(index);
 71                 g.drawimage(tabimage, rect.right - rect.height - 4, 4, rect.height - 2, rect.height - 2);
 72             }
 73         }
 74 
 75         private void painttabtext(system.drawing.graphics graph, int index)
 76         {
 77             string tabtext = this.tabpages[index].text;
 78 
 79             system.drawing.stringformat format = new system.drawing.stringformat();
 80             format.alignment = stringalignment.near;
 81             format.linealignment = stringalignment.center;
 82             format.trimming = stringtrimming.ellipsischaracter;
 83 
 84             brush forebrush = null;
 85 
 86             if (this.tabpages[index].enabled == false)
 87             {
 88                 forebrush = systembrushes.controldark;
 89             }
 90             else
 91             {
 92                 forebrush = systembrushes.controltext;
 93             }
 94 
 95             font tabfont = this.font;
 96             if (index == this.selectedindex)
 97             {
 98                 if (this.tabpages[index].enabled != false)
 99                 {
100                     forebrush = new solidbrush(_headselectedbackcolor);
101                 }
102             }
103 
104             rectangle rect = this.gettabrect(index);
105 
106             var txtsize = controlhelper.getstringwidth(tabtext, graph, tabfont);
107             rectangle rect2 = new rectangle(rect.left + (rect.width - txtsize) / 2 - 1, rect.top, rect.width, rect.height);
108 
109             graph.drawstring(tabtext, tabfont, forebrush, rect2, format);
110         }
111 
112         /// <summary>
113         /// 设置 tabpage 内容页边框色
114         /// </summary>
115         /// <param name="e"></param>
116         private void paintthetabpageborder(system.windows.forms.painteventargs e)
117         {
118             if (this.tabcount > 0)
119             {
120                 rectangle borderrect = this.tabpages[0].bounds;
121                 //borderrect.inflate(1, 1);
122                 rectangle rect = new rectangle(borderrect.x - 2, borderrect.y-1, borderrect.width + 5, borderrect.height+2);
123                 controlpaint.drawborder(e.graphics, rect, this.bordercolor, buttonborderstyle.solid);
124             }
125         }
126 
127         /// <summary>
128         /// // tabpage 页头部间隔色
129         /// </summary>
130         /// <param name="e"></param>
131         private void painttheselectedtab(system.windows.forms.painteventargs e)
132         {
133             if (this.selectedindex == -1)
134                 return;
135             rectangle selrect;
136             int selrectright = 0;
137             selrect = this.gettabrect(this.selectedindex);
138             selrectright = selrect.right;
139             e.graphics.drawline(new pen(_headselectedbackcolor), selrect.left, selrect.bottom + 1, selrectright, selrect.bottom + 1);
140         }
141 
142         private graphicspath gettabpath(int index)
143         {
144             system.drawing.drawing2d.graphicspath path = new system.drawing.drawing2d.graphicspath();
145             path.reset();
146 
147             rectangle rect = this.gettabrect(index);
148 
149             switch (alignment)
150             {
151                 case tabalignment.top:
152 
153                     break;
154                 case tabalignment.bottom:
155 
156                     break;
157                 case tabalignment.left:
158 
159                     break;
160                 case tabalignment.right:
161 
162                     break;
163             }
164 
165             path.addline(rect.left, rect.top, rect.left, rect.bottom + 1);
166             path.addline(rect.left, rect.top, rect.right , rect.top);
167             path.addline(rect.right , rect.top, rect.right , rect.bottom + 1);
168             path.addline(rect.right , rect.bottom + 1, rect.left, rect.bottom + 1);
169 
170             return path;
171         }

2个重写函数处理字体相关

 1  [dllimport("user32.dll")]
 2         private static extern intptr sendmessage(intptr hwnd, int msg, intptr wparam, intptr lparam);
 3 
 4         private const int wm_setfont = 0x30;
 5         private const int wm_fontchange = 0x1d;
 6 
 7         protected override void oncreatecontrol()
 8         {
 9             base.oncreatecontrol();
10             this.onfontchanged(eventargs.empty);
11         }
12 
13         protected override void onfontchanged(eventargs e)
14         {
15             base.onfontchanged(e);
16             intptr hfont = this.font.tohfont();
17             sendmessage(this.handle, wm_setfont, hfont, (intptr)(-1));
18             sendmessage(this.handle, wm_fontchange, intptr.zero, intptr.zero);
19             this.updatestyles();
20         }

 完整代码

  1 using system;
2 using system.collections.generic;
3 using system.componentmodel;
4 using system.diagnostics;
5 using system.drawing;
6 using system.drawing.drawing2d;
7 using system.linq;
8 using system.runtime.interopservices;
9 using system.text;
10 using system.windows.forms;
11 
12 namespace hzh_controls.controls
13 {
14     public class tabcontrolext : tabcontrol
15     {
16         public tabcontrolext()
17             : base()
18         {
19             setstyles();
20             this.multiline = true;
21             this.itemsize = new size(this.itemsize.width, 50);
22         }
23 
24         private void setstyles()
25         {
26             base.setstyle(
27                 controlstyles.userpaint |
28                 controlstyles.doublebuffer |
29                 controlstyles.optimizeddoublebuffer |
30                 controlstyles.allpaintinginwmpaint |
31                 controlstyles.resizeredraw |
32                 controlstyles.supportstransparentbackcolor, true);
33             base.updatestyles();
34         }
35 
36         private color _backcolor = color.white;
37         [browsable(true)]
38         [editorbrowsable(editorbrowsablestate.always)]
39         [defaultvalue(typeof(color), "white")]
40         public override color backcolor
41         {
42             get { return _backcolor; }
43             set
44             {
45                 _backcolor = value;
46                 base.invalidate(true);
47             }
48         }
49 
50         private color _bordercolor = color.fromargb(232, 232, 232);
51         [defaultvalue(typeof(color), "232, 232, 232")]
52         [description("tabcontorl边框色")]
53         public color bordercolor
54         {
55             get { return _bordercolor; }
56             set
57             {
58                 _bordercolor = value;
59                 base.invalidate(true);
60             }
61         }
62 
63         private color _headselectedbackcolor = color.fromargb(255, 85, 51);
64         [defaultvalue(typeof(color), "255, 85, 51")]
65         [description("tabpage头部选中后的背景颜色")]
66         public color headselectedbackcolor
67         {
68             get { return _headselectedbackcolor; }
69             set { _headselectedbackcolor = value; }
70         }
71 
72         private color _headselectedbordercolor = color.fromargb(232, 232, 232);
73         [defaultvalue(typeof(color), "232, 232, 232")]
74         [description("tabpage头部选中后的边框颜色")]
75         public color headselectedbordercolor
76         {
77             get { return _headselectedbordercolor; }
78             set { _headselectedbordercolor = value; }
79         }
80 
81         private color _headerbackcolor = color.white;
82         [defaultvalue(typeof(color), "white")]
83         [description("tabpage头部默认背景颜色")]
84         public color headerbackcolor
85         {
86             get { return _headerbackcolor; }
87             set { _headerbackcolor = value; }
88         }
89 
90         protected override void onpaintbackground(painteventargs pevent)
91         {
92             if (this.designmode == true)
93             {
94                 lineargradientbrush backbrush = new lineargradientbrush(
95                             this.bounds,
96                             systemcolors.controllightlight,
97                             systemcolors.controllight,
98                             lineargradientmode.vertical);
99                 pevent.graphics.fillrectangle(backbrush, this.bounds);
100                 backbrush.dispose();
101             }
102             else
103             {
104                 this.painttransparentbackground(pevent.graphics, this.clientrectangle);
105             }
106         }
107 
108         /// <summary>
109         ///  tabcontorl 背景色设置
110         /// </summary>
111         /// <param name="g"></param>
112         /// <param name="cliprect"></param>
113         protected void painttransparentbackground(graphics g, rectangle cliprect)
114         {
115             if ((this.parent != null))
116             {
117                 cliprect.offset(this.location);
118                 painteventargs e = new painteventargs(g, cliprect);
119                 graphicsstate state = g.save();
120                 g.smoothingmode = smoothingmode.highspeed;
121                 try
122                 {
123                     g.translatetransform((float)-this.location.x, (float)-this.location.y);
124                     this.invokepaintbackground(this.parent, e);
125                     this.invokepaint(this.parent, e);
126                 }
127                 finally
128                 {
129                     g.restore(state);
130                     cliprect.offset(-this.location.x, -this.location.y);
131                     //新加片段,待测试
132                     using (solidbrush brush = new solidbrush(_backcolor))
133                     {
134                         cliprect.inflate(1, 1);
135                         g.fillrectangle(brush, cliprect);
136                     }
137                 }
138             }
139             else
140             {
141                 system.drawing.drawing2d.lineargradientbrush backbrush = new system.drawing.drawing2d.lineargradientbrush(this.bounds, systemcolors.controllightlight, systemcolors.controllight, system.drawing.drawing2d.lineargradientmode.vertical);
142                 g.fillrectangle(backbrush, this.bounds);
143                 backbrush.dispose();
144             }
145         }
146 
147         protected override void onpaint(painteventargs e)
148         {
149             // paint the background 
150             base.onpaint(e);
151             this.painttransparentbackground(e.graphics, this.clientrectangle);
152             this.paintallthetabs(e);
153             this.paintthetabpageborder(e);
154             this.painttheselectedtab(e);
155         }
156 
157         private void paintallthetabs(system.windows.forms.painteventargs e)
158         {
159             if (this.tabcount > 0)
160             {
161                 for (int index = 0; index < this.tabcount; index++)
162                 {
163                     this.painttab(e, index);
164                 }
165             }
166         }
167 
168         private void painttab(system.windows.forms.painteventargs e, int index)
169         {
170             graphicspath path = this.gettabpath(index);
171             this.painttabbackground(e.graphics, index, path);
172             this.painttabborder(e.graphics, index, path);
173             this.painttabtext(e.graphics, index);
174             this.painttabimage(e.graphics, index);
175         }
176 
177         /// <summary>
178         /// 设置选项卡头部颜色
179         /// </summary>
180         /// <param name="graph"></param>
181         /// <param name="index"></param>
182         /// <param name="path"></param>
183         private void painttabbackground(system.drawing.graphics graph, int index, system.drawing.drawing2d.graphicspath path)
184         {
185             rectangle rect = this.gettabrect(index);
186             system.drawing.brush buttonbrush = new system.drawing.drawing2d.lineargradientbrush(rect, _headerbackcolor, _headerbackcolor, lineargradientmode.vertical);  //非选中时候的 tabpage 页头部背景色
187             graph.fillpath(buttonbrush, path);
188             //if (index == this.selectedindex)
189             //{
190             //    //buttonbrush = new system.drawing.solidbrush(_headselectedbackcolor);
191             //    graph.drawline(new pen(_headerbackcolor), rect.right+2, rect.bottom, rect.left + 1, rect.bottom);
192             //}
193             buttonbrush.dispose();
194         }
195 
196         /// <summary>
197         /// 设置选项卡头部边框色
198         /// </summary>
199         /// <param name="graph"></param>
200         /// <param name="index"></param>
201         /// <param name="path"></param>
202         private void painttabborder(system.drawing.graphics graph, int index, system.drawing.drawing2d.graphicspath path)
203         {
204             pen borderpen = new pen(_bordercolor);// tabpage 非选中时候的 tabpage 头部边框色
205             if (index == this.selectedindex)
206             {
207                 borderpen = new pen(_headselectedbordercolor); // tabpage 选中后的 tabpage 头部边框色
208             }
209             graph.drawpath(borderpen, path);
210             borderpen.dispose();
211         }
212 
213         private void painttabimage(system.drawing.graphics g, int index)
214         {
215             image tabimage = null;
216             if (this.tabpages[index].imageindex > -1 && this.imagelist != null)
217             {
218                 tabimage = this.imagelist.images[this.tabpages[index].imageindex];
219             }
220             else if (this.tabpages[index].imagekey.trim().length > 0 && this.imagelist != null)
221             {
222                 tabimage = this.imagelist.images[this.tabpages[index].imagekey];
223             }
224             if (tabimage != null)
225             {
226                 rectangle rect = this.gettabrect(index);
227                 g.drawimage(tabimage, rect.right - rect.height - 4, 4, rect.height - 2, rect.height - 2);
228             }
229         }
230 
231         private void painttabtext(system.drawing.graphics graph, int index)
232         {
233             string tabtext = this.tabpages[index].text;
234 
235             system.drawing.stringformat format = new system.drawing.stringformat();
236             format.alignment = stringalignment.near;
237             format.linealignment = stringalignment.center;
238             format.trimming = stringtrimming.ellipsischaracter;
239 
240             brush forebrush = null;
241 
242             if (this.tabpages[index].enabled == false)
243             {
244                 forebrush = systembrushes.controldark;
245             }
246             else
247             {
248                 forebrush = systembrushes.controltext;
249             }
250 
251             font tabfont = this.font;
252             if (index == this.selectedindex)
253             {
254                 if (this.tabpages[index].enabled != false)
255                 {
256                     forebrush = new solidbrush(_headselectedbackcolor);
257                 }
258             }
259 
260             rectangle rect = this.gettabrect(index);
261 
262             var txtsize = controlhelper.getstringwidth(tabtext, graph, tabfont);
263             rectangle rect2 = new rectangle(rect.left + (rect.width - txtsize) / 2 - 1, rect.top, rect.width, rect.height);
264 
265             graph.drawstring(tabtext, tabfont, forebrush, rect2, format);
266         }
267 
268         /// <summary>
269         /// 设置 tabpage 内容页边框色
270         /// </summary>
271         /// <param name="e"></param>
272         private void paintthetabpageborder(system.windows.forms.painteventargs e)
273         {
274             if (this.tabcount > 0)
275             {
276                 rectangle borderrect = this.tabpages[0].bounds;
277                 //borderrect.inflate(1, 1);
278                 rectangle rect = new rectangle(borderrect.x - 2, borderrect.y - 1, borderrect.width + 5, borderrect.height + 2);
279                 controlpaint.drawborder(e.graphics, rect, this.bordercolor, buttonborderstyle.solid);
280             }
281         }
282 
283         /// <summary>
284         /// // tabpage 页头部间隔色
285         /// </summary>
286         /// <param name="e"></param>
287         private void painttheselectedtab(system.windows.forms.painteventargs e)
288         {
289             if (this.selectedindex == -1)
290                 return;
291             rectangle selrect;
292             int selrectright = 0;
293             selrect = this.gettabrect(this.selectedindex);
294             selrectright = selrect.right;
295             e.graphics.drawline(new pen(_headselectedbackcolor), selrect.left, selrect.bottom + 1, selrectright, selrect.bottom + 1);
296         }
297 
298         private graphicspath gettabpath(int index)
299         {
300             system.drawing.drawing2d.graphicspath path = new system.drawing.drawing2d.graphicspath();
301             path.reset();
302 
303             rectangle rect = this.gettabrect(index);
304 
305             switch (alignment)
306             {
307                 case tabalignment.top:
308 
309                     break;
310                 case tabalignment.bottom:
311 
312                     break;
313                 case tabalignment.left:
314 
315                     break;
316                 case tabalignment.right:
317 
318                     break;
319             }
320 
321             path.addline(rect.left, rect.top, rect.left, rect.bottom + 1);
322             path.addline(rect.left, rect.top, rect.right, rect.top);
323             path.addline(rect.right, rect.top, rect.right, rect.bottom + 1);
324             path.addline(rect.right, rect.bottom + 1, rect.left, rect.bottom + 1);
325 
326             return path;
327         }
328 
329         [dllimport("user32.dll")]
330         private static extern intptr sendmessage(intptr hwnd, int msg, intptr wparam, intptr lparam);
331 
332         private const int wm_setfont = 0x30;
333         private const int wm_fontchange = 0x1d;
334 
335         protected override void oncreatecontrol()
336         {
337             base.oncreatecontrol();
338             this.onfontchanged(eventargs.empty);
339         }
340 
341         protected override void onfontchanged(eventargs e)
342         {
343             base.onfontchanged(e);
344             intptr hfont = this.font.tohfont();
345             sendmessage(this.handle, wm_setfont, hfont, (intptr)(-1));
346             sendmessage(this.handle, wm_fontchange, intptr.zero, intptr.zero);
347             this.updatestyles();
348         }
349     }
350 }

 

用处及效果

最后的话

如果你喜欢的话,请到  点个星 星吧