¿Doble problema de almacenamiento en búfer de un TabControl derivado dibujado por el propietario?

StackOverflow https://stackoverflow.com/questions/223628

Pregunta

He derivado un TabControl con el propósito expreso de habilitar el búfer doble, excepto que nada funciona como se esperaba. Aquí está el código TabControl:

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

Este control de tabulación se configura con su modo de dibujo como 'OwnerDrawnFixed' para que pueda cambiar los colores. Aquí está el método de dibujo personalizado:

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

    }

Sin embargo, todo queda en vano, ya que este control no tiene doble búfer y aún parpadea cuando se cambia el tamaño.

¿Alguna idea?

¿Fue útil?

Solución

Si lees la documentación, dice, " Este miembro no es significativo para este control. " Si desea que el control se dibuje utilizando doble búfer, deberá implementarlo usted mismo. Además del hecho de que si el propietario dibuja el control, tendría que implementar el doble búfer de todos modos.

Otros consejos

En primer lugar, puede deshacerse de su código TabControl : puede activar el almacenamiento en búfer y, a continuación, desactivarlo inmediatamente, por lo que no está haciendo nada útil.

Parte de tu problema es que estás tratando de pintar solo parte del TabControl .

La solución más sencilla que ofrece aproximadamente un 90% (aún es posible obtener un parpadeo) es agregar esto a su clase de formulario:

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

Si desea estar muy seguro de no tener parpadeo, deberá dibujar todo el TabControl por sí mismo, y asegúrese de ignorar las solicitudes de pintura de fondo.

Editar: ten en cuenta que esto solo funcionará en XP y versiones posteriores.

En el pasado, he tenido problemas con el doble búfer en los controles y la única forma de detener el parpadeo era garantizar que no se llamara al método heredado de OnPaintBackground. (Vea el código a continuación) También deberá asegurarse de que todo el fondo esté pintado durante su llamada de pintura.

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

No estoy seguro, pero puede intentar duplicar el control que contiene el control de pestaña.

Miré un poco alrededor, probé tu código y cualquier otra cosa que pudiera pensar, pero no veo una manera de deshacerme del parpadeo. Desafortunadamente, en mis pruebas, incluso un control de pestañas regular (no dibujado por el propietario) parpadea durante el cambio de tamaño.

Para su valor, desactive " Mostrar contenido de la ventana mientras arrastra " Lo arreglaré, pero me doy cuenta de que puede no ser útil.

¡Creo que no funciona porque estás deshabilitando el búfer doble!

Todo this.DoubleBuffered = true hace que se establezca ControlStyles.OptimizedDoubleBuffer en true. Ya que está deshabilitando esa bandera en la siguiente línea de su programa, realmente no está haciendo nada. Elimine ControlStyles.OptimizedDoubleBuffer (y quizás ControlStyles.AllPaintingInWmPaint) y debería funcionar para usted.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top