Le fond transparent C # Picturebox ne semble pas fonctionner

Pour un de mes projets, j’ai besoin d’images à afficher avec un arrière-plan transparent. J’ai créé des images .png avec un fond transparent (pour les vérifier, 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; } } 

Cependant, cela affiche simplement la boîte à images avec un arrière-plan blanc. Je n’arrive pas à le faire fonctionner avec un arrière-plan transparent.

Cela fonctionne probablement parfaitement. Vous voyez ce qui se cache derrière le contrôle de la boîte à images. Quelle est la forme. Dont BackColor est probablement blanc. Vous pouvez définir la propriété BackgroundImage du formulaire pour être sûr que vous devriez voir l’image dans la zone d’image. Comme ça:

entrez la description de l'image ici

Percer un trou à la fois dans la boîte à images et dans le formulaire nécessite une arme plus grosse, Form.TransparencyKey

Si vous souhaitez superposer des images sur des images (et non des images sur un formulaire), voici l’astuce:

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

Où overImage et backImage sont PictureBox avec png (avec arrière-plan transparent).

En effet, comme indiqué précédemment, la transparence d’une image est rendue à l’aide de la couleur de fond du conteneur Parent. Les PictureBox n’ont pas de propriété “Parent”, vous devez donc les créer manuellement (ou bien créer un contrôle personnalisé).

Il y a une excellente solution sur le site Web CodeProject à l’adresse

Rendre les contrôles transparents – pas de scintillement

essentiellement, l’astuce consiste à remplacer l’événement paintbackground de manière à parcourir en boucle tous les contrôles sous-jacents à picturebox et à 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(); } } } } 

Je sais que votre question est fondée en C # , mais en raison de la similitude et de la facilité de conversion à partir de VB.NET , je vais append une version complète de VB qui permet également de mettre à jour l’arrière-plan du contrôle lorsque vous le déplacez.

Vous avez déjà une réponse, mais c’est pour les autres qui trouvent ce message par les moteurs de recherche, et qui souhaitent une version VB , ou qui souhaitent simplement trouver un échantillon convertible COMPLET s’ils en ont également besoin en C # .

Créez une nouvelle classe de contrôle personnalisée et collez-y les éléments suivants en écrasant …

Classe de contrôle personnalisée:

 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 

… enregistrez la classe, puis nettoyez votre projet et construisez à nouveau. Le nouveau contrôle doit apparaître comme un nouvel élément d’outil. Trouvez-le et faites-le glisser vers votre formulaire.

J’ai eu des problèmes avec ce contrôle cependant … Cela se produit lorsque j’essaie de charger une image animée “Loading” .gif .

L’image n’anime pas et a également des problèmes d’affichage lorsque vous masquez le contrôle, puis essayez à nouveau de l’afficher.

Triez ces problèmes et vous aurez une classe de contrôle personnalisée parfaite. 🙂

MODIFIER:

Je ne sais pas si ce qui suit fonctionnera dans l’IDE de C # ou non, 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 les versions C # et VB.NET. lol

Si vous affichez png avec transparence dans la zone d’image, la transparence sera automatiquement prise en compte, vous n’aurez donc pas besoin de définir une couleur transparente.

Les réponses ci-dessus semblent résoudre votre problème. Vous voyez bien ce qu’il y a derrière le contrôle de la zone d’image – le formulaire lui-même avec backColor blanc. J’ai créé ici une fonction simple qui convertit d’abord une image de type octet (tableau) en bitmap, puis définit 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 lancer cette fonction sur Paint of the 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