C#的Picturebox透明背景似乎不工作

对于我的一个项目,我需要用透明背景来显示图像。 我做了一些具有透明背景的.png图像(检查这个我在Photoshop中打开它们)。 现在我有一个扩展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; } } 

这只是显示与白色背景的图片框,我似乎无法使其工作在透明的背景。

它可能完美的作品。 您正在看到图片框控件背后的内容。 这是表格。 谁的BackColor可能是白色的。 您可以将表单的BackgroundImage属性设置为确定,您应该通过图片框来查看图像。 喜欢这个:

在这里输入图像描述

通过图片框窗体打孔需要一个更大的武器,Form.TransparencyKey

如果你想叠加图像(而不是forms上的图像),这将成为诀窍:

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

overImage和backImage是PictureBox的png(透明背景)。

这是因为,如前所述,图像的透明度使用父容器的背面颜色呈现。 PictureBoxes没有“父”属性,所以你必须手动(或创build一个cutom控件当然)。

在CodeProject网站上有一个很好的解决scheme

制作透明的控件 – 不闪烁

本质上诀窍是重写paintbackground事件,以便遍历所有控件的底层控件并重绘它们。 function是: –

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

如果您在图片框中显示png的透明度,它会自动考虑透明度,所以您不需要设置透明颜色

我知道你的问题是build立在C#上的 ,但是由于VB.NET的相似性和易用性,我将添加一个完整的VB版本,在你移动的时候也可以更新控件的背景。

你已经有了一个答案,但这是为search引擎find这个post的其他人,&想要一个VB版本,或者只是想find一个完整的可转换样本,如果他们也需要在C#中

创build一个新的自定义控件类 ,并粘贴以下内容…覆盖默认类的东西:

自定义控件类:

 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 

…保存class级,然后清理你的项目,再次build立。 新控件应该显示为一个新的工具项目。 find它,并将其拖到您的表单。

我有这个控制的问题,虽然…当我尝试加载animation“加载” .gif图像时发生。

图像不animation,并且在隐藏控件时也有显示问题,然后尝试再次显示。

对这些问题进行sorting,您将拥有一个完美的自定义控件类。 🙂

编辑:

我不知道以下是否会在C#的IDE中工作,但这是我的转换尝试:

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

试一试,看看自己我猜:P

ps:我不是古茹,所以在C#和VB.NET版本中都会遇到各种各样的错误。 大声笑

上面的答案似乎解决了你的问题。 你确实看到了图片框控件背后的东西 – 带有backColor白色的图片本身。 我在这里创build了一个简单的函数,首先将字节types(数组)的图像转换为位图,然后将特定颜色(从位图图像)设置为透明。 你也可以使用一些东西:

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

你可以在pictureBox的Paint上激发这个func。 这是我在上面的函数中引用的类:

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

谢谢。 Chagbert