2

我已经派生了一个 TabControl,其明确目的是启用双缓冲,除了没有按预期工作。这是 TabControl 代码:

class DoubleBufferedTabControl : TabControl
{
    public DoubleBufferedTabControl() : base()
    {
        this.DoubleBuffered = true;
        this.SetStyle
            (
                ControlStyles.UserPaint |
                ControlStyles.AllPaintingInWmPaint |
                ControlStyles.ResizeRedraw |
                ControlStyles.OptimizedDoubleBuffer |
                ControlStyles.SupportsTransparentBackColor,
                false
            );
    }
}

然后将此 Tabcontrol 的绘制模式设置为“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);
        }

    }

然而,一切都无济于事,因为这个控件不是双缓冲的,并且在调整大小时仍然会闪烁。

有任何想法吗?

4

6 回答 6

2

如果您阅读文档,它会说,“此成员对于此控件没有意义。” 如果您希望使用双缓冲来绘制控件,则必须自己实现它。除了如果您拥有控件,您将不得不自己实现双缓冲这一事实。

于 2008-10-23T00:03:39.263 回答
2

首先,您可以摆脱您的TabControl代码——您打开缓冲,然后立即将其关闭,因此它实际上并没有做任何有用的事情。

您的部分问题是您试图仅绘制TabControl.

提供大约 90% 解决方案的最简单解决方案(仍然可能会出现闪烁)是将其添加到您的表单类中:

protected override CreateParams CreateParams
{
    get
    {
        CreateParams cp = base.CreateParams;
        cp.ExStyle |= 0x02000000;
        return cp;
    }
}

如果您想非常确定没有闪烁,则需要自己绘制整个画面TabControl,并确保忽略背景绘制请求。

编辑:请注意,这仅适用于 XP 及更高版本。

于 2008-11-10T19:53:32.433 回答
1

过去,我在控件上遇到了双重缓冲问题,而停止闪烁的唯一方法是确保不调用继承的 OnPaintBackground 方法。(参见下面的代码)您还需要确保在您的绘制调用期间绘制整个背景。

protected override void OnPaintBackground( PaintEventArgs pevent )
{
    //do not call base - I don't want the background re-painted!
}
于 2008-11-19T17:48:02.643 回答
0

不确定,但您可以尝试对包含选项卡控件的控件进行双缓冲。

于 2008-10-21T22:00:30.903 回答
0

我环顾四周,尝试了您的代码以及我能想到的任何其他方法,但我看不到消除闪烁的方法。不幸的是,在我的测试中,即使是常规的(非所有者绘制的)选项卡控件在调整大小时也会闪烁。

对于它的价值,关闭“拖动时显示窗口内容”将修复它,但我意识到这可能没有帮助。

于 2008-10-22T03:49:09.187 回答
0

我认为它不起作用,因为您禁用了双缓冲!

所做this.DoubleBuffered = true的只是将 ControlStyles.OptimizedDoubleBuffer 设置为 true。由于您在程序的下一行禁用了该标志,因此您实际上什么也没做。删除 ControlStyles.OptimizedDoubleBuffer(也许还有 ControlStyles.AllPaintingInWmPaint),它应该适合你。

于 2008-11-10T13:43:56.267 回答