2011-01-14 62 views
11

我正在製作一個程序,其中面板中有很多面板和麪板。爲什麼我的WinForms控件閃爍並緩慢調整大小?

我在這些面板中有幾個自定義繪製控件。

1面板的調整大小功能包含調整該面板中所有控件大小和位置的代碼。

現在只要我調整程序的大小,此面板的大小調整就會激活。這導致該面板中組件的閃爍很多。

所有用戶繪製的控件都是雙緩衝的。

有人能幫我解決這個問題嗎?

+0

如果我沒有退出投票,我會投票關閉這個問題作爲這個問題的副本:[Winforms Double Buffering](http://support.microsoft.com/kb/3718380/winforms-double -buffering)。所以這裏是免費的。 – 2011-01-14 11:19:27

+0

@Cody Gray - 我不同意!問題可能類似,但您發送的鏈接下提供的答案是完全錯誤/不好的,因爲它會導致很多副作用。 – HABJAN 2011-01-14 11:51:15

+0

@HABJAN:你能告訴我一些這些副作用嗎? – 2011-01-14 11:52:39

回答

1

也許一個很好的解決方案將是使用Form.ResizeBeginForm.ResizeEnd事件。

On ResizeBegin將主面板可見性設置爲false,在ResizeEnd上將主面板可見性設置爲true。

這種方式面板將不會重繪,而有人正在調整您的表單。

17

看看您發佈的項目,當您選擇第一個選項卡並使用漸變填充組框時,閃爍效果非常差。顯示第二個或第三個標籤時,幾乎沒有任何閃爍。

    Your main form

所以很明顯的問題,有事情做與你可見標籤頁上的控件。快速瀏覽一下自定義漸變填充組框類的代碼可以提供更具體的原因。每次繪製其中一個groupbox控件時,您正在執行一個處理成本非常高的lot因爲每個 groupbox控件每次重新調整窗體大小時都必須重新繪製自己,代碼的執行次數令人難以置信。

另外,你有控制的背景設置爲‘透明’,其中有通過詢問父窗口先畫本身的控制窗口內產生的背景像素的WinForms爲僞造。然後控制器就會自動完成。這比使用像SystemColors.Control這樣的純色來填充控件的背景還要多,並且在組框有機會繪製自己之前,它會導致您在調整窗體大小時看到表單的像素被繪製。

下面是我從您的自定義的漸變填充組框控件類談論的具體代碼:

protected override void OnPaint(PaintEventArgs e) 
{ 
    if (Visible) 
    { 
     Graphics gr = e.Graphics; 
     Rectangle clipRectangle = new Rectangle(new Point(0, 0), this.Size); 
     Size tSize = TextRenderer.MeasureText(Text, this.Font); 
     Rectangle r1 = new Rectangle(0, (tSize.Height/2), Width - 2, Height - tSize.Height/2 - 2); 
     Rectangle r2 = new Rectangle(0, 0, Width, Height); 
     Rectangle textRect = new Rectangle(6, 0, tSize.Width, tSize.Height); 

     GraphicsPath gp = new GraphicsPath(); 
     gp.AddRectangle(r2); 
     gp.AddRectangle(r1); 
     gp.FillMode = FillMode.Alternate; 

     gr.FillRectangle(new SolidBrush(Parent.BackColor), clipRectangle); 

     LinearGradientBrush gradBrush; 
     gradBrush = new LinearGradientBrush(clipRectangle, SystemColors.GradientInactiveCaption, SystemColors.InactiveCaptionText, LinearGradientMode.BackwardDiagonal); 
     gr.FillPath(gradBrush, RoundedRectangle.Create(r1, 7)); 

     Pen borderPen = new Pen(BorderColor); 
     gr.DrawPath(borderPen, RoundedRectangle.Create(r1, 7)); 
     gr.FillRectangle(gradBrush, textRect); 
     gr.DrawRectangle(borderPen, textRect); 
     gr.DrawString(Text, base.Font, new SolidBrush(ForeColor), 6, 0); 
    } 

} 

protected override void OnPaintBackground(PaintEventArgs pevent) 
{ 
    if (this.BackColor == Color.Transparent) 
     base.OnPaintBackground(pevent); 
} 

而現在,你已經看到了代碼,紅色警告標誌應該上去。 你正在創建一個GDI +對象(刷子,筆,區域等)的,但沒有Dispose其中任何一個!幾乎所有的代碼應該包含在using聲明中。這只是草率的編碼。

做所有這些工作都會花費一些東西。當計算機被迫投入太多時間來渲染控制時,其他事情就會落後。你看到一個閃爍,因爲它緊跟着調整大小。這與其他任何超載計算機沒有什麼不同(比如計算pi的值),當你使用像你這樣的許多自定義繪製控件時,這很容易實現。透明度在Win32中很難,很多自定義3D繪畫也是如此。它使用戶界面看起來感覺笨重。還有一個原因,我不明白從本地控制趕走。

你真的只有三種選擇:

  1. 處理閃爍。 (我同意,這不是一個好的選擇。)
  2. 使用不同的控件,如標準的內置控件。當然,他們可能沒有花哨的漸變效果,但是如果用戶定製了他們的Windows主題,那麼在一半時間內看起來就會失效。在深灰色的背景上閱讀黑色文本也是相當困難的。
  3. 更改自定義控件中的繪畫代碼以減少工作量。你或許可以通過一些簡單的「優化」來獲得,這些優化不會讓你感到任何視覺效果,但我懷疑這是不太可能的。這是速度和眼睛糖果之間的折衷。無所事事總是更快。
1

雖然掛接到ResizeBegin和ResizeEnd是正確的想法,而不是隱藏主面板的可見性,我會延遲任何調整大小的計算,直到ResizeEnd。在這種情況下,你甚至不需要鉤入ResizeBegin或Resize - 所有的邏輯都進入ResizeEnd。

我這樣說有兩個原因。一,即使面板被隱藏,調整大小操作可能仍然是昂貴的,所以除非調整大小計算被延遲,否則表單不會像它應該那樣響應。二,在調整大小的同時隱藏窗格的內容可能會讓用戶感到震驚。

2

使用此代碼調整窗體大小時,我成功消除了閃爍。謝謝。

VB.NET

Public Class Form1 

Public Sub New() 
    Me.SetStyle(ControlStyles.UserPaint Or ControlStyles.OptimizedDoubleBuffer Or ControlStyles.AllPaintingInWmPaint Or ControlStyles.SupportsTransparentBackColor, True) 
End Sub 

Private Sub Form1_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Resize 
    Me.Update() 
End Sub 

End Class 

C#

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
     Resize += Form1_Resize; 
     this.SetStyle(ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.SupportsTransparentBackColor, true); 
    } 

    private void Form1_Resize(object sender, System.EventArgs e) 
    { 
     this.Update(); 
    } 

} 
16

而調整的雙贏形式要擺脫閃爍,暫停佈局,同時調整。如下所示覆蓋表單resizebegin/resizeend方法。

protected override void OnResizeBegin(EventArgs e) { 
    SuspendLayout(); 
    base.OnResizeBegin(e); 
} 
protected override void OnResizeEnd(EventArgs e) { 
    ResumeLayout(); 
    base.OnResizeEnd(e); 
} 

這將使控制完整的(因爲他們之前調整位置),並強制重繪完成調整操作時。

2

所以我就遇到了這個同樣的問題 - 我有一個透明背景的控制被重新粉刷像34次,什麼工作對我來說是:

在我的形式包含控制

protected override void OnResize(EventArgs e) 
    { 
     myControl.Visible = false; 
     base.OnResize(e); 
     myControl.Visible = true; 
    } 

而且在控制是相同的:

protected override void OnResize(EventArgs e) 
    { 
     this.Visible = false; 
     base.OnResize(e); 
     this.Visible = true; 
    } 

這種減小重繪至4中的量,這有效地消除了任何閃爍被調整大小的控制時。

0

我有同樣的問題。

它接縫,這種情況是因爲您使用的圓角。當我將CornerRadius屬性設置爲0時,閃爍消失了。

到目前爲止,我只找到了以下解決方法。不是最好的,但它停止閃爍。

private void Form_ResizeBegin(object sender, EventArgs e) 
{ 
    rectangleShape.CornerRadius = 0; 
} 

private void Form_ResizeEnd(object sender, EventArgs e) 
{ 
    rectangleShape.CornerRadius = 15; 
}