2015-12-31 24 views
3

我正在創建一個UserControl,並且我想通過ControlPaint.DrawBorder()向它添加邊框。
我創建了一個覆蓋了OnPaint(),並把這個在它:在用戶控件上拖動一個窗口之後,在GDI +中出現污跡現象

protected override void OnPaint(PaintEventArgs e) 
{ 
    base.OnPaint(e); 


    int  Border_Width =1; 
    Color Border_Color =Color.FromArgb(170,170,170); 

    ControlPaint.DrawBorder(e.Graphics,e.ClipRectangle, 
     Border_Color,Border_Width,ButtonBorderStyle.Solid,  //Left 
     Border_Color,Border_Width,ButtonBorderStyle.Solid,  //Top 
     Border_Color,Border_Width,ButtonBorderStyle.Solid,  //Right 
     Border_Color,Border_Width,ButtonBorderStyle.Solid);  //Bottom 
} 

繪製邊框時很好,但因爲我補充說,一個問題開始:

每當我在拖一些其他的窗口用戶控制,我得到一個「剩」抹黑用戶控件..

一睹它的樣貌:

重寫的OnPaint()之前:

重寫後的OnPaint():

爲什麼會出現這種情況?

從我的實驗,
試圖啓用DubbleBuffering這裏沒有幫助..拖尾現象依然..

而且,如果我禁用ControlPaint.DrawBorder()線,
e.Graphics.DrawRectangle()替換它,
則問題消失..

所以這意味着問題不一定在重寫OnPaint()或類似的東西,但與ControlPaint.DrawBorder()

ControlPaint類在其提供的其他繪圖操作中是否存在問題?
是否有修復,或者應該避免由於這個錯誤?

回答

3

看來你使用cliprect來繪製邊框,這意味着只有應該重繪的控件的一部分。使用控制尺寸/座標繪製邊框。

+0

根據你的建議,我現在把第二個參數從'e.ClipRectangle'改爲'this.Bounds',並且令人驚訝的是它似乎解決了問題..但是我不明白爲什麼..你知道爲什麼?這個參數應該影響邊框矩形的位置和大小,它如何影響上面描述的拖尾現象? – spaceman

+1

正如我上面提到的,cliprect是控件的一部分,應該重繪。 DrawBorder只繪製一個圍繞Rectangle參數的邊框,並不考慮控件本身的邊界。如果你使用ClipRectangle,你只能「標記」即。在已更改的ClipRect區域周圍繪製邊框。因爲這個「標記」從未透支,所以會出現拖影效應。 嗯... 把你原來的「拖尾」的代碼,把你剛纔您DrwarBorder()語句之前已經提到的DrawRectangle()語句並觀察行爲...... 我敢肯定,那麼你就可以理解行爲! – Tom

+0

謝謝湯姆,絕對有幫助 – spaceman

2

您誤解了e.ClipRectangle的作用。它與您的窗口內容無關,只會告訴您窗口的哪部分需要重新繪製。代碼中的錯誤只在XP上可見,而在使用Aero的較新Windows版本上則更少。

當您拖動另一個窗口穿過您的操作系統時,操作系統會告訴您只需重新繪製移動顯示的窗口部分。只是一條條,如果你水平拖動,那麼它將只有用戶自上次繪製之後移動窗口的數量。 e.ClipRectangle包含該條子。

它旨在幫助您優化您的繪畫代碼。由於您只需繪製條子,因此您可以跳過任何在其外面繪製的代碼。優化您的繪畫代碼可能很重要,如果它太慢,那麼用戶可以看到條的未上漆部分,併產生類似於啓用鼠標線時所看到的視覺效果。但是,Windows本身已經被優化以在內部觀察ClipRectangle。你仍然使Graphics方法調用,但他們什麼都不做。或者只做你要求他們做的部分工作,即與ClipRectangle相交的部分。所以實際上必須編寫代碼並對矩形進行測試是非常罕見的。

你的bug在Aero上不太明顯,它在內存中雙緩衝窗口表面。更接近許多程序員認爲繪畫應該起作用的方式。它可以很快地從表面複製重新生成條子而不要求你幫忙。但是,當您將窗口從屏幕拖出並返回時,仍會出現這種情況,雙緩衝表面不包含不在屏幕上的窗口部分。