2013-03-19 119 views
6

我正在構建一個Control派生類,它支持Opcacity屬性。
這種控制可以同時承載的文字和圖片,並會比布爾淡化出來,並在
這裏是我的代碼:C#中的淡入淡出控制#

internal class FadeControl : Control 
{ 
    private int opacity = 100; 

    public FadeControl() 
    { 
     SetStyle(ControlStyles.SupportsTransparentBackColor, true); 
    } 

    public int Opacity 
    { 
     get 
     { 
      return opacity; 
     } 
     set 
     { 
      if (value > 100) opacity = 100; 
      else if (value < 1) opacity = 1; 
      else opacity = value; 

      if (Parent != null) 
       Parent.Invalidate(Bounds, true); 
     } 
    } 

    protected override CreateParams CreateParams 
    { 
     get 
     { 
      CreateParams cp = base.CreateParams; 
      cp.ExStyle = cp.ExStyle | 0x20; 
      return cp; 
     } 
    } 

    protected override void OnPaintBackground(PaintEventArgs e) 
    { 
     //do nothing 
    } 

    protected override void OnMove(EventArgs e) 
    { 
     RecreateHandle(); 
    } 

    protected override void OnPaint(PaintEventArgs e) 
    { 
     using (Graphics g = e.Graphics) 
     { 
      Rectangle bounds = new Rectangle(0, 0, Width - 1, Height - 1); 
      int alpha = (opacity * 255)/100; 

      using (Brush bckColor = new SolidBrush(Color.FromArgb(alpha, BackColor))) 
      { 
       if (BackColor != Color.Transparent) 
        g.FillRectangle(bckColor, bounds); 
      } 

      ColorMatrix colorMatrix = new ColorMatrix(); 
      colorMatrix.Matrix33 = (float)alpha/255; 
      ImageAttributes imageAttr = new ImageAttributes(); 
      imageAttr.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); 

      if (BackgroundImage != null) 
       g.DrawImage(BackgroundImage, bounds, 0, 0, Width, Height, GraphicsUnit.Pixel, imageAttr); 

      if (Text != string.Empty) 
      { 
       using (Brush txtBrush = new SolidBrush(Color.FromArgb(alpha, ForeColor))) 
       { 
        g.DrawString(Text, Font, txtBrush, 5, 5); 
       } 
      } 
     } 
    } 

    protected override void OnBackColorChanged(EventArgs e) 
    { 
     if (Parent != null) 
      Parent.Invalidate(Bounds, true); 

     base.OnBackColorChanged(e); 
    } 

    protected override void OnParentBackColorChanged(EventArgs e) 
    { 
     Invalidate(); 

     base.OnParentBackColorChanged(e); 
    } 
} 

我的推杆其中有一個計時器上有一個窗體上的控件。
定時器將控件的不透明度從0設置爲100,並返回並且工作正常。
我試圖解決的問題是,控制閃爍,同時改變其不透明度。
將控件設置爲ControlStyles.DoubleBuffer將使窗體上的控件不可見。

任何建議將受到歡迎。

+3

當您使用WS_EX_TRANSPARENT時,這是不可避免的。所以不要使用它。 – 2013-03-19 14:08:28

+0

[淡入一個面板 - Windows窗體]的可能重複(http://stackoverflow.com/questions/10178559/fade-a-panel-windows-forms) – 2013-03-19 14:08:36

+0

鏈接上的控件不支持透明背景色。我希望cotrol能夠在包含PNG圖像和文本的情況下淡入淡出。 – toy4fun 2013-03-19 14:48:16

回答

0

我無法同時使用雙緩衝區和WS_EX_TRANSPARENT(0x20)作爲透明背景。所以我決定通過複製父控件的內容來實現透明背景,並使用雙緩衝區來防止閃爍。

以下是最終的源代碼,測試和工作:

using System; 
using System.Drawing; 
using System.Drawing.Imaging; 
using System.Windows.Forms; 

internal class FadeControl : Control 
{ 
    private int opacity = 100; 
    private Bitmap backgroundBuffer; 
    private bool skipPaint; 

    public FadeControl() 
    { 
     SetStyle(ControlStyles.SupportsTransparentBackColor, true); 
     SetStyle(ControlStyles.ResizeRedraw, true); 
     SetStyle(ControlStyles.DoubleBuffer | 
       ControlStyles.AllPaintingInWmPaint | 
       ControlStyles.UserPaint, true); 
    } 

    public int Opacity 
    { 
     get 
     { 
      return opacity; 
     } 
     set 
     { 
      if (value > 100) opacity = 100; 
      else if (value < 1) opacity = 1; 
      else opacity = value; 

      if (Parent != null) 
       Parent.Invalidate(Bounds, true); 
     } 
    } 

    protected override void OnPaintBackground(PaintEventArgs e) 
    { 
     //do nothig 
    } 

    protected override void OnMove(EventArgs e) 
    { 
     RecreateHandle(); 
    } 

    private void CreateBackgroundBuffer(Control parent) 
    { 
     int offsetX; 
     int offsetY; 
     GetOffsets(out offsetX, out offsetY, parent); 
     backgroundBuffer = new Bitmap(Width + offsetX, Height + offsetY); 
    } 

    protected override void OnResize(EventArgs e) 
    { 
     var parent = Parent; 
     if (parent != null) 
     { 
      CreateBackgroundBuffer(parent); 
     } 
     base.OnResize(e); 
    } 

    private void GetOffsets(out int offsetX, out int offsetY, Control parent) 
    { 
     var parentPosition = parent.PointToScreen(Point.Empty); 
     offsetY = Top + parentPosition.Y - parent.Top; 
     offsetX = Left + parentPosition.X - parent.Left; 
    } 

    private void UpdateBackgroundBuffer(int offsetX, int offsetY, Control parent) 
    { 
     if (backgroundBuffer == null) 
     { 
      CreateBackgroundBuffer(parent); 
     } 
     Rectangle parentBounds = new Rectangle(0, 0, Width + offsetX, Height + offsetY); 
     skipPaint = true; 
     parent.DrawToBitmap(backgroundBuffer, parentBounds); 
     skipPaint = false; 
    } 

    private void DrawBackground(Graphics graphics, Rectangle bounds) 
    { 
     int offsetX; 
     int offsetY; 
     var parent = Parent; 
     GetOffsets(out offsetX, out offsetY, parent); 
     UpdateBackgroundBuffer(offsetX, offsetY, parent); 
     graphics.DrawImage(backgroundBuffer, bounds, offsetX, offsetY, Width, Height, GraphicsUnit.Pixel); 
    } 

    private void Draw(Graphics graphics) 
    { 
     Rectangle bounds = new Rectangle(0, 0, Width, Height); 
     DrawBackground(graphics, bounds); 

     int alpha = (opacity * 255)/100; 

     using (Brush bckColor = new SolidBrush(Color.FromArgb(alpha, BackColor))) 
     { 
      if (BackColor != Color.Transparent) 
      { 
       graphics.FillRectangle(bckColor, bounds); 
      } 
     } 

     ColorMatrix colorMatrix = new ColorMatrix(); 
     colorMatrix.Matrix33 = (float)alpha/255; 
     ImageAttributes imageAttr = new ImageAttributes(); 
     imageAttr.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); 

     if (BackgroundImage != null) 
     { 
      graphics.DrawImage(BackgroundImage, bounds, 0, 0, Width, Height, GraphicsUnit.Pixel, imageAttr); 
     } 

     if (Text != string.Empty) 
     { 
      using (Brush txtBrush = new SolidBrush(Color.FromArgb(alpha, ForeColor))) 
      { 
       graphics.DrawString(Text, Font, txtBrush, 5, 5); 
      } 
     } 
    } 

    protected override void OnPaint(PaintEventArgs e) 
    { 
     if (!skipPaint) 
     { 
      Graphics graphics = e.Graphics; 
      Draw(graphics); 
     } 
    } 

    protected override void OnBackColorChanged(EventArgs e) 
    { 
     if (Parent != null) 
     { 
      Parent.Invalidate(Bounds, true); 
     } 
     base.OnBackColorChanged(e); 
    } 

    protected override void OnParentBackColorChanged(EventArgs e) 
    { 
     Invalidate(); 
     base.OnParentBackColorChanged(e); 
    } 
} 

注意,方法CreateParams不再存在,我也已經改變了構造器。

字段skipPaint是知道什麼時候不進行繪畫,以便能夠告訴父母在OnPaint期間將自己繪製爲位圖而沒有無限遞歸。

backgroundBuffer不是實現雙緩衝,而是保留父級內容的副本而不提供控制。每次更新都會更新,我知道還有更高效的解決方案...... *但是這種方法可以簡化並且不應該成爲瓶頸,除非您在同一個容器上有太多的這些控件。

*:更好的解決方案是每次父節點無效時更新它。在同一個家長的所有FadeControls中,還有更多的分享。

+0

剛剛有機會測試它 - 完美的作品。謝謝。 – toy4fun 2013-03-30 16:02:36