WinForms自定义TabPage时自绘模式下ImageList图片无法显示问题
问题原因
你的自绘逻辑中完全没有添加ImageList的绘制代码,同时原代码存在GDI资源未释放、重绘区域未适配图片的问题,这是导致图片不显示、标签闪烁的核心原因。
修复步骤
前置配置
- 确认TabControl的
ImageList属性已经绑定目标ImageList控件,且每个TabPage都正确设置了ImageIndex或ImageKey属性。 - 开启TabControl双缓冲解决闪烁问题,在窗体构造函数的
InitializeComponent()调用后添加如下代码:
// 反射开启TabControl内置双缓冲 typeof(TabControl).InvokeMember("DoubleBuffered", System.Reflection.BindingFlags.SetProperty | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic, null, tabControl1, new object[] { true });
替换DrawItem事件代码
修正后的完整代码已经加入图片绘制逻辑、资源释放逻辑,同时预留了图片和文字的间距避免重叠:
private void tabControl1_DrawItem(object sender, DrawItemEventArgs e) { Graphics g = e.Graphics; Brush textBrush; TabPage tabPage = tabControl1.TabPages[e.Index]; Rectangle tabBounds = tabControl1.GetTabRect(e.Index); // 绘制标签背景 if (e.State == DrawItemState.Selected) { textBrush = new SolidBrush(Color.Red); g.FillRectangle(Brushes.Gray, e.Bounds); } else { textBrush = new SolidBrush(e.ForeColor); e.DrawBackground(); } // 绘制ImageList对应的图片 if (tabControl1.ImageList != null && tabPage.ImageIndex >= 0) { Image targetImg = tabControl1.ImageList.Images[tabPage.ImageIndex]; // 计算图片垂直居中的位置,左侧留4px边距 Point imgLocation = new Point( tabBounds.Left + 4, tabBounds.Top + (tabBounds.Height - targetImg.Height) / 2 ); g.DrawImageUnscaled(targetImg, imgLocation); } // 调整文字绘制区域,预留图片宽度避免重叠 Rectangle textBounds = tabBounds; textBounds.X -= 8; using (Font tabFont = new Font("Arial", 14.0f, FontStyle.Bold, GraphicsUnit.Pixel)) { StringFormat stringFlags = new StringFormat { Alignment = StringAlignment.Far, LineAlignment = StringAlignment.Center }; g.DrawString(tabPage.Text, tabFont, textBrush, textBounds, stringFlags); } // 释放Brush资源,避免GDI泄漏 textBrush.Dispose(); }
补充说明
- 如果你使用
ImageKey而非ImageIndex绑定图片,只需要将图片绘制部分的判断逻辑改为判断!string.IsNullOrEmpty(tabPage.ImageKey),再通过tabControl1.ImageList.Images[tabPage.ImageKey]取值即可。 - 代码中的边距数值可以根据你的ImageList图片尺寸、样式需求自行调整。
- 所有GDI对象用完必须释放,否则会出现偶发绘制异常、内存占用持续升高的问题。
内容的提问来源于stack exchange,提问作者xKara
相关产品推荐
相关产品推荐

