C # Picturebox transparent background ne semble pas fonctionner

pour un de mes projets j'ai besoin d'images à afficher avec un fond transparent. J'ai fait quelques .images png qui ont un fond transparent (pour vérifier cela, je les ai ouvertes dans Photoshop). Maintenant j'ai une classe qui étend PictureBox:

class Foo : PictureBox
{
    public Foo(int argument)
        : base()
    {
        Console.WriteLine(argument);//different in the real application of course.
        //MyProject.Properties.Resources.TRANSPARENCYTEST.MakeTransparent(MyProject.Properties.Resources.TRANSPARENCYTEST.GetPixel(1,1)); //<-- also tried this
        this.Image = MyProject.Properties.Resources.TRANSPARENCYTEST;
        ((Bitmap)this.Image).MakeTransparent(((Bitmap)this.Image).GetPixel(1, 1));
        this.SizeMode = PictureBoxSizeMode.StretchImage;
        this.BackColor = System.Drawing.Color.Transparent;
    }
}

cela cependant affiche juste la picturebox avec un fond blanc, Je ne peux pas sembler le faire fonctionner avec un fond transparent.

18
demandé sur teuneboon 2011-04-02 13:24:02

6 réponses

il fonctionne probablement parfaitement. Vous voyez ce qu'il y a derrière le contrôle de la boîte à images. Qui est la forme. Dont BackColor est probablement blanc. Vous pouvez définir la propriété Backgrounddimage du formulaire pour être sûr, vous devriez voir l'image à travers la boîte d'image. Comme ceci:

enter image description here

perforation d'un trou à travers à la fois the picture box et la forme nécessite une arme plus grande, Forme.TransparencyKey

20
répondu Hans Passant 2011-04-02 13:11:42

si vous voulez superposer des images sur des images (et non des images sur la forme), cela ferait l'astuce:

overImage.Parent = backImage;
overImage.BackColor = Color.Transparent;
overImage.Location = thePointRelativeToTheBackImage;

où surimage et backImage sont des PictureBox avec png (avec fond transparent).

C'est parce que, comme dit précédemment, la transparence d'une image est affichée en utilisant la couleur de fond du conteneur Parent. PictureBoxes n'ont pas une propriété" Parent " donc vous devez le faire manuellement (ou créer un contrôle cutom bien sûr).

37
répondu Tobia Zambon 2012-02-06 10:40:12

il y a une excellente solution sur le site du Codeprojet à

Faire Des Contrôles Transparents - Pas De Scintillement

essentiellement le truc est de passer outre l'événement paintbackground de manière à boucler toutes les commandes sous-jacentes à la picturebox et de les redessiner. La fonction est: -

protected override void OnPaintBackground(PaintEventArgs e)
       // Paint background with underlying graphics from other controls
   {
       base.OnPaintBackground(e);
       Graphics g = e.Graphics;

       if (Parent != null)
       {
           // Take each control in turn
           int index = Parent.Controls.GetChildIndex(this);
           for (int i = Parent.Controls.Count - 1; i > index; i--)
           {
               Control c = Parent.Controls[i];

               // Check it's visible and overlaps this control
               if (c.Bounds.IntersectsWith(Bounds) && c.Visible)
               {
                   // Load appearance of underlying control and redraw it on this background
                   Bitmap bmp = new Bitmap(c.Width, c.Height, g);
                   c.DrawToBitmap(bmp, c.ClientRectangle);
                   g.TranslateTransform(c.Left - Left, c.Top - Top);
                   g.DrawImageUnscaled(bmp, Point.Empty);
                   g.TranslateTransform(Left - c.Left, Top - c.Top);
                   bmp.Dispose();
               }
           }
       }
   }
12
répondu Tony Reynolds 2014-07-30 13:08:45

I know your Question is founded in c# , but due to the similarity, & ease of conversion from VB.NET , je vais ajouter une version complète VB qui permet également la mise à jour de l'arrière-plan de la commande lorsque vous la déplacez.

vous avez déjà une réponse, mais c'est pour les autres qui trouvent ce post par les moteurs de recherche, & voudrait une VB version, ou tout simplement veulent trouver une pleine échantillon convertible s'ils en ont également besoin en c# .

créer un nouveau Custom Control Class , & coller ce qui suit dans elle... l'écrasement de la classe par défaut choses:

Contrôle Personnalisé De La Classe:

Public Class TransparentPictureBox
    Private WithEvents refresher As Timer
    Private _image As Image = Nothing

    Public Sub New()

        ' This call is required by the designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.
        refresher = New Timer()
        'refresher.Tick += New EventHandler(AddressOf Me.TimerOnTick)
        refresher.Interval = 50
        refresher.Start()

    End Sub

    Protected Overrides ReadOnly Property CreateParams() As CreateParams
        Get
            Dim cp As CreateParams = MyBase.CreateParams
            cp.ExStyle = cp.ExStyle Or &H20
            Return cp
        End Get
    End Property

    Protected Overrides Sub OnMove(ByVal e As EventArgs)
        MyBase.OnMove(e)
        MyBase.RecreateHandle()
    End Sub

    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
        MyBase.OnPaint(e)

        'Add your custom paint code here
        If _image IsNot Nothing Then
            e.Graphics.DrawImage(_image, CInt(Width / 2) - CInt(_image.Width / 2), CInt(Height / 2) - CInt(_image.Height / 2))
        End If
    End Sub


    Protected Overrides Sub OnPaintBackground(ByVal e As System.Windows.Forms.PaintEventArgs)
        ' Paint background with underlying graphics from other controls
        MyBase.OnPaintBackground(e)
        Dim g As Graphics = e.Graphics

        If Parent IsNot Nothing Then
            ' Take each control in turn
            Dim index As Integer = Parent.Controls.GetChildIndex(Me)
            For i As Integer = Parent.Controls.Count - 1 To index + 1 Step -1
                Dim c As Control = Parent.Controls(i)

                ' Check it's visible and overlaps this control
                If c.Bounds.IntersectsWith(Bounds) AndAlso c.Visible Then
                    ' Load appearance of underlying control and redraw it on this background
                    Dim bmp As New Bitmap(c.Width, c.Height, g)
                    c.DrawToBitmap(bmp, c.ClientRectangle)
                    g.TranslateTransform(c.Left - Left, c.Top - Top)
                    g.DrawImageUnscaled(bmp, Point.Empty)
                    g.TranslateTransform(Left - c.Left, Top - c.Top)
                    bmp.Dispose()
                End If
            Next
        End If
    End Sub

    Public Property Image() As Image
        Get
            Return _image
        End Get
        Set(value As Image)
            _image = value
            MyBase.RecreateHandle()
        End Set
    End Property

    Private Sub refresher_Tick(sender As Object, e As System.EventArgs) Handles refresher.Tick
        MyBase.RecreateHandle()
        refresher.Stop()
    End Sub
End Class

...sauvez la classe, puis nettoyez votre projet, et construire à nouveau. Le nouveau contrôle doit apparaître comme un nouvel outil. Trouver, & faites-le glisser à votre formulaire.

j'ai eu des problèmes avec ce contrôle cependant... Cela se produit lorsque j'essaie de charger un "chargement" animé .gif de l'image.

l'image ne s'Anime pas, et a également des problèmes d'affichage lorsque vous cachez la commande, puis essayez de l'afficher à nouveau.

trier ces questions, et vous aurez une classe de contrôle parfait personnalisé. :)

EDIT:

Je n'ai pas idée si ce qui suit fonctionnera en C# 's IDE ou pas, mais voici ma tentative de conversion:

using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
public class TransparentPictureBox
{
    private Timer withEventsField_refresher;
    private Timer refresher {
        get { return withEventsField_refresher; }
        set {
            if (withEventsField_refresher != null) {
                withEventsField_refresher.Tick -= refresher_Tick;
            }
            withEventsField_refresher = value;
            if (withEventsField_refresher != null) {
                withEventsField_refresher.Tick += refresher_Tick;
            }
        }
    }

    private Image _image = null;

    public TransparentPictureBox()
    {
        // This call is required by the designer.
        InitializeComponent();

        // Add any initialization after the InitializeComponent() call.
        refresher = new Timer();
        //refresher.Tick += New EventHandler(AddressOf Me.TimerOnTick)
        refresher.Interval = 50;
        refresher.Start();

    }

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

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

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

        //Add your custom paint code here
        if (_image != null) {
            e.Graphics.DrawImage(_image, Convert.ToInt32(Width / 2) - Convert.ToInt32(_image.Width / 2), Convert.ToInt32(Height / 2) - Convert.ToInt32(_image.Height / 2));
        }
    }


    protected override void OnPaintBackground(System.Windows.Forms.PaintEventArgs e)
    {
        // Paint background with underlying graphics from other controls
        base.OnPaintBackground(e);
        Graphics g = e.Graphics;

        if (Parent != null) {
            // Take each control in turn
            int index = Parent.Controls.GetChildIndex(this);
            for (int i = Parent.Controls.Count - 1; i >= index + 1; i += -1) {
                Control c = Parent.Controls(i);

                // Check it's visible and overlaps this control
                if (c.Bounds.IntersectsWith(Bounds) && c.Visible) {
                    // Load appearance of underlying control and redraw it on this background
                    Bitmap bmp = new Bitmap(c.Width, c.Height, g);
                    c.DrawToBitmap(bmp, c.ClientRectangle);
                    g.TranslateTransform(c.Left - Left, c.Top - Top);
                    g.DrawImageUnscaled(bmp, Point.Empty);
                    g.TranslateTransform(Left - c.Left, Top - c.Top);
                    bmp.Dispose();
                }
            }
        }
    }

    public Image Image {
        get { return _image; }
        set {
            _image = value;
            base.RecreateHandle();
        }
    }

    private void refresher_Tick(object sender, System.EventArgs e)
    {
        base.RecreateHandle();
        refresher.Stop();
    }
}

essayez-le , et voyez par vous-même je suppose :p

ps: Je ne suis pas un gourou, alors attendez-vous à toutes sortes D'erreurs dans le C#, & VB.NET versions. lol

4
répondu DTeCH 2013-10-15 15:08:24

si vous affichez png avec transparence dans la boîte d'image, il sera automatiquement prendre en compte la transparence, de sorte que vous n'avez pas besoin de définir la couleur transparente

3
répondu Anton Semenov 2011-04-02 09:44:22

Les réponses ci-dessus semblent résoudre votre problème. Vous voyez en effet ce qui se cache derrière le contrôle de la boîte d'image - la forme elle-même avec backColor blanc. J'ai créé ici une fonction simple qui convertit d'abord une image de type octet (tableau) en un bitmap et ensuite en définissant des couleurs spécifiques (à partir de l'image bitmap) en transparent. Quelque chose que vous pourriez aussi bien utiliser:

 using System;
   using System.Drawing;
   using System.Drawing.Imaging;
   using System.Windows.Forms;
    public void LogoDrawTransparent(PaintEventArgs e)
    {
        // Create a Bitmap object from an image file.
        Image myImg;
        Bitmap myBitmap;

        try
        {
            myImg = cls_convertImagesByte.GetImageFromByte(newImg);
            myBitmap = new Bitmap(myImg); // @"C:\Temp\imgSwacaa.jpg");  

            // Get the color of a background pixel.
            Color backColor = myBitmap.GetPixel(0, 0); // GetPixel(1, 1); 
            Color backColorGray = Color.Gray;
            Color backColorGrayLight = Color.LightGray;
            Color backColorWhiteSmoke = Color.WhiteSmoke;
            Color backColorWhite = Color.White;
            Color backColorWheat = Color.Wheat;

            // Make backColor transparent for myBitmap.
            myBitmap.MakeTransparent(backColor);
                    // OPTIONALLY, you may make any other "suspicious" back color transparent (usually gray, light gray or whitesmoke)
            myBitmap.MakeTransparent(backColorGray);
            myBitmap.MakeTransparent(backColorGrayLight);
            myBitmap.MakeTransparent(backColorWhiteSmoke);

            // Draw myBitmap to the screen.
            e.Graphics.DrawImage(myBitmap, 0, 0, pictureBox1.Width, pictureBox1.Height); //myBitmap.Width, myBitmap.Height);
        }
        catch
        {
            try { pictureBox1.Image = cls_convertImagesByte.GetImageFromByte(newImg); }
            catch { } //must do something
        }
    }

vous pouvez tirer ce func sur la peinture de la pictureBox. C'est ma classe qui est référencée dans la fonction ci-dessus:

    class cls_convertImagesByte
{

    public static Image GetImageFromByte(byte[] byteArrayIn)
    {
        MemoryStream ms = new MemoryStream(byteArrayIn);
        Image returnImage = Image.FromStream(ms);
        return returnImage;
    }

    public static byte[] GetByteArrayFromImage(System.Drawing.Image imageIn)
    {
        MemoryStream ms = new MemoryStream();
        imageIn.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);
        return ms.ToArray();
    }
}

Merci. Chagbert

1
répondu Chagbert 2014-05-23 06:15:35