2012-06-30 153 views
7

我一直在试图显示一个具有透明边框作为控件背景的图像。带透明背景的绘图控制

不幸的是,透明的区域会在父表孔如下:

在上图中,形式有哪些我所希望看到我在背后控制红色背景透明区域。

我使用的代码如下:

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) 
    { 
     if (this.Image != null) 
     { 
      Graphics g = Graphics.FromImage(this.Image); 

      ImageAttributes attr = new ImageAttributes(); 

      //set the transparency based on the top left pixel 
      attr.SetColorKey((this.Image as Bitmap).GetPixel(0, 0), (this.Image as Bitmap).GetPixel(0, 0)); 

      //draw the image using the image attributes. 
      Rectangle dstRect = new Rectangle(0, 0, this.Image.Width, this.Image.Height); 

      e.Graphics.DrawImage(this.Image, dstRect, 0, 0, this.Image.Width, this.Image.Height, 
       GraphicsUnit.Pixel, attr); 
     } 
     else 
     { 
      base.OnPaint(e); 
     } 
    } 

    protected override void OnPaintBackground(System.Windows.Forms.PaintEventArgs e) 
    { 
     //base.OnPaintBackground(e); 
    } 

这类是从一个PictureBox继承因为我需要它实现的OnMouseMove和OnMouseUp活动的控制。

我一直在研究大部分时间没有成功测试出不同的想法,但不幸的是,大多数只能在完整的框架上工作,而不是.Net CF.

任何想法将不胜感激。

回答

6

啊,CF透明度的乐趣。我可以继续谈论它(并有in my blogProject Resistance code我很久以前做过)。

的要点是这样的。子控件必须绘制它的区域,但首先必须回调它的父项(在您的案例中为Form),并告诉它在除了子项的裁剪区域之外的任何地方都重绘它的背景图像,然后绘制它自己的顶部。如果这听起来有点混乱,那是因为它。

例如,如果你看Project Resistance,View(它只是一个Control)绘制一个电阻和带。它坐落在具有图像背景形式,以及背景需要“透视”电阻的透明区域:

enter image description here

所以它这样做电阻的绘制代码:

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

    try 
    { 
     RECT rect = new RECT(this.Bounds); 

     // draw the blank 
     Infrastructure.GraphicTools.DrawTransparentBitmap(e.Graphics, m_blankImage, Bounds, 
       new Rectangle(0, 0, m_blankImage.Width, m_blankImage.Height)); 

     if (m_bandsImage != null) 
     { 
      // draw the bands 
      Infrastructure.GraphicTools.DrawTransparentBitmap(e.Graphics, m_bandsImage, Bounds, 
       new Rectangle(0, 0, m_bandsImage.Width, m_bandsImage.Height)); 
     } 
    } 
    finally 
    { 
    } 

    if (!Controller.TouchMode) 
    { 
     // TODO: draw in the selection arrow 
     // Controller.SelectedBand 
    } 
} 

这很简单。最关键的是,它调用它的基本的OnPaint,这将会:

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) 
{ 
    // this assumes we're in a workspace, on MainForm (the whole Parent.Parent thing) 
    IBackgroundPaintProvider bgPaintProvider = Parent.Parent as IBackgroundPaintProvider; 
    if (bgPaintProvider != null) 
    { 
     Rectangle rcPaint = e.ClipRectangle; 
     // use the parent, since it's the workspace position in the Form we want, 
     // not our position in the workspace 
     rcPaint.Offset(Parent.Left, Parent.Top); 
     bgPaintProvider.PaintBackground(e.Graphics, e.ClipRectangle, rcPaint); 
    } 
} 

你可以看到它调用了含有形式的PaintBackground(这是Parent.Parent在这种情况下becuse的控制实际上是一个容器称为工作区 - 你不需要在你的案例中走两次)。这在你目前看到的作为“洞”的区域绘制背景图像

public void PaintBackground(Graphics g, Rectangle targetRect, Rectangle sourceRect) 
{ 
    g.DrawImage(m_bmBuffer, targetRect, sourceRect, GraphicsUnit.Pixel); 
} 
+0

哇,谢谢你。一个非常有用和详细的解释。你肯定花了一些时间在这个问题上。 –

+0

@ctacke我想出了一个非常接近你的透明度解决方案,它可以在设计器和运行时使用。我最近意识到我的解决方案在嵌套容器控件时不起作用,因为“Parent.Parent”不起作用。我尝试将“Parent.Parent”切换到this.TopLevelControl,它在运行时工作,但不是在设计时。在哪里你可以得到一个解决方案来在Container控件中嵌套透明控件,并且仍然让设计者使控件变得透明? –

+0

几年前,我放弃了甚至试图为我的控件获得设计师支持。它从来没有觉得这对我很重要,而且总是很脆弱。有时候它会起作用,其他时候它不会,我发现自己燃烧了几天,实际上没有做出什么高效率的事情,所以我甚至从来没有打算控制设计的矩形,甚至从不打扰设计师。 – ctacke