派生所有者绘制的TabControl的双重缓冲问题
本文关键字:缓冲 问题 TabControl 所有者 绘制 派生 | 更新日期: 2023-09-27 17:48:49
我派生了一个TabControl,其明确目的是启用双缓冲,但没有任何功能按预期工作。这是TabControl代码:
class DoubleBufferedTabControl : TabControl
{
public DoubleBufferedTabControl() : base()
{
this.DoubleBuffered = true;
this.SetStyle
(
ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.ResizeRedraw |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.SupportsTransparentBackColor,
false
);
}
}
这个选项卡控件的绘制模式设置为"OwnerDrawnFixed",这样我就可以更改颜色。以下是自定义绘图方法:
private void Navigation_PageContent_DrawItem(object sender, DrawItemEventArgs e)
{
//Structure.
Graphics g = e.Graphics;
TabControl t = (TabControl)sender;
TabPage CurrentPage = t.TabPages[e.Index];
//Get the current tab
Rectangle CurrentTabRect = t.GetTabRect(e.Index);
//Get the last tab.
Rectangle LastTab = t.GetTabRect(t.TabPages.Count - 1);
//Main background rectangle.
Rectangle BackgroundRect = new Rectangle(LastTab.Width, t.Bounds.Y - 4, t.Width - (LastTab.Width), t.Height);
//Tab background rectangle.
Rectangle TabBackgroundRect = new Rectangle(0, LastTab.Y + LastTab.Height, LastTab.Width, t.Bounds.Height - (LastTab.Y + LastTab.Height));
//Set anitialiasing for the text.
e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
//String format for the text.
StringFormat StringFormat = new StringFormat();
StringFormat.Alignment = StringAlignment.Center;
StringFormat.LineAlignment = StringAlignment.Center;
//Fill the background.
g.FillRectangle(Brushes.LightGray, BackgroundRect);
g.FillRectangle(Brushes.Bisque, TabBackgroundRect);
//Draw the selected tab.
if(e.State == DrawItemState.Selected)
{
g.FillRectangle(Brushes.White, e.Bounds);
Rectangle SelectedTabOutline = new Rectangle(e.Bounds.X + 2, e.Bounds.Y + 2, e.Bounds.Width, e.Bounds.Height - 4);
g.DrawRectangle(new Pen(Brushes.LightGray, 4f), SelectedTabOutline);
g.DrawString(CurrentPage.Text, new Font("Arial", 12f, FontStyle.Bold, GraphicsUnit.Point), new SolidBrush(Color.FromArgb(70, 70, 70)), CurrentTabRect, StringFormat);
}
else
{
g.FillRectangle(new SolidBrush(Color.FromArgb(230, 230, 230)), e.Bounds);
g.DrawString(CurrentPage.Text, new Font("Arial", 12f, FontStyle.Regular, GraphicsUnit.Point), Brushes.Gray, CurrentTabRect, StringFormat);
}
}
然而,所有这些都无济于事,因为此控件不是双缓冲的,并且在调整大小时仍会闪烁。
有什么想法吗
如果你阅读文档,它会说,"这个成员对这个控件没有意义。"如果你想用双缓冲绘制控件,你必须自己实现它。此外,如果您的所有者绘制控件,那么无论如何您都必须自己实现双缓冲。
首先,您可以去掉TabControl
代码—你打开缓冲,然后立即关闭它,所以它实际上没有做任何有用的事情。
你的部分问题是你试图只画TabControl
的部分。
提供大约90%解决方案(仍然可能出现闪烁)的最简单解决方案是将其添加到表单类中:
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000;
return cp;
}
}
如果你想非常确信没有闪烁,你需要自己绘制整个TabControl
,并确保忽略背景绘制请求。
编辑:请注意,这只适用于XP及更高版本。
我过去在控件上遇到过双重缓冲的问题,停止闪烁的唯一方法是确保继承的OnPaintBackground方法没有被调用。(请参阅下面的代码)您还需要确保在喷漆过程中对整个背面进行喷漆。
protected override void OnPaintBackground( PaintEventArgs pevent )
{
//do not call base - I don't want the background re-painted!
}
不确定,但您可以尝试对包含选项卡控件的控件进行双重缓冲。
我环顾四周,尝试了你的代码和其他我能想到的东西,但我看不出有什么方法可以消除闪烁。不幸的是,在我的测试中,即使是一个常规的(非所有者绘制的)选项卡控件在调整大小时也会闪烁。
值得一提的是,关闭"拖动时显示窗口内容"会解决这个问题,但我意识到这可能没有帮助。
我认为它不起作用,因为您正在禁用双缓冲!
this.DoubleBuffered = true
所做的只是将ControlStyles.OptimizedDoubleBuffer设置为true。由于您在程序的下一行中禁用了该标志,因此您实际上什么也没做。删除ControlStyles.OptimizedDoubleBuffer(也许还有ControlStyle.AllPaintingInWmPaint),它应该对你有用。