我正在尝试在C#(.NET 3.5 SP1)中创建一个透明按钮,以便在我的WinForms应用程序中使用。我已经尝试了一切让按钮变得透明(它应该在按钮下方显示渐变背景)但它只是不起作用。
以下是我正在使用的代码:
public class ImageButton : ButtonBase, IButtonControl
{
public ImageButton()
{
this.SetStyle(
ControlStyles.SupportsTransparentBackColor |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.ResizeRedraw |
ControlStyles.UserPaint, true);
this.BackColor = Color.Transparent;
}
protected override void OnPaint(PaintEventArgs pevent)
{
Graphics g = pevent.Graphics;
g.FillRectangle(Brushes.Transparent, this.ClientRectangle);
g.DrawRectangle(Pens.Black, this.ClientRectangle);
}
// rest of class here...
}
问题是该按钮似乎是从某个地方抓取随机UI内存并从Visual Studio的UI中填充一些缓冲区(在设计模式下)。在运行时它会抓住一些零缓冲区并且完全是黑色的。
我的最终目标是在隐形按钮而不是矩形上绘制图像。然而,这个概念应该保持不变。当用户将鼠标悬停在按钮上时,会绘制一个按钮类型的形状。
有什么想法吗?
编辑:谢谢大家,以下为我工作:
public class ImageButton : Control, IButtonControl
{
public ImageButton()
{
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
SetStyle(ControlStyles.Opaque, true);
SetStyle(ControlStyles.ResizeRedraw, true);
this.BackColor = Color.Transparent;
}
protected override void OnPaint(PaintEventArgs pevent)
{
Graphics g = pevent.Graphics;
g.DrawRectangle(Pens.Black, this.ClientRectangle);
}
protected override void OnPaintBackground(PaintEventArgs pevent)
{
// don't call the base class
//base.OnPaintBackground(pevent);
}
protected override CreateParams CreateParams
{
get
{
const int WS_EX_TRANSPARENT = 0x20;
CreateParams cp = base.CreateParams;
cp.ExStyle |= WS_EX_TRANSPARENT;
return cp;
}
}
// rest of class here...
}
答案 0 :(得分:17)
WinForms(和底层User32)根本不支持透明度。然而,WinForms可以通过使用你提供的控件样式来模拟透明度 - SupportsTransparentBackColor,但在这种情况下,所有“透明”控件都可以,它允许绘制父级的背景。
ButtonBase使用一些防止使用此机制的窗口样式。我看到两个解决方案:一个是从Control(而不是ButtonBase)派生你的控件,第二个是使用Parent的DrawToBitmap来获取你的按钮下的背景,然后在OnPaint中绘制这个图像。
答案 1 :(得分:10)
在winforms中,有一些技巧可以让控件在使用透明度时正确绘制背景。您可以将此代码添加到OnPaint或OnPaintBackground以获取正在绘制的背景中的控件:
if (this.Parent != null)
{
GraphicsContainer cstate = pevent.Graphics.BeginContainer();
pevent.Graphics.TranslateTransform(-this.Left, -this.Top);
Rectangle clip = pevent.ClipRectangle;
clip.Offset(this.Left, this.Top);
PaintEventArgs pe = new PaintEventArgs(pevent.Graphics, clip);
//paint the container's bg
InvokePaintBackground(this.Parent, pe);
//paints the container fg
InvokePaint(this.Parent, pe);
//restores graphics to its original state
pevent.Graphics.EndContainer(cstate);
}
else
base.OnPaintBackground(pevent); // or base.OnPaint(pevent);...
答案 2 :(得分:1)
我不确定ButtonBase支持透明度......你检查过了吗?
我编写了许多透明控件,但我总是继承自Control或UserControl。
如果你想阻止控件绘制它的背景 - 你应该重写OnPaintBackground而不是OnPaint而不是调用基类。
使用Brushes.Transparent填充一个矩形很有趣 - 你在那里画的是一种看不见的颜色。或者换句话说:它什么都不做!
答案 3 :(得分:1)
我知道这个问题已经过时了,但是如果有人不想创建控件来执行此操作,我会从其他文章中提取此代码,并将其更改为扩展方法。
public static void ToTransparent(this System.Windows.Forms.Button Button,
System.Drawing.Color TransparentColor)
{
Bitmap bmp = ((Bitmap)Button.Image);
bmp.MakeTransparent(TransparentColor);
int x = (Button.Width - bmp.Width) / 2;
int y = (Button.Height - bmp.Height) / 2;
Graphics gr = Button.CreateGraphics();
gr.DrawImage(bmp, x, y);
}
呼叫如:
buttonUpdate.ToTransparent(Color.Magenta);