2010-09-28 31 views
2

J'ai un problème avec le contrôle Label qui scintille terriblement.winforms Label scintillant

Voici un code pour reproduire le problème.

Comment résoudre ce problème? MISE À JOUR: La solution pour le cas précédent (un formulaire contient directement un libellé) consistait à créer la forme: DoubleBuffered = true. Mais ce n'est pas une solution générique. Par exemple, que dois-je faire dans le cas d'une étiquette dans un SplitContainer? c'est mon cas réel.

code mis à jour:

DoubleBufferedLabel.cs:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 

namespace FlickerLabelTest 
{ 
    public class DoubleBufferedLabel : Label 
    { 
     public DoubleBufferedLabel() 
     { 
      DoubleBuffered = true; 
     } 
    } 
} 

DoubleBufferedSplitContainer.cs:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 

namespace FlickerLabelTest 
{ 
    public class DoubleBufferedSplitContainer : SplitContainer 
    { 
     public DoubleBufferedSplitContainer() 
     { 
      DoubleBuffered = true; 
     } 
    } 
} 

Form1.cs:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 

namespace FlickerLabelTest 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void timer1_Tick(object sender, EventArgs e) 
     { 
      label1.Text += "0"; 
     } 
    } 
} 

Form1.Designer.cs:

namespace FlickerLabelTest 
{ 
    partial class Form1 
    { 
     /// <summary> 
     /// Required designer variable. 
     /// </summary> 
     private System.ComponentModel.IContainer components = null; 

     /// <summary> 
     /// Clean up any resources being used. 
     /// </summary> 
     /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> 
     protected override void Dispose(bool disposing) 
     { 
      if (disposing && (components != null)) 
      { 
       components.Dispose(); 
      } 
      base.Dispose(disposing); 
     } 

     #region Windows Form Designer generated code 

     /// <summary> 
     /// Required method for Designer support - do not modify 
     /// the contents of this method with the code editor. 
     /// </summary> 
     private void InitializeComponent() 
     { 
      this.components = new System.ComponentModel.Container(); 
      this.timer1 = new System.Windows.Forms.Timer(this.components); 
      this.label1 = new FlickerLabelTest.DoubleBufferedLabel(); 
      this.splitContainer1 = new DoubleBufferedSplitContainer(); 
      this.splitContainer1.Panel2.SuspendLayout(); 
      this.splitContainer1.SuspendLayout(); 
      this.SuspendLayout(); 
      // 
      // timer1 
      // 
      this.timer1.Enabled = true; 
      this.timer1.Interval = 1; 
      this.timer1.Tick += new System.EventHandler(this.timer1_Tick); 
      // 
      // label1 
      // 
      this.label1.Dock = System.Windows.Forms.DockStyle.Fill; 
      this.label1.Location = new System.Drawing.Point(0, 0); 
      this.label1.Name = "label1"; 
      this.label1.Size = new System.Drawing.Size(186, 262); 
      this.label1.TabIndex = 0; 
      this.label1.Text = "label1"; 
      // 
      // splitContainer1 
      // 
      this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; 
      this.splitContainer1.Location = new System.Drawing.Point(0, 0); 
      this.splitContainer1.Name = "splitContainer1"; 
      // 
      // splitContainer1.Panel2 
      // 
      this.splitContainer1.Panel2.Controls.Add(this.label1); 
      this.splitContainer1.Size = new System.Drawing.Size(284, 262); 
      this.splitContainer1.SplitterDistance = 94; 
      this.splitContainer1.TabIndex = 1; 
      // 
      // Form1 
      // 
      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 
      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 
      this.ClientSize = new System.Drawing.Size(284, 262); 
      this.Controls.Add(this.splitContainer1); 
      this.DoubleBuffered = true; 
      this.Name = "Form1"; 
      this.Text = "Form1"; 
      this.WindowState = System.Windows.Forms.FormWindowState.Maximized; 
      this.splitContainer1.Panel2.ResumeLayout(false); 
      this.splitContainer1.ResumeLayout(false); 
      this.ResumeLayout(false); 

     } 

     #endregion 

     private System.Windows.Forms.Timer timer1; 
     private DoubleBufferedLabel label1; 
     private DoubleBufferedSplitContainer splitContainer1; 
    } 
} 

Program.cs:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Windows.Forms; 

namespace FlickerLabelTest 
{ 
    static class Program 
    { 
     /// <summary> 
     /// The main entry point for the application. 
     /// </summary> 
     [STAThread] 
     static void Main() 
     { 
      Application.EnableVisualStyles(); 
      Application.SetCompatibleTextRenderingDefault(false); 
      Application.Run(new Form1()); 
     } 
    } 
} 

Répondre

10

Le problème est avec la station d'accueil. Si vous modifiez le Label.Dock de Fill à None, définissez manuellement la taille de l'étiquette pour remplir le panneau divisé, puis l'ancrer sur tous les côtés, il ne scintille pas.

Si vous voulez voir la cause du scintillement, alors que Dock est toujours mis à Fill, passer outre OnResize dans votre classe DoubleBufferedLabel, lancez l'application, et en cours d'exécution mis un point d'arrêt dans OnResize. Ajouter une montre pour le Size et vous verrez le basculer entre son temps de conception et les tailles d'exécution.

J'ai essayé d'utiliser un SplitContainer et Label régulièrement dans votre exemple, définissez DoubleBuffer à False sur la forme, et il ne clignote pas si je partais Dock ensemble à None sur le Label.

1

Pas vraiment une réponse, mais pourquoi voulez-vous mettre à jour votre étiquette chaque milliseconde? Si vous voulez dire 1 seconde, vous devez définir votre intervalle à 1000.

Vous pouvez résoudre ce problème en donnant au formulaire le temps de se redessiner et d'utiliser un intervalle plus grand.

Mise à jour: avéré, la mise en DoubleBuffered true résout le problème. Merci pour csharptest.net pour le signaler et DxCK pour me corriger.

+1

Le scintillement ne concerne pas l'intervalle de temporisation, c'est à propos de l'implémentation de la peinture. L'étiquette scintille même si je mets la minuterie à l'intervalle 1000, et c'est ennuyeux mes yeux. 1ms est pour la reproduction rapide. Un contrôle double-buffered normal ne clignotera pas même en taux de mise à jour 1ms. – DxCK

+0

Vous avez raison, mon erreur. J'ai oublié que DoubleBuffered est faux par défaut. –

0

Arrête le réglage des minuteurs à 1ms. Non sérieusement, ce que vous voyez ici, c'est que le Label essaie de suivre ses changements, mais ne le fait pas parce qu'ils sont fréquents. Ainsi, les solutions possibles sont:

  • Choisissez un moyen de changer l'étiquette moins souvent
  • Activer Double-buffering sur le formulaire
2

Collez ceci dans votre code de formulaire pour aider le Dock calculs de mise en page:

protected override void OnLoad(EventArgs e) { 
     label1.Size = this.ClientSize; 
     base.OnLoad(e); 
    } 
+0

Jusqu'à présent, votre solution est la meilleure, car elle est générique, elle fonctionne lorsque Label directement dans un formulaire, et même dans un SplitContainer. Pouvez-vous s'il vous plaît expliquer pourquoi résoudre le scintillement? Comment ça marche? – DxCK

0

Pourquoi ne pas exécuter votre fonction de mise à jour d'étiquette via un délégué asynchrone? Ou utilisez l'espace de noms System.Threading pour une saveur différente.

En outre, comme les gens avant moi mentionné, il serait utile si vous définissez la propriété DoubleBuffer sur votre formulaire à la vérité (ce n'est pas une balle d'argent cependant).

0

L'activation de la double mise en mémoire tampon sur le formulaire résoudra le problème. Mais c'est en fait une solution coûteuse. Si vous venez d'ajouter ce qui suit au formulaire:

SetStyle(ControlStyles.AllPaintingInWmPaint, true); 

le scintillement sera également terminé.

Le comportement par défaut du système d'exploitation Windows consiste à laisser toutes les fenêtres peindre leur arrière-plan et, plus tard, les laisser peindre. Cela remonte à l'époque où la peinture des lettres prenait beaucoup de temps. Ce drapeau lui dit de plier la peinture de fond et la peinture régulière (pour la même fenêtre) immédiatement après l'autre. La double mise en mémoire tampon peut être réservée aux cas où vous effectuez vous-même la peinture (lorsque vous surchargez OnPaint).