我正在製作一個程序,其中面板中有很多面板和麪板。爲什麼我的WinForms控件閃爍並緩慢調整大小?
我在這些面板中有幾個自定義繪製控件。
1面板的調整大小功能包含調整該面板中所有控件大小和位置的代碼。
現在只要我調整程序的大小,此面板的大小調整就會激活。這導致該面板中組件的閃爍很多。
所有用戶繪製的控件都是雙緩衝的。
有人能幫我解決這個問題嗎?
我正在製作一個程序,其中面板中有很多面板和麪板。爲什麼我的WinForms控件閃爍並緩慢調整大小?
我在這些面板中有幾個自定義繪製控件。
1面板的調整大小功能包含調整該面板中所有控件大小和位置的代碼。
現在只要我調整程序的大小,此面板的大小調整就會激活。這導致該面板中組件的閃爍很多。
所有用戶繪製的控件都是雙緩衝的。
有人能幫我解決這個問題嗎?
也許一個很好的解決方案將是使用Form.ResizeBegin和Form.ResizeEnd事件。
On ResizeBegin將主面板可見性設置爲false,在ResizeEnd上將主面板可見性設置爲true。
這種方式面板將不會重繪,而有人正在調整您的表單。
看看您發佈的項目,當您選擇第一個選項卡並使用漸變填充組框時,閃爍效果非常差。顯示第二個或第三個標籤時,幾乎沒有任何閃爍。
所以很明顯的問題,有事情做與你可見標籤頁上的控件。快速瀏覽一下自定義漸變填充組框類的代碼可以提供更具體的原因。每次繪製其中一個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繪畫也是如此。它使用戶界面看起來和感覺笨重。還有一個原因,我不明白從本地控制趕走。
你真的只有三種選擇:
雖然掛接到ResizeBegin和ResizeEnd是正確的想法,而不是隱藏主面板的可見性,我會延遲任何調整大小的計算,直到ResizeEnd。在這種情況下,你甚至不需要鉤入ResizeBegin或Resize - 所有的邏輯都進入ResizeEnd。
我這樣說有兩個原因。一,即使面板被隱藏,調整大小操作可能仍然是昂貴的,所以除非調整大小計算被延遲,否則表單不會像它應該那樣響應。二,在調整大小的同時隱藏窗格的內容可能會讓用戶感到震驚。
使用此代碼調整窗體大小時,我成功消除了閃爍。謝謝。
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();
}
}
而調整的雙贏形式要擺脫閃爍,暫停佈局,同時調整。如下所示覆蓋表單resizebegin/resizeend方法。
protected override void OnResizeBegin(EventArgs e) {
SuspendLayout();
base.OnResizeBegin(e);
}
protected override void OnResizeEnd(EventArgs e) {
ResumeLayout();
base.OnResizeEnd(e);
}
這將使控制完整的(因爲他們之前調整位置),並強制重繪完成調整操作時。
所以我就遇到了這個同樣的問題 - 我有一個透明背景的控制被重新粉刷像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中的量,這有效地消除了任何閃爍被調整大小的控制時。
我有同樣的問題。
它接縫,這種情況是因爲您使用的圓角。當我將CornerRadius屬性設置爲0時,閃爍消失了。
到目前爲止,我只找到了以下解決方法。不是最好的,但它停止閃爍。
private void Form_ResizeBegin(object sender, EventArgs e)
{
rectangleShape.CornerRadius = 0;
}
private void Form_ResizeEnd(object sender, EventArgs e)
{
rectangleShape.CornerRadius = 15;
}
如果我沒有退出投票,我會投票關閉這個問題作爲這個問題的副本:[Winforms Double Buffering](http://support.microsoft.com/kb/3718380/winforms-double -buffering)。所以這裏是免費的。 – 2011-01-14 11:19:27
@Cody Gray - 我不同意!問題可能類似,但您發送的鏈接下提供的答案是完全錯誤/不好的,因爲它會導致很多副作用。 – HABJAN 2011-01-14 11:51:15
@HABJAN:你能告訴我一些這些副作用嗎? – 2011-01-14 11:52:39