Рисование прозрачной кнопки
Я пытаюсь создать прозрачную кнопку в С# (.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 (в режиме разработки). Во время выполнения он захватывает некоторый нулевой буфер и полностью черный.
Моя конечная цель - нарисовать изображение на невидимой кнопке вместо прямоугольника. Однако концепция должна оставаться прежней. Когда пользователь нависает над кнопкой, формируется форма кнопки.
Любые идеи?
EDIT: Спасибо всем, следующее работало для меня:
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...
}
Ответы
Ответ 1
WinForms (и базовый User32) вообще не поддерживает прозрачность. WinForms, однако, может имитировать прозрачность, используя стиль управления, который вы предоставляете, - SupportsTransparentBackColor, но в этом случае все, что делает "прозрачный" элемент управления, позволяют рисовать родительский фон.
ButtonBase использует некоторые стили окон, которые не позволяют работать с этим механизмом. Я вижу два решения: один - вывести свой контроль из Control (вместо ButtonBase), а второй - использовать Parent DrawToBitmap для получения фона под вашей кнопкой, а затем нарисовать это изображение в OnPaint.
Ответ 2
В 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 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);...
Ответ 3
Я не уверен, что ButtonBase поддерживает прозрачность... вы проверили это?
Я написал несколько прозрачных элементов управления, но я всегда унаследовал их от Control или UserControl.
Если вы хотите заблокировать контрольную картину в фоновом режиме - вы должны переопределить OnPaintBackground вместо OnPaint и не вызывать базовый класс.
Заполнение прямоугольника Brushes.Transparent - это смешно, хотя - вы рисуете невидимым цветом над тем, что там есть. Или иначе: ничего не делает!
Ответ 4
Я знаю, что этот вопрос старый, но если кто-то не хочет создавать элемент управления для этого, я придумал этот код из другой статьи и изменил его метод расширения.
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);