Pregunta

En mi solicitud estoy en constante movimiento de un control a otro. No he creado. de controles de usuario, pero durante la navegación mis controles obtiene el parpadeo. Se tarda 1 o 2 segundos para actualización. Traté de establecer este

SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
or
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true); 
SetStyle(ControlStyles.DoubleBuffer, true);

pero no ayudó ... Cada control tiene la misma imagen de fondo con diferentes controles. Entonces, ¿cuál es la solución para ello .. Gracias
.

¿Fue útil?

Solución

No es el tipo de parpadeo que el búfer doble puede resolver. Tampoco BeginUpdate o SuspendLayout. Tienes demasiados controles, la BackgroundImage puede hacer que sea un mucho peor.

Se inicia cuando el control de usuario se pinta. Se señala a la BackgroundImage, dejando agujeros en las ventanas de control del niño van. Cada control secundario a continuación, recibe un mensaje de pintar en sí, que van a rellenar el agujero con su contenido de la ventana. Cuando se tiene una gran cantidad de controles, esos agujeros son visibles para el usuario por un tiempo. Son normalmente blanca, que contrasta con el mal BackgroundImage cuando está oscuro. O pueden ser de color negro si el formulario tiene su conjunto Opacidad o TransparencyKey propiedad, lo que contrasta mal con casi cualquier cosa.

Esta es una limitación bastante fundamental de las formas de Windows, que se ha quedado atascado con la forma en que Windows hace que las ventanas. Fijado por WPF por cierto, que no utiliza las ventanas de los controles secundarios. Lo que se desea es de doble amortiguar el formulario completo, incluyendo los controles secundarios. Eso es posible, comprobar mi código en este hilo para la solución. Tiene efectos secundarios sin embargo, y no aumenta realmente la pintura velocidad. El código es simple, pegue esto en su forma (no el control de usuario):

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

Hay muchas cosas que puede hacer para mejorar la velocidad de la pintura, hasta el punto de que el parpadeo no se nota más. Comience por hacer frente a la BackgroundImage. Pueden ser realmente caro cuando la imagen de origen es grande y tiene que ser reducido para adaptarlas al control. Cambie la propiedad BackgroundImageLayout para "Teja". Si eso le da una aceleración notable, volver a su programa de pintura y cambiar el tamaño de la imagen para que sea una mejor correspondencia con el tamaño típico de control. O escribir código en el método de la UC OnResize () para crear una copia de tamaño apropiado de la imagen para que no tenga que cambiar de tamaño cada vez que se vuelve a dibujar de control. Utilice el formato de píxel Format32bppPArgb para esa copia, que hace aproximadamente 10 veces más rápido que cualquier otro formato de píxel.

La siguiente cosa que puede hacer es evitar que los orificios de ser tan notable y contrastar mal con la imagen. Puede desactivar la bandera de estilo WS_CLIPCHILDREN para la UC, la bandera que impide que la UC de pintura en la zona donde van los controles secundarios. Pega este código en el código del control de usuario:

protected override CreateParams CreateParams {
  get {
    var parms = base.CreateParams;
    parms.Style &= ~0x02000000;  // Turn off WS_CLIPCHILDREN
    return parms;
  }
}

Los controles secundarios ahora se pintan en la parte superior de la imagen de fondo. Es posible que aún verlos pintan de uno por uno, pero el agujero blanco o negro intermedia fea no serán visibles.

Por último, pero no menos importante, reducir el número de controles secundarios es siempre un buen enfoque para resolver problemas de dibujo lentas. Anular el caso de la UC OnPaint () y dibujar lo que ahora se muestra en un niño. Etiqueta y en particular cuadro de imagen son muy derrochador. Conveniente para apuntar y hacer clic, pero su alternativa de peso ligero (dibujar una cadena o una imagen) realiza solamente una sola línea de código en el método de OnPaint ().

Otros consejos

Este es un problema real, y la respuesta Hans Passant dio es grande para guardar el parpadeo. Sin embargo, hay efectos secundarios como él menciona, y pueden ser feo (IU feo). Como se ha dicho, "Se puede desactivar la bandera de estilo WS_CLIPCHILDREN para la UC", sino que sólo lo apaga para una UC. Los componentes en el formulario principal todavía tienen problemas.

ejemplo, una barra de desplazamiento del panel no pintar, porque es técnicamente en la zona infantil. Sin embargo, el componente secundario no dibuja la barra de desplazamiento, por lo que no consigue pintado hasta ratón sobre (o por un determinado evento it).

Además, iconos animados (iconos que cambian en un bucle de espera) no funciona. La eliminación de los iconos en una tabPage.ImageKey no cambia de tamaño / repintar los otros TabPages adecuadamente.

Así que yo estaba buscando una manera de apagar el WS_CLIPCHILDREN en la pintura inicial por lo que mi formulario se carga bien pintada, o mejor aún, sólo se enciendo mientras cambia el tamaño de mi formulario con una gran cantidad de componentes.

El truco es conseguir que la aplicación llame CreateParams con el estilo WS_EX_COMPOSITED / WS_CLIPCHILDREN deseada? He encontrado un hack aquí ( http://www.angryhacker.com/blog/archive/2010/07/21/how-to-get-rid-of-flicker-on-windows-forms-applications.aspx ) y funciona muy bien. Gracias AngryHacker!

Me puso la llamada TurnOnFormLevelDoubleBuffering () en el evento de formulario ResizeBegin. TurnOffFormLevelDoubleBuffering () en el evento de formulario ResizeEnd (o simplemente dejarlo WS_CLIPCHILDREN después de que se pintó inicialmente correctamente.)

    int originalExStyle = -1;
    bool enableFormLevelDoubleBuffering = true;

    protected override CreateParams CreateParams
    {
        get
        {
            if (originalExStyle == -1)
                originalExStyle = base.CreateParams.ExStyle;

            CreateParams cp = base.CreateParams;
            if (enableFormLevelDoubleBuffering)
                cp.ExStyle |= 0x02000000;   // WS_EX_COMPOSITED
            else
                cp.ExStyle = originalExStyle;

            return cp;
        }
    }

    public void TurnOffFormLevelDoubleBuffering()
    {
        enableFormLevelDoubleBuffering = false;
        this.MaximizeBox = true;
    }

Si usted está haciendo ninguna costumbre de pintar en el control (es decir primordial OnPaint), puede intentar el doble buffer mismo.

Image image;
protected override OnPaint(...) {
    if (image == null || needRepaint) {
        image = new Bitmap(Width, Height);
        using (Graphics g = Graphics.FromImage(image)) {
            // do any painting in image instead of control
        }
        needRepaint = false;
    }
    e.Graphics.DrawImage(image, 0, 0);
}

e invalidar su control con una propiedad NeedRepaint

De lo contrario la respuesta anterior con SuspendLayout y ResumeLayout es probablemente lo que quiere.

En el formulario principal o control de usuario, donde reside la imagen de fondo establecen la propiedad BackgroundImageLayout a Center o Stretch. Usted notará una gran diferencia cuando el control de usuario está prestando.

He intentado añadir esto como un comentario, pero no tengo suficientes puntos. Esto es lo único que alguna vez ayudó a mis problemas de parpadeo tantos gracias a Hans para su puesto. Para cualquier persona que está usando C ++ Builder, como yo, aquí está la traducción

Añadir la declaración CreateParams al archivo principal de la aplicación forma .h por ejemplo.

class TYourMainFrom : public TForm
{
protected:
    virtual void __fastcall CreateParams(TCreateParams &Params);
}

y añadir esto a su archivo .cpp

void __fastcall TYourMainForm::CreateParams(TCreateParams &Params)
{
    Params.ExStyle |= 0x02000000;  // Turn on WS_EX_COMPOSITED
    TForm::CreateParams(Params);
}

Ponga el código de abajo en su constructor o evento OnLoad y si usted está usando algún tipo de control de usuario personalizado que tener controles sub, tendrá que asegurarse de que estos controles personalizados también se almacenan doble (a pesar de que en la EM documentación que dicen que está establecido en true por defecto).

Si estás haciendo un control personalizado, es posible que desee añadir esta bandera en su ctor:

SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

Opcionalmente se puede utilizar este código en su Formulario / control:

foreach (Control control in Controls)
{
    typeof(Control).InvokeMember("DoubleBuffered",
        BindingFlags.SetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
        null, control, new object[] { true });
}

iteración a través de todos los controles en el formulario / control y el acceso a su propiedad DoubleBuffered y luego cambiarlo por cierto con el fin de hacer que cada control en el formulario de doble buffer. La razón por la que hacemos la reflexión aquí, es porque imagine que tiene un control que tiene controles secundarios que no son accesibles, de esa manera, incluso si son controles privados, que todavía van a cambiar su propiedad en true.

Más información sobre la técnica de doble búfer se puede encontrar aquí .

Hay otra propiedad que normalmente tienen preferencia para ordenar este problema:

protected override CreateParams CreateParams
{
    get
    {
        CreateParams parms = base.CreateParams;
        parms.ExStyle |= 0x00000020; // WS_EX_COMPOSITED
        return parms;
    }
}

WS_EX_COMPOSITED - Pinturas. Todos los descendientes de una ventana con el fin de abajo hacia arriba se pinta con doble búfer

Se puede encontrar más de estos indicadores de estilo aquí .

Espero que ayude!

Sólo para añadir a la respuesta Hans dio:

(versión TLDR: La transparencia es más pesado de lo que cree, utilice sólo colores sólidos en todas partes)

Si WS_EX_COMPOSITED, DoubleBuffered y WS_CLIPCHILDREN no ha solucionado el parpadeo (para mí WS_CLIPCHILDREN lo hizo aún peor), intente esto: pasar por todos los controles y todo el código, y siempre que tengas Cualquier transparencia o semi-transparencia para BackColor, ForeColor, o cualquier otro color, simplemente eliminarlo, utilizan colores sólidos solamente. En la mayoría de los casos en los que cree que acaba de Tienes para usar la transparencia, que no lo hacen. Re-diseño de su código y controles, y el uso de colores sólidos. Tenía terribles terribles parpadeo, y el programa estaba corriendo lento. Una vez me quita la transparencia se aceleró de manera significativa, y no es 0 parpadeo.

EDIT: Para añadir aún más, acabo de descubrir que WS_EX_COMPOSITED no tiene por qué ser la ventana de ancho, se podría aplicar sólo para controles específicos! Esto me salvó un montón de problemas. Sólo hacer un control personalizado heredado de cualquiera que sea el control que necesita, y pegar la anulación ya publicado por WS_EX_COMPOSITED. De esta manera se obtiene de bajo nivel doble búfer en este control solamente, evitando los efectos secundarios desagradables en el resto de la aplicación!

Sé que esta pregunta es muy viejo, pero quiero dar mi experiencia en ella.

Yo tenía un montón de problemas con el parpadeo Tabcontrol en un formulario con OnPaint y / o OnPaintBackGround overrided en Windows 8 utilizando .NET 4.0.

El único piensan que trabajado ha sido NO USO el método Graphics.DrawImage en las anulaciones OnPaint, en otras palabras, cuando sorteo se realiza directamente a la gráfica proporcionada por el PaintEventArgs, incluso la pintura de todo el rectángulo, el parpadeo desaparecido. Pero si la llamada al método DrawImage, incluso dibujar un mapa de bits recortado, (creado por el doble buffer) que aparezca parpadeo.

Hope que ayuda!

I combinado esta revisión parpadeo y esta revisión de la fuente , entonces he tenido que añadir un poco de mi propio código para iniciar un temporizador en la pintura para invalidar la TabControl cuando se va fuera de la pantalla y la espalda, etc ..

Los tres hacen esto:

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class TabControlEx:TabControl
{
    [DllImport("user32.dll")]
    private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
    private const int WM_PAINT = 0x0f;
    private const int WM_SETFONT = 0x30;
    private const int WM_FONTCHANGE = 0x1d;
    private System.Drawing.Bitmap buffer;
    private Timer timer = new Timer();
    public TabControlEx()
    {
        timer.Interval = 1;
        timer.Tick += timer_Tick;
        this.SetStyle(ControlStyles.UserPaint | ControlStyles.DoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
    }
    void timer_Tick(object sender, EventArgs e)
    {
        this.Invalidate();
        this.Update();
        timer.Stop();
    }
    protected override void WndProc(ref Message m)
    {
        if (m.Msg == WM_PAINT) timer.Start();
        base.WndProc(ref m);
    }
    protected override void OnPaint(PaintEventArgs pevent)
    {
        this.SetStyle(ControlStyles.UserPaint, false);
        base.OnPaint(pevent);
        System.Drawing.Rectangle o = pevent.ClipRectangle;
        System.Drawing.Graphics.FromImage(buffer).Clear(System.Drawing.SystemColors.Control);
        if (o.Width > 0 && o.Height > 0)
        DrawToBitmap(buffer, new System.Drawing.Rectangle(0, 0, Width, o.Height));
        pevent.Graphics.DrawImageUnscaled(buffer, 0, 0);
        this.SetStyle(ControlStyles.UserPaint, true);
    }

    protected override void OnResize(EventArgs e)
    {
        base.OnResize(e);
        buffer = new System.Drawing.Bitmap(Width, Height);
    }
    protected override void OnCreateControl()
    {
        base.OnCreateControl();
        this.OnFontChanged(EventArgs.Empty);
    }
    protected override void OnFontChanged(EventArgs e)
    {
        base.OnFontChanged(e);
        IntPtr hFont = this.Font.ToHfont();
        SendMessage(this.Handle, WM_SETFONT, hFont, (IntPtr)(-1));
        SendMessage(this.Handle, WM_FONTCHANGE, IntPtr.Zero, IntPtr.Zero);
        this.UpdateStyles();
    }
}

No soy el creador, pero por lo que entiendo el mapa de bits hace todo el fallo derivación.

Esta fue la única cosa que definitivamente resuelto TabControl (con iconos) parpadeo para mí.

Video en consecuencia diferencia: vainilla tabcontrol vs tabcontrolex

http://gfycat.com/FineGlitteringDeermouse

ps. tendrá que establecer HotTrack = true, ya que corrige este error que también

¿Usted intentó Control.DoubleBuffered propiedad?

  

Obtiene o establece un valor que indica si este control debe volver a dibujar su superficie usando un tampón secundario para reducir o prevenir el parpadeo.

este y esta ayuda fuerzas.

No hay necesidad de cualquier Doblebuffering y todo lo que los chicos cosas ...

Una solución simple ...

Si está utilizando la interfaz MDI, basta con pegar el código de abajo en el formulario principal. Se eliminará todo el parpadeo de las páginas. Sin embargo, algunas páginas que requieren más tiempo para la carga se showup en 1 o 2 segundos. Pero esto es mejor que muestra una hoja en el parpadeo en la que cada artículo viene uno por uno.

Esta es la única mejor solución para toda la aplicación. Ver el código para poner en la forma principal:

protected override CreateParams CreateParams {
  get {
    CreateParams cp = base.CreateParams;
    cp.ExStyle |= 0x02000000;  // Turn on WS_EX_COMPOSITED
    return cp;
  }
} 
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top