试试这个透明的标签自定义控件。
它与您尝试构建的 Panel Control 相似,但与 Panel (ScrollableControl) 略有不同:Panel 在绘制背景时会生成persistence 的形式(无论您是否拥有设置ControlStyles.Opaque = false,因此它没有初始背景)导致背景(颜色是否带有Alpha)覆盖前一个图层。
标签控件没有这个问题。
将它拖到一个容器(窗体或其他子容器)上,然后将其拉伸到任何其他控件上:它覆盖的所有控件都将在 下绘制,并保留 translucency。
- 您可以将控件覆盖在表单中的其他容器(包括 GroupBox)内或子容器内。
- 您无法覆盖正在运行的 ProgressBar(无需稍微调整自定义控件)。
查看类似的实现:
Translucent circular Control with text
还有关于使用透明面板的注意事项在这里:
Transparent Overlapping Circular Progress Bars (Custom Control)
使用透明标签或图片框(您也可以使用它来替换此处提供的代码中的标签)无法实现相同的效果。
在 cmets 中链接的覆盖形式 Hans Passant:
Draw semi transparent overlay image all over the windows form having some controls
当然效果很好;这是一种替代方法,可能在设计时更容易使用,但显然并非在所有情况下都有用(例如,当您必须完全覆盖表单时)。
请注意,我已将Opacity 属性值的范围从0-100 更改为0-255:我更喜欢这种方式。当然你可以使用任何你喜欢的数字范围。
▶ 你可以覆盖可滚动控件,作为 TextBox/RichTextBox,但你不能让它以任何方式滚动,它会毁了派对(如果你忘记/不能足够快地使半透明覆盖失效)。
▶ 同样重要的是:我测试代码的最低 .Net 版本是 .Net Framework 4.8(它已经改变/更新了许多部门的很多东西)
使用 System.ComponentModel;
使用 System.Drawing;
使用 System.Runtime.InteropServices;
使用 System.Windows.Forms;
[DesignerCategory("code")]
public class LabelTransparent : Label, IMessageFilter
{
private const int WS_EX_TRANSPARENT = 0x0020;
private const int WM_PAINT = 0x000F;
private IntPtr m_TopLevelWindow = IntPtr.Zero;
private int m_Opacity = 127;
public LabelTransparent()
{
SetStyle(ControlStyles.Opaque | ControlStyles.Selectable |
ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, false);
}
protected override CreateParams CreateParams {
get {
CreateParams cp = base.CreateParams;
cp.ExStyle |= WS_EX_TRANSPARENT;
return cp;
}
}
public bool PreFilterMessage(ref Message m)
{
if (IsHandleCreated && m_TopLevelWindow != IntPtr.Zero && m.Msg == WM_PAINT) {
var handle = m.HWnd;
if (GetAncestor(handle, 3) != m_TopLevelWindow) return false;
if (handle != this.Handle && handle != Parent?.Handle) {
GetWindowRect(handle, out RECT rect);
if (RectangleToScreen(ClientRectangle).IntersectsWith(rect.ToRectangle())) {
InvalidateOverlapped();
return true;
}
}
}
return false;
}
protected override void OnHandleCreated(EventArgs e)
{
if (!DesignMode) Application.AddMessageFilter(this);
m_TopLevelWindow = FindForm().Handle;
base.OnHandleCreated(e);
}
protected override void OnHandleDestroyed(EventArgs e)
{
if (!DesignMode) Application.RemoveMessageFilter(this);
m_TopLevelWindow = IntPtr.Zero;
base.OnHandleDestroyed(e);
}
protected override void OnLayout(LayoutEventArgs e)
{
base.OnLayout(e);
AutoSize = false;
base.Text = string.Empty;
}
public new Color BackColor {
get => base.BackColor;
set {
if (base.BackColor == value) return;
base.BackColor = value;
InvalidateOverlapped();
}
}
[DefaultValue(127)]
public int Opacity {
get => m_Opacity;
set {
if (m_Opacity == value) return;
m_Opacity = Math.Max(Math.Min(value, 255), 0);
InvalidateOverlapped();
}
}
protected override void OnPaint(PaintEventArgs e)
{
using (var brush = new SolidBrush(Color.FromArgb(m_Opacity, BackColor))) {
e.Graphics.FillRectangle(brush, ClientRectangle);
}
}
private void InvalidateOverlapped() {
if (Parent == null || Parent.Handle == IntPtr.Zero) return;
Parent.Invalidate(Bounds, true);
Parent.Update();
}
[DllImport("user32.dll")]
private static extern IntPtr GetAncestor(IntPtr hwnd, uint gaFlags);
[DllImport("User32.dll", SetLastError = true)]
private static extern bool GetWindowRect(IntPtr hWnd, out RECT rc);
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
public RECT(int x, int y, int width, int height) {
Left = x;
Top = y;
Right = x + width;
Bottom = y + height;
}
public Rectangle ToRectangle() => Rectangle.FromLTRB(Left, Top, Right, Bottom);
}
}