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 n'affiche que la Picturebox avec un fond blanc, je n'arrive pas à la faire fonctionner avec un fond transparent.
Cela fonctionne probablement parfaitement. Vous voyez ce qui se cache derrière le contrôle de la zone d'image. Quelle est la forme. Dont BackColor est probablement blanc. Vous pouvez définir la propriété BackgroundImage du formulaire pour être sûr, vous devriez voir l'image à travers la zone d'image. Comme ça:
Perforer un trou à travers les deux la zone d'image et le formulaire nécessite une arme plus grande, Form.TransparencyKey
Si vous voulez superposer des images sur des images (et non des images sur un formulaire), cela ferait l'affaire:
overImage.Parent = backImage;
overImage.BackColor = Color.Transparent;
overImage.Location = thePointRelativeToTheBackImage;
Où overImage et backImage sont PictureBox avec png (avec fond transparent).
En effet, comme indiqué précédemment, la transparence d'une image est rendue à l'aide de la couleur arrière du conteneur parent. Les PictureBoxes n'ont pas de propriété "Parent", vous devez donc la faire manuellement (ou créer un contrôle personnalisé bien sûr).
Il y a une excellente solution sur le site Web de CodeProject à
Faire des contrôles transparents - pas de scintillement
essentiellement, l'astuce consiste à remplacer l'événement paintbackground afin de parcourir tous les contrôles sous-jacents à la boîte d'image 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();
}
}
}
}
Je sais que votre question est fondée en C #, mais en raison de la similitude et de la facilité de conversion de VB.NET, j'ajouterai un VB version 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 ceux qui trouvent ce message par les moteurs de recherche, et qui aimeraient une version VB , ou veulent simplement trouver un FULL échantillon convertible s'ils en ont également besoin en C #.
Créez une nouvelle classe de contrôle personnalisée, et collez-y ce qui suit ... en écrasant les éléments de classe par défaut:
Classe de contrôle personnalisé:
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 reconstruisez. 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 cependant eu des problèmes avec ce contrôle ... Cela se produit lorsque j'essaie de charger une image "Loading" . Gif animée.
L'image ne s'anime pas et présente également des problèmes d'affichage lorsque vous masquez le contrôle, puis essayez de l'afficher à nouveau.
Triez ces problèmes et vous aurez une classe de contrôle personnalisée parfaite. :)
MODIFIER:
Je n'ai aucune idée si ce qui suit fonctionnera dans C # IDE 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 un png avec transparence dans la zone d'image, il prendra automatiquement en compte la transparence, vous n'avez donc pas besoin de définir une couleur transparente
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 zone d'image - le formulaire lui-même avec backColor blanc. J'ai ici créé une fonction simple qui convertit d'abord une image de type octet (tableau) en bitmap et définit ensuite 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