最近开发WinForm频繁使用了TabControl控件,这个控件的选项卡没有BackgroundImage这个属性,那么如何为其各个选项卡添加背景图片呢?(这里说的是每个TabPage的头部,也就是标题,不是工作区域。)
最开始用到TabControl的时候,我的每个选项卡是写死的,而后由于项目需求又动态添加了TabControl并生成各个选项卡,而两次我都要重绘其标题,因此在这里把我当时两种情形下重绘的方法通过一个例子一起分享出来。
首先先在窗体拖个Tabcontrol控件,然后更改了其Alignment属性为Left,使其选项卡在左边。然后可以通过更改其ItemSize调节每个选项卡的大小。值得注意的是,因为在此是把TabControl向左旋转了90°,所以此时设置宽的时候实际上改变的是它的高,设置高的时候实际上改变的是它的宽。而且设置宽(改变高)发现无效是因为受选项卡文本字体所影响,可相应地改变字体尺寸。调整一番后的效果图:
接着就要进入正题重绘其选项卡背景了。首先要把它的DrawMode属性改为OwnerDrawFixed,改了这个才会让用户自己绘制标题生效。接着给它添加DrawItem事件。事件重绘方法如下:
1 private void tabMain_DrawItem(object sender, DrawItemEventArgs e) 2 { 3 Bitmap b0 = new Bitmap(@"..\..\Images\1.jpg"); 4 Bitmap b1 = new Bitmap(@"..\..\Images\2.jpg"); 5 Bitmap b2 = new Bitmap(@"..\..\Images\3.jpg"); 6 Bitmap b3 = new Bitmap(@"..\..\Images\4.jpg"); 7 switch (e.Index) 8 { 9 case 0: 10 e.Graphics.DrawImage(b0, e.Bounds); 11 break; 12 case 1: 13 e.Graphics.DrawImage(b1, e.Bounds); 14 break; 15 case 2: 16 e.Graphics.DrawImage(b2, e.Bounds); 17 break; 18 case 3: 19 e.Graphics.DrawImage(b3, e.Bounds); 20 break; 21 } 22 }
本文的图片我都事先放在当前项目下的一个Images文件夹里了。
最终效果图:
以上是写死的情况下为其重绘标题,现在来介绍当选项卡是动态生成时为其重绘标题的方法。在说明此之前,我们先为原有TabControl添加SelectedIndexChanged事件,通过获取其SelectedIndex从而知道哪个选项卡被点击了,在此,我在第二个选项卡里面动态添加另一个TabControl并生成其各个TabPage。代码如下:
1 private void tabMain_SelectedIndexChanged(object sender, EventArgs e) 2 { 3 switch (tabMain.SelectedIndex) 4 { 5 case 0: 6 break; 7 case 1: 8 //假设动态生成的TabControl有4个选项卡 9 for (int i = 0; i < 4; i++) 10 { 11 TabPage page = new TabPage(); 12 page.Name = "page" + i.ToString(); 13 page.Text = (i + 1).ToString(); 14 this.tabSub.Controls.Add(page); 15 } 16 this.tabSub.ItemSize = new System.Drawing.Size(80, 80); 17 this.tabSub.Font = new System.Drawing.Font("宋体", 20); 18 this.tabSub.Dock = DockStyle.Fill; 19 this.tabMain.TabPages[1].Controls.Add(tabSub); 20 break; 21 case 2: 22 break; 23 case 3: 24 break; 25 } 26 }
在外部预先定义好要生成的TabControl变量:
TabControl tabSub = new TabControl();
效果如下:
好了,接下来也该为它重绘下标题了。首先在上面设置tabSub属性的代码下新增这两行:
this.tabSub.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.tabSub_DrawItem);
this.tabSub.DrawMode = System.Windows.Forms.TabDrawMode.OwnerDrawFixed;
第一行是为tabSub新增绘制标题的事件,第二行是为了让系统使用我们自己绘制的样式。
然后自己写个绘制方法,代码如下:
1 private void tabSub_DrawItem(object sender, DrawItemEventArgs e) 2 { 3 List<string> imgPath = new List<string>() 4 { 5 @"..\..\Images\d.jpg", 6 @"..\..\Images\s.jpg", 7 @"..\..\Images\n.jpg", 8 @"..\..\Images\x.jpg" 9 }; 10 for (int i = 0; i < this.tabSub.TabCount; i++) 11 { 12 Bitmap b = new Bitmap(imgPath[i]); 13 if (e.Index == i) 14 { 15 e.Graphics.DrawImage(b, e.Bounds); 16 } 17 } 18 }
效果如下:
OK,至此大功告成。当然上述代码是有缺陷的,当你轮换左边选项卡最后又点到第二个选项卡时,它会再加载多一次,这个只需要在当初绘制的时候加个判断就行了,可以判断当前选项卡下是否已经包含了这些控件,或者定义个布尔变量用来判断是否已经加载就可以了。