【问题标题】:C# Picturebox transparent background doesn't seem to workC# Picturebox透明背景似乎不起作用
【发布时间】:2011-07-28 04:45:27
【问题描述】:

对于我的一个项目,我需要以透明背景显示图像。我制作了一些具有透明背景的 .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;
    }
}

然而,这只是用白色背景显示图片框,我似乎无法让它在透明背景下工作。

【问题讨论】:

  • 您能否提供一张图片的链接(您拥有的最基本的一张)?
  • 我依稀记得(在我的 WinForm 时代),当控件的背景标记为“透明”时,它真正呈现为透明。相反,它使用容器的背景颜色呈现。你的容器的背景颜色是白色的吗?
  • @Stephen:我很确定就是这样。在 WinForms 中,图像没有任何真正的透明度(默认情况下不是)。如果您的控件重叠,您将看到它。
  • 除了通过透明区域显示表单的(白色)背景之外,您还能期待什么?我什至不明白这里的问题是什么......汉斯的答案是正确的。 (另请注意,这与 C# 语言没有任何关系。C# 没有用户界面;您为此使用 WinForms,它包装了本机 Windows API。它不是真的专为透明而设计。您构建的不是网页,而是桌面应用程序。)

标签: c# transparency picturebox


【解决方案1】:

如果您想在图像上叠加图像(而不是在形式上叠加图像),这将是诀窍:

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

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

这是因为,如前所述,图像的透明度是使用父容器的背景颜色呈现的。 PictureBox 没有“父”属性,因此您必须手动创建(当然也可以创建自定义控件)。

【讨论】:

  • 只是为了澄清(不确定类型),我使用了 overImage.Location = new Point(x,y) 并且一切正常。非常感谢!
  • 它工作正常,点需要定义对应的父容器。根据这个例子,backImage 是父容器。
  • .BackColor 设置为Color.Transparent 是关键。谢谢!
【解决方案2】:

它可能完美无缺。您将看到图片框控件背后的内容。是哪一种形式。谁的背景色可能是白色的。您可以设置窗体的BackgroundImage 属性,以确保您应该通过图片框看到图像。像这样:

两个图片框表单上打一个洞需要更大的武器,Form.TransparencyKey

【讨论】:

  • 这不是真正的透明度。如果图片框后面有另一个控件,它将不会通过透明区域显示。相反,表单背景将显示在控件上方。
  • 是的,是的,我们知道,它是一个窗口,它们在设计上是不透明的。您会看到父图形本身作为背景。您也可以获得其他控件来绘制自己以及but that is work。使用 Paint 事件或 WPF 将油漆层堆叠在一起。
【解决方案3】:

CodeProject 网站上有一个很好的解决方案

Making Transparent Controls - No Flickering

本质上,诀窍是覆盖paintbackground 事件,以便循环遍历图片框下的所有控件并重绘它们。功能是:-

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

【讨论】:

  • 不幸的是,该代码项目文章已于 2013 年 10 月 2 日被删除。
  • 今天还有用,这篇文章...迫不及待地得到老板的OK转用wpf :(
【解决方案4】:

我知道您的问题是在 C# 中建立的,但由于相似性以及从 VB.NET 转换的容易性,我将添加一个完整的 VB 版本,它还允许在您移动控件时更新控件的背景。

您已经有了答案,但这是为那些通过搜索引擎找到这篇文章的人准备的在 C# 中。

创建一个新的自定义控件类,并将以下内容粘贴到其中...覆盖默认类的内容:

自定义控件类:

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

...保存类,然后清理您的项目,并再次构建。新控件应显示为新工具项。找到它,并将其拖到您的表单中。

我在使用此控件时遇到了问题...当我尝试加载动画“正在加载”.gif 图像时会发生这种情况。

图像没有动画,并且隐藏控件时也有显示问题,然后尝试再次显示。

解决这些问题,您将拥有一个完美的自定义控件类。 :)

编辑:

我不知道以下内容是否适用于 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 版本中都会出现各种错误。哈哈

【讨论】:

    【解决方案5】:

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

    【讨论】:

    • 我刚刚用图片框试了一下你的图片。它可以在没有任何透明规范的情况下正常工作。
    【解决方案6】:

    以上答案似乎可以解决您的问题。您确实看到了图片框控件背后的内容 - 背景颜色为白色的表单本身。我在这里创建了一个简单的函数,它首先将字节类型(数组)的图像转换为位图,然后将特定颜色(来自位图图片)设置为透明。你不妨使用的东西:

     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上触发这个函数。 这是我在上面的函数中引用的类:

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

    谢谢。查格伯特

    【讨论】:

      猜你喜欢
      • 2021-06-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-14
      • 2021-10-13
      • 1970-01-01
      • 2015-04-25
      相关资源
      最近更新 更多