2012-06-30 3 views
7

J'ai essayé d'afficher une image qui a une bordure transparente comme arrière-plan d'un contrôle.Contrôle de dessin avec fond transparent

Malheureusement, la zone transparente crée un trou sous la forme de parent comme suit:

Dans l'image ci-dessus, la forme a un fond rouge que je l'avais espéré voir derrière mon contrôle les zones transparentes.

Le code j'est la suivante:

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

Cette classe est héritée d'un PictureBox parce que je besoin d'un contrôle qui implémente des événements OnMouseMove et OnMouseUp.

J'ai fait des recherches la plupart du jour sans succès tester des idées différentes, mais malheureusement, la plupart travaillent uniquement sur le cadre complet et non .Net CF.

Toutes les idées seraient grandement appréciées.

Répondre

6

Ah les joies de la transparence CF. Je pourrais continuer encore et encore à ce sujet (et ont in my blog et le Project Resistance code je l'ai fait il y a des siècles).

L'essentiel, c'est ceci. Le contrôle enfant doit peindre ses zones, mais il doit d'abord rappeler à son parent (le formulaire dans votre cas) et lui dire de redessiner son image d'arrière-plan partout sauf dans la région de découpage de l'enfant et ensuite se dessiner dessus . Si cela semble un peu confus, c'est parce que c'est le cas.

Par exemple, si vous regardez Project Resistance, une vue (qui est juste un contrôle) dessine une résistance et des bandes. Il se trouve dans un formulaire qui a un fond d'image, et arrière-plan doit « montrer à travers » les zones transparentes de la résistance:

enter image description here

Ainsi, dans le code de dessin de la résistance, il le fait:

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

Ce qui est assez simple. La clé est qu'il appelle à son OnPaint de base, ce qui le fait:

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

Vous pouvez voir qu'il appelle PaintBackground du contenant formulaire (il est parent.parent dans ce cas becuse le contrôle est en fait dans un conteneur appelé Espace de travail - vous n'auriez pas besoin de marcher deux fois dans votre cas). Cela dessine dans l'image d'arrière-plan dans la zone que vous voyez actuellement comme le "trou"

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

Wow, merci pour cela. Une explication extrêmement utile et détaillée. Vous avez certainement passé du temps sur le sujet. –

+0

@ctacke Je suis arrivé avec une solution de transparence qui est très proche de la vôtre, et cela fonctionne aussi bien dans le concepteur que dans l'exécution. J'ai récemment réalisé que ma solution ne fonctionnerait pas lors de l'imbrication de Conteneur Contrôles car la fonction "Parent.Parent" ne fonctionne pas. J'ai essayé de basculer "Parent.Parent" à this.TopLevelControl, qui fonctionne à l'exécution mais pas au moment du design. Où avez-vous déjà trouvé une solution pour imbriquer des contrôles transparents à l'intérieur des contrôles Container tout en laissant le concepteur rendre votre contrôle transparent? –

+0

J'ai renoncé même à essayer d'obtenir le support du concepteur pour mes commandes il y a des années. Cela n'a jamais été aussi important pour moi et était toujours fragile.Parfois cela fonctionnait, d'autres fois ça ne fonctionnait pas et je me retrouvais en train de brûler des jours sans vraiment faire quelque chose de productif, alors je ne m'occupe même plus du concepteur à moins de disposer les rectangles où vont les commandes. – ctacke