【问题标题】:Panel overlay not drawn over Labels面板覆盖未绘制在标签上
【发布时间】:2021-06-21 15:55:59
【问题描述】:

我在 GroupBox 等中有多个 GroupBox 和标签。
我正在尝试制作一个简单的半透明面板来覆盖所有控件,但它只是拒绝正常工作。

我正在使用此自定义面板控件,但它不包括标签和其他控件:标签通过它显示但您无法单击它们。不知道这是什么魔法

有没有人有解决方案来覆盖和调暗其他控件?

using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;

public class ExtendedPanel : Panel
{
    private const int WS_EX_TRANSPARENT = 0x20;

    public ExtendedPanel() {
        SetStyle(ControlStyles.Opaque, true);
    }
    
    private int opacity = 50;

    [DefaultValue(50)]
    public int Opacity {
        get {
            return this.opacity;
        }
        set {
            if (value < 0 || value > 100)
                throw new ArgumentException("value must be between 0 and 100");
            this.opacity = value;
          }
      }

    protected override CreateParams CreateParams {
        get {
            CreateParams cp = base.CreateParams;
            cp.ExStyle = cp.ExStyle | WS_EX_TRANSPARENT;
            return cp;
        }
    }
    protected override void OnPaint(PaintEventArgs e) {
        using (var brush = new SolidBrush(Color.FromArgb(this.opacity * 255 / 100, this.BackColor))) {
            e.Graphics.FillRectangle(brush, this.Parent.ClientRectangle);
        }
        base.OnPaint(e);
    }
}

【问题讨论】:

标签: c# winforms graphics overlay transparency


【解决方案1】:

试试这个透明的标签自定义控件。

它与您尝试构建的 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);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-12
    • 2013-05-22
    • 1970-01-01
    • 1970-01-01
    • 2018-09-12
    • 1970-01-01
    • 1970-01-01
    • 2011-02-17
    相关资源
    最近更新 更多