2012-06-30 29 views
7

He intentado mostrar una imagen que tiene un borde transparente como fondo de un control.Control de dibujo con fondo transparente

Desafortunadamente, el área transparente crea un agujero en el formulario principal de la siguiente manera:

En la imagen anterior, la forma tiene un fondo de color rojo que yo esperaba ver detrás de mi control en las áreas transparentes.

El código I utilizada es la siguiente:

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); 
    } 

Esta clase se hereda de un cuadro de imagen porque necesitaba un control que implementa onMouseMove y onMouseUp Events.

He estado investigando la mayor parte del día sin éxito probando diferentes ideas, pero desafortunadamente la mayoría solo funciona en el framework completo y no en .Net CF.

Cualquier idea sería muy apreciada.

Respuesta

6

Ah las alegrías de la transparencia CF. Podría seguir y seguir sobre eso (y tengo in my blog y el Project Resistance code que hice hace años).

Lo esencial es esto. El control infantil tiene que pintar sus áreas, pero primero tiene que volver a llamar a sus padres (el Formulario en su caso) y pedirle que vuelva a dibujar su imagen de fondo en todas partes excepto en la región de recorte del niño y luego dibujar encima de eso . Si eso suena un poco confuso, es porque lo es.

Por ejemplo, si mira Project Resistance, una Vista (que es solo un Control) dibuja una resistencia y bandas. Se encuentra en una forma que tiene una imagen de fondo, y que el fondo tiene que "mostrar a través de" las áreas transparentes de la resistencia:

enter image description here

Así que en el código de dibujo de la resistencia se hace esto:

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 
    } 
} 

Que es lo suficientemente simple. La clave es que llama a su OnPaint base, lo que hace esto:

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); 
    } 
} 

Se puede ver que está llamando PaintBackground del formulario que contiene (es parent.parent en este caso, los pisos más altos del control es en realidad en un recipiente llamado Espacio de trabajo: no necesitaría subir dos veces en su caso). Eso dibuja en la imagen de fondo en el área que está viendo actualmente como el "agujero"

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

Wow, gracias por eso. Una explicación extremadamente útil y detallada. Ciertamente has dedicado algo de tiempo al tema. –

+0

@ctacke Se me ocurrió una solución de Transparencia que está muy cerca de la tuya, y funciona tanto en el diseñador como en el tiempo de ejecución. Recientemente me di cuenta de que mi solución no funcionará al anidar Controles de Contenedor porque la función "Parent.Parent" no funciona. Intenté cambiar "Parent.Parent" a este. Top Control de nivel, que funciona en tiempo de ejecución pero no en tiempo de diseño. ¿Alguna vez ha podido obtener una solución para anidar controles transparentes dentro de los controles del contenedor y todavía tiene el diseñador que haga que su control sea transparente? –

+0

Dejé de intentar incluso obtener soporte de diseñador para mis controles hace años. Simplemente nunca me pareció tan importante y siempre fue frágil.A veces funcionaría, otras veces no funcionaría y me encontré ardiendo días sin hacer nada productivo, así que nunca me molesté con el diseñador, ni mucho menos para diseñar los rectángulos donde irán los controles. – ctacke