派生自绘TabControl的双缓冲问题?

发布于 2024-07-08 09:00:46 字数 2828 浏览 3 评论 0原文

我派生了一个 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);
        }

    }

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

有什么想法吗?

I have derived a TabControl with the express purpose of enabling double buffering, except nothing is working as expected. Here is the TabControl code:

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

This Tabcontrol is then set with it's draw mode as 'OwnerDrawnFixed' so i can changed the colours. Here is the custom drawing method:

    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);
        }

    }

All to no avail however, as this control is not double buffered and still flickers when resized.

Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

稍尽春風 2024-07-15 09:00:46

如果您阅读文档,它会说:“此成员对此控件没有意义。” 如果您希望使用双缓冲绘制控件,则必须自己实现。 除此之外,如果您拥有所有者绘制控件,则无论如何您都必须自己实现双缓冲。

If you read the documentation, it says, "This member is not meaningful for this control." If you want the control to be drawn utilizing double-buffering, you'll have to implement it yourself. Besides the fact that if you owner-draw the control, you would have to implement double-buffering yourself anyhow.

七月上 2024-07-15 09:00:46

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

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

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

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

如果您想非常确定不会出现闪烁,您将需要自己绘制整个 TabControl ,并确保忽略背景绘制请求。

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

First of all, you can get rid of your TabControl code—you turn on buffering, and then immediately turn it off, so it's not actually doing anything useful.

Part of your problem is that you're trying to paint just part of the TabControl.

The easiest solution that gives about a 90% solution (it's still possible to get a flicker) is to add this to your form class:

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

If you want to be very sure of getting no flicker, you'll need to draw the entire TabControl yourself, and make sure to ignore background painting requests.

Edit: Note that this will only work in XP and later.

乖乖公主 2024-07-15 09:00:46

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

protected override void OnPaintBackground( PaintEventArgs pevent )
{
    //do not call base - I don't want the background re-painted!
}

I've had problems with double buffering on controls in the past and the only way to stop the flicker was to ensure the inherited OnPaintBackground method was not being called. (See code below) You will also need to ensure the entire backgound is painted during your paint call.

protected override void OnPaintBackground( PaintEventArgs pevent )
{
    //do not call base - I don't want the background re-painted!
}
谁人与我共长歌 2024-07-15 09:00:46

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

Not sure, but you might try double-buffering the control that contains the tab control.

我们只是彼此的过ke 2024-07-15 09:00:46

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

就其价值而言,关闭“拖动时显示窗口内容”可以解决此问题,但我意识到这可能没有帮助。

I looked around quite a bit, tried your code and whatever else I could think of, but I don't see a way to get rid of the flicker. Unfortunately, in my tests even a regular (non-owner-drawn) tab control flickers during resizing.

For what it's worth, turning off "Show window contents while dragging" will fix it, but I realize that may not be helpful.

穿透光 2024-07-15 09:00:46

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

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

I think it doesn't work because you are disabling double buffering!

All this.DoubleBuffered = true does is set ControlStyles.OptimizedDoubleBuffer to true. Since you are disabling that flag in the next line of your program, you are really doing nothing. Remove ControlStyles.OptimizedDoubleBuffer (and perhaps ControlStyles.AllPaintingInWmPaint) and it should work for you.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文