【问题标题】:Is it possible to create a non-shaped control?是否可以创建非形状控件?
【发布时间】:2013-07-16 20:39:48
【问题描述】:

我正在尝试将没有确定形状的图像(例如帽子)放在不同的图像控件之上。 问题是,由于控件具有确定的形状,它会保留默认背景颜色以覆盖留空的空间。图像控件与图像的大小完全相同。 我尝试使用 control.BackColor = Color.Transparent;但它似乎不起作用。 还有其他建议吗?

【问题讨论】:

  • 图片本身是透明的吗?例如,PNG 图像支持透明色。这对于您尝试工作非常重要......
  • 编辑了您的标题。请阅读:meta.stackexchange.com/questions/19190/…
  • 我相信这是 WinForms,因此您可能希望在标签中指定它(而不是背景或图片框)。在注意到 BackColor 之前,我本来打算为 WPF 回答这个问题。
  • 是的,我的图像具有透明背景,为 PNG 格式。

标签: c# winforms image background transparent


【解决方案1】:

您可以为此使用Control.Region

GraphicsPath path = new GraphicsPath();
path.AddEllipse(control.ClientRectangle);
control.Region = new Region(path);

试试这个,您可以使用GraphicsPath 创建任何形状并将其设置为Region,例如我创建了椭圆。

编辑

如果你只想设置 BackColor = Color.Transparent。出于某种原因,某些控件不允许这样做。在这种情况下,您可以执行以下操作

public class CustomControl1 : Control
{
    public CustomControl1()
    {
        this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
    }
}

创建控件的后代并设置 this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); 应该可以解决问题

【讨论】:

【解决方案2】:

如果您的Image Control(如PictureBox)在运行时没有被用户移动(通过按住鼠标并拖动),您可以使用这种技术,让您可以在彼此之上显示图像。图片应具有透明背景:

public class ImageControl : Control {
   public ImageControl(){
      SetStyle(ControlStyles.Opaque, true);
   }
   public Image Image {get;set;}
   protected override CreateParams CreateParams {
      get {
          CreateParams cp = base.CreateParams;
          cp.ExStyle |= 0x20;
          return cp;
      }
   }
   protected override void OnPaint(PaintEventArgs e){
      if(Image != null) e.Graphics.DrawImage(Image, Point.Empty);
   }
}

您可以使用上面的控件代替PictureBox。通过在运行时拖动来移动此控件会导致大量闪烁。因此,如果您愿意,我认为只有 1 个使用 Region 的解决方案。在这种方法中,您必须将您的 Bitmap 转换为 Region 并将此 Region 分配给您的 Control.Region 属性。 Chris Dunaway 提供的链接对您执行此操作非常有帮助。但是我不得不说Region 的边框并不像您所期望的那样平滑。这是这种方法的不足之处。为方便起见,我将代码在这里稍作修改,此代码使用LockBits,这将优于原始代码:

public class Util {
//invert will toggle backColor to foreColor (in fact, I mean foreColor here is the Solid Color which makes your image distinct from the background).
    public static Region RegionFromBitmap(Bitmap bm, Color backColor, bool invert)
    {
        Region rgn = new Region();
        rgn.MakeEmpty();//This is very important            
        int argbBack = backColor.ToArgb();
        BitmapData data = bm.LockBits(new Rectangle(0, 0, bm.Width, bm.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
        int[] bits = new int[bm.Width * bm.Height];
        Marshal.Copy(data.Scan0, bits, 0, bits.Length);
        //
        Rectangle line = Rectangle.Empty;
        line.Height = 1;
        bool inImage = false;
        for (int i = 0; i < bm.Height; i++)
        {
            for (int j = 0; j < bm.Width; j++)
            {
                int c = bits[j + i * bm.Width];
                if (!inImage)
                {
                    if (invert ? c == argbBack : c != argbBack)
                    {
                        inImage = true;
                        line.X = j;
                        line.Y = i;
                    }
                }
                else if(invert ? c != argbBack : c == argbBack)
                {
                    inImage = false;
                    line.Width = j - line.X;
                    rgn.Union(line);
                }
            }
        }
        bm.UnlockBits(data);
        return rgn;
    }
}
//Use the code
//if your Bitmap is a PNG with transparent background, you can get the Region from it like this:
Region rgn = Util.RegionFromBitmap(yourPng, Color.FromArgb(0), false);
//if your Bitmap has a figure with solid color of Black, you can get the Region like this:
Region rgn = Util.RegionFromBitmap(yourPng, Color.Black, true);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-29
    • 2015-12-04
    • 2013-07-11
    • 2022-06-17
    • 2021-12-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多