Я собираюсь дать вам пару советов о том, как действовать.
Начните с этого прозрачного элемента управления (TransparentPanel
).
Этот класс является производным от Panel
. Это первый выбор: Panel
- это правильный элемент управления для наследования или расширения для этой задачи? Может быть, а может и нет.
Например, Panel
- это контейнер. Вам нужны особенности контейнера, здесь? Контейнер очень много значит. Он наследует ScrollableControl и имеет ContainerControl среди своих стилей окна. Он уже с багажом.
Вместо этого вы можете выбрать Label
, он легкий. Или создайте UserControl.
Я не думаю, что есть абсолютный лучший выбор . Это зависит от того, для чего используется этот пользовательский элемент управления. Вы должны попробовать это.
class TransparentPanel : Panel
{
internal const int WS_EX_TRANSPARENT = 0x00000020;
public TransparentPanel() => InitializeComponent();
protected void InitializeComponent()
{
this.SetStyle(ControlStyles.AllPaintingInWmPaint |
ControlStyles.Opaque |
ControlStyles.ResizeRedraw |
ControlStyles.SupportsTransparentBackColor |
ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, false);
}
protected override CreateParams CreateParams
{
get {
CreateParams parameters = base.CreateParams;
parameters.ExStyle |= WS_EX_TRANSPARENT;
return parameters;
}
}
}
Примечания
Здесь
ControlStyles.SupportsTransparentBackColor устанавливается явно. Класс
Panel
уже поддерживает это. В любом случае он указан, поскольку дает представление о том, что представляет собой этот пользовательский элемент управления для простого чтения в его конструкторе.
Также для ControlStyles.OptimizedDoubleBuffer
установлено значение false.
Это предотвращает любое вмешательство системы в окраску элемента управления. Там нет кэширования , пользовательский элемент управления отображается новым, когда он недействителен. Форма контейнера предпочтительно должна иметь свойство DoubleBuffer
, установленное на true
, но вы можете проверить его без, чтобы увидеть, есть ли разница.
Этот Пользовательский элемент управления (не путать с UserControl
) полностью прозрачен. Он не рисует свой фон. Но на его поверхности можно рисовать что угодно.
Воспользуйтесь ссылками, размещенными ранее:
- Это Полупрозрачная метка (без фоновой окраски, отключено DoubleDuffering
)
- Reza Aghaei прозрачная панель (используя Opacity
по-другому)
- TaW S Панель сетки (Color.Transparent
и DoubleBuffer
)
- Эти примечания: Причины, по которым ярлык WinForms не хочет быть прозрачным?
4 разных способа получить один и тот же результат. Какой из них выбрать, зависит от контекста / пункта назначения.
Совет времени разработки : при тестировании пользовательских функций управления не забывайте всегда перестраивать проект. Может случиться, что CustomControl
, сброшенный на Form
из Toolbox
, не будет обновлен новыми изменениями при запуске проекта.
Кроме того, если вы добавляете или удаляете свойства , вам необходимо удалить элемент управления, перестроить и добавить новый в форму.
Если вы этого не сделаете, есть очень хороший шанс, что ваши изменения / дополнения будут полностью проигнорированы, и вы продолжаете тестировать функции, которые никогда не вступают в игру.
Пример, использующий 2 перекрывающихся пользовательских элемента управления.
(используя обычай TransparentPanel
)
Это тестовый код, используемый для создания этих чертежей:
- Создайте новый пользовательский элемент управления, используя класс TransparentPanel
, показанный ранее:
- Бросить два TransparentPanel
объектов на тестовой форме
- Назначьте TransparentPanel1
и TransparentPanel2
обработчикам событий transparentPanel1_Paint
и transparentPanel2_Paint
.
- Перекрыть две прозрачные панели, , убедившись, что вы не вложите их по ошибке .
- Адаптируйте остальную часть кода (вам нужна только кнопка, здесь с именем btnRotate
, назначьте обработчик btnRotate_Click
)
private System.Windows.Forms.Timer RotateTimer = null;
private float RotationAngle1 = 90F;
private float RotationAngle2 = 0F;
public bool RotateFigures = false;
public form1()
{
InitializeComponent();
RotateTimer = new Timer();
RotateTimer.Interval = 50;
RotateTimer.Enabled = false;
RotateTimer.Tick += new EventHandler(this.RotateTick);
}
protected void RotateTick(object sender, EventArgs e)
{
RotationAngle1 += 10F;
RotationAngle2 += 10F;
transparentPanel1.Invalidate();
transparentPanel2.Invalidate();
}
private void btnRotate_Click(object sender, EventArgs e)
{
RotateTimer.Enabled = !RotateTimer.Enabled;
if (RotateTimer.Enabled == false)
{
RotateFigures = false;
RotationAngle1 = 90F;
RotationAngle2 = 0F;
}
else
{
RotateFigures = true;
}
}
private void transparentPanel1_Paint(object sender, PaintEventArgs e)
{
if (!RotateFigures) return;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
e.Graphics.CompositingMode = CompositingMode.SourceOver;
Rectangle rect = transparentPanel1.ClientRectangle;
Rectangle rectInner = rect;
using (Pen transpPen = new Pen(transparentPanel1.Parent.BackColor, 10))
using (Pen penOuter = new Pen(Color.SteelBlue, 8))
using (Pen penInner = new Pen(Color.Teal, 8))
using (Matrix m1 = new Matrix())
using (Matrix m2 = new Matrix())
{
m1.RotateAt(-RotationAngle1, new PointF(rect.Width / 2, rect.Height / 2));
m2.RotateAt(RotationAngle1, new PointF(rect.Width / 2, rect.Height / 2));
rect.Inflate(-(int)penOuter.Width, -(int)penOuter.Width);
rectInner.Inflate(-(int)penOuter.Width * 3, -(int)penOuter.Width * 3);
e.Graphics.Transform = m1;
e.Graphics.DrawArc(transpPen, rect, -4, 94);
e.Graphics.DrawArc(penOuter, rect, -90, 90);
e.Graphics.ResetTransform();
e.Graphics.Transform = m2;
e.Graphics.DrawArc(transpPen, rectInner, 190, 100);
e.Graphics.DrawArc(penInner, rectInner, 180, 90);
}
}
private void transparentPanel2_Paint(object sender, PaintEventArgs e)
{
if (!RotateFigures) return;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
e.Graphics.CompositingMode = CompositingMode.SourceOver;
Rectangle rect = transparentPanel2.ClientRectangle;
Rectangle rectInner = rect;
using (Pen transpPen = new Pen(transparentPanel2.Parent.BackColor, 10))
using (Pen penOuter = new Pen(Color.Orange, 8))
using (Pen penInner = new Pen(Color.DarkRed, 8))
using (Matrix m1 = new Matrix())
using (Matrix m2 = new Matrix())
{
m1.RotateAt(RotationAngle2, new PointF(rect.Width / 2, rect.Height / 2));
m2.RotateAt(-RotationAngle2, new PointF(rect.Width / 2, rect.Height / 2));
rect.Inflate(-(int)penOuter.Width, -(int)penOuter.Width);
rectInner.Inflate(-(int)penOuter.Width * 3, -(int)penOuter.Width * 3);
e.Graphics.Transform = m1;
e.Graphics.DrawArc(transpPen, rect, -4, 94);
e.Graphics.DrawArc(penOuter, rect, 0, 90);
e.Graphics.ResetTransform();
e.Graphics.Transform = m2;
e.Graphics.DrawArc(transpPen, rectInner, 190, 100);
e.Graphics.DrawArc(penInner, rectInner, 180, 90);
}
}