2015-02-09 37 views
2

我試圖通過循環在運行時winform中添加300個按鈕。這需要很長時間,所以我想在循環運行時顯示一個.gif加載圖像。 loading.gif只顯示,但不會動畫,直到循環結束。這是爲什麼?.gif在整個循環結束之前不會動畫?

pictureBox1.Load("loading.gif"); 
pictureBox1.Invalidate(); 
pictureBox1.Update(); 

// loop to add buttons 
this.SuspendLayout(); 
for (int i = 0; i < 300; i++) 
    // add buttons 
this.ResumeLayout(); 
this.PerformLayout(); 
+0

如果你註釋掉了添加按鈕的代碼,gif動畫呢? – Bijington 2015-02-09 10:10:11

+5

爲什麼你需要300個按鈕?也許有更好的解決方案? – JeffRSon 2015-02-09 10:29:09

+0

@Bijington是的,它會動畫 – Fish 2015-02-09 13:08:38

回答

4

該循環阻塞了UI線程,因此pictureBox1未更新。有幾種可能的解決方案:

醜陋的:在按鈕創建循環中偶爾使用Application.DoEvents();(即不是每一輪)。

或者你可以從一個計時器創建按鈕,10或20每隔直到你得到300

或者你可以使用一個基於線程閃屏時間。但是,重要的是,所有按鈕都是由UI線程創建的。

或找到一個不需要300個按鈕的更好的解決方案。

+0

Application.DoEvents()真的有用,非常感謝你 – Fish 2015-02-09 13:15:25

1

可以手動處理動畫事件。令人驚訝的是,OnFrameChanged事件仍然激發,使動畫成爲可能。

public class Form1 : Form { 

    Button btn = new Button { Text = "Button", Dock = DockStyle.Top }; 
    AsyncPictureBox box = new AsyncPictureBox("c:\\temp\\chick_dance.gif") { Dock = DockStyle.Fill }; 

    public Form1() { 
     Controls.Add(box); 
     Controls.Add(btn); 

     btn.Click += delegate { 
      box.AnimateImage = !box.AnimateImage; 
      Thread.Sleep(30000); 
     }; 
    } 
} 

public class AsyncPictureBox : Control { 

    Bitmap bitmap = null; 
    bool currentlyAnimating = false; 
    int frameCount = 0; 
    int frame = 0; 

    public AsyncPictureBox(String filename) { 
     bitmap = new Bitmap(filename); 
     this.DoubleBuffered = true; 
     frameCount = bitmap.GetFrameCount(System.Drawing.Imaging.FrameDimension.Time); 
    } 

    public bool AnimateImage { 
     get { 
      return currentlyAnimating; 
     } 

     set { 
      if (currentlyAnimating == value) 
       return; 

      currentlyAnimating = value; 
      if (value) 
       ImageAnimator.Animate(bitmap, OnFrameChanged); 
      else 
       ImageAnimator.StopAnimate(bitmap, OnFrameChanged); 
     } 
    } 

    // even though the UI thread is busy, this event is still fired 
    private void OnFrameChanged(object o, EventArgs e) { 
     Graphics g = this.CreateGraphics(); 
     g.Clear(this.BackColor); 
     bitmap.SelectActiveFrame(System.Drawing.Imaging.FrameDimension.Time, frame); 
     frame = (frame + 1) % frameCount; 
     g.DrawImage(bitmap, Point.Empty); 
     g.Dispose(); 
    } 

    protected override void Dispose(bool disposing) { 
     base.Dispose(disposing); 
     if (disposing) { 
      if (bitmap != null) 
       bitmap.Dispose(); 
      bitmap = null; 
     } 
    } 
}