Winforms 控件中的阴影?

发布于 2024-08-25 16:17:59 字数 41 浏览 7 评论 0原文

有没有办法给控件添加阴影?

有没有具有此功能的控件?

is there a way to add a drop shadow to controls?

are there any controls out there with this feature?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

微凉徒眸意 2024-09-01 16:17:59

您必须像这样覆盖 CreateParams 属性:

private const int CS_DROPSHADOW = 0x00020000;
protected override CreateParams CreateParams
{
    get
    {
        // add the drop shadow flag for automatically drawing
        // a drop shadow around the form
        CreateParams cp = base.CreateParams;
        cp.ClassStyle |= CS_DROPSHADOW;
        return cp;
    }
}

You have to overwrite the CreateParamsproperty like this:

private const int CS_DROPSHADOW = 0x00020000;
protected override CreateParams CreateParams
{
    get
    {
        // add the drop shadow flag for automatically drawing
        // a drop shadow around the form
        CreateParams cp = base.CreateParams;
        cp.ClassStyle |= CS_DROPSHADOW;
        return cp;
    }
}
坠似风落 2024-09-01 16:17:59

这个问题已经存在了6年了,需要一个答案。我希望任何需要这样做的人都可以从我的解决方案中推断出任何控制集的答案。我有一个面板,想要在每个子控件下方绘制阴影 - 在本例中是一个或多个面板(但该解决方案应该适用于其他控件类型,只需进行一些小的代码更改)。

由于控件的阴影必须绘制在该控件容器的表面上,因此我们首先向容器的 Paint() 事件添加一个函数。

Container.Paint += dropShadow;

dropShadow() 看起来像这样:

    private void dropShadow(object sender, PaintEventArgs e)
    {
        Panel panel = (Panel)sender;
        Color[] shadow = new Color[3];
        shadow[0] = Color.FromArgb(181, 181, 181);
        shadow[1] = Color.FromArgb(195, 195, 195);
        shadow[2] = Color.FromArgb(211, 211, 211);
        Pen pen = new Pen(shadow[0]);
        using (pen)
        {
            foreach (Panel p in panel.Controls.OfType<Panel>())
            {
                Point pt = p.Location;
                pt.Y += p.Height;
                for (var sp = 0; sp < 3; sp++)
                {
                    pen.Color = shadow[sp];
                    e.Graphics.DrawLine(pen, pt.X, pt.Y, pt.X + p.Width - 1, pt.Y);
                    pt.Y++;
                }
            }
        }
    }

显然,您可以从容器的集合中选择不同的控件类型,并且可以通过一些细微的调整来改变阴影的颜色和深度。

This question has been around for 6 years and needs an answer. I hope that anyone who needs to do this can extrapolate an answer for any control set from my solution. I had a panel and wanted to draw a drop shadow underneath every child control - in this instance one or more panels (but the solution should hold good for other control types with some minor code changes).

As the drop shadow for a control has to be drawn on the surface of that control's container we start by adding a function to the container's Paint() event.

Container.Paint += dropShadow;

dropShadow() looks like this:

    private void dropShadow(object sender, PaintEventArgs e)
    {
        Panel panel = (Panel)sender;
        Color[] shadow = new Color[3];
        shadow[0] = Color.FromArgb(181, 181, 181);
        shadow[1] = Color.FromArgb(195, 195, 195);
        shadow[2] = Color.FromArgb(211, 211, 211);
        Pen pen = new Pen(shadow[0]);
        using (pen)
        {
            foreach (Panel p in panel.Controls.OfType<Panel>())
            {
                Point pt = p.Location;
                pt.Y += p.Height;
                for (var sp = 0; sp < 3; sp++)
                {
                    pen.Color = shadow[sp];
                    e.Graphics.DrawLine(pen, pt.X, pt.Y, pt.X + p.Width - 1, pt.Y);
                    pt.Y++;
                }
            }
        }
    }

Clearly you can pick a different control type from the container's collection and you can vary the colour and depth of the shadow with some minor tweaks.

路还长,别太狂 2024-09-01 16:17:59

最上面的答案实际上确实生成了阴影,但我个人对它并不满意,原因有几个:

  • 它只适用于矩形(当然,WinForms 控件都是矩形,但我们可能想在其他情况下使用它)
  • 更多重要的是:这并不顺利。它看起来不像其他程序中的其他阴影看起来那么自然。
  • 最后,配置有点烦人。

因此,由于所有这些事情,我最终为我的项目编写了自己的内容,我想我应该在这里分享它:

public partial class Form1 : Form
{
    List<Control> shadowControls = new List<Control>();
    Bitmap shadowBmp = null;
    public Form1()
    {
        InitializeComponent();
        shadowControls.Add(panel1);
        this.Refresh();
    }

    private void Form1_Paint(object sender, PaintEventArgs e)
    {
        if (shadowBmp == null || shadowBmp.Size != this.Size)
        {
            shadowBmp?.Dispose();
            shadowBmp = new Bitmap(this.Width, this.Height, PixelFormat.Format32bppArgb);
        }
        foreach (Control control in shadowControls)
        {
            using (GraphicsPath gp = new GraphicsPath())
            {
                gp.AddRectangle(new Rectangle(control.Location.X, control.Location.Y, control.Size.Width, control.Size.Height));
                DrawShadowSmooth(gp, 100, 60, shadowBmp);
            }
            e.Graphics.DrawImage(shadowBmp, new Point(0, 0));
        }
    }
    private static void DrawShadowSmooth(GraphicsPath gp, int intensity, int radius, Bitmap dest)
    {
        using (Graphics g = Graphics.FromImage(dest))
        {
            g.Clear(Color.Transparent);
            g.CompositingMode = CompositingMode.SourceCopy;
            double alpha = 0;
            double astep = 0;
            double astepstep = (double)intensity / radius / (radius / 2D);
            for (int thickness = radius; thickness > 0; thickness--)
            {
                using (Pen p = new Pen(Color.FromArgb((int)alpha, 0, 0, 0), thickness))
                {
                    p.LineJoin = LineJoin.Round;
                    g.DrawPath(p, gp);
                }
                alpha += astep;
                astep += astepstep;
            }
        }
    }
}

在此实现中,添加到 shadowControls 的所有控件都将用平滑的颜色绘制阴影。您应该能够对非矩形形状实现此功能,因为生成阴影的主函数采用 GraphicsPath。请注意,在将阴影绘制到表单之前,将阴影绘制到另一个位图非常重要,因为 main 函数需要 SourceCopy 的合成模式才能工作,这意味着如果您不将其绘制到另一个表面首先,阴影后面的任何东西都将被完全替换,并且透明度方面毫无用处。我正在回答 10 年前的问题,但希望这对某人有帮助!

The top answer does in fact generate a shadow, but I personally wasn't satisfied with it for a few reasons:

  • It only works for rectangles (granted, WinForms controls are all rectangles, but we might want to use this in other cases)
  • More importantly: It's not smooth. It doesn't look as natural as other shadows in other programs look.
  • Finally, it's slightly annoying to configure.

So, because of all these things, I ended up writing my own for my project and I thought I'd share it here:

public partial class Form1 : Form
{
    List<Control> shadowControls = new List<Control>();
    Bitmap shadowBmp = null;
    public Form1()
    {
        InitializeComponent();
        shadowControls.Add(panel1);
        this.Refresh();
    }

    private void Form1_Paint(object sender, PaintEventArgs e)
    {
        if (shadowBmp == null || shadowBmp.Size != this.Size)
        {
            shadowBmp?.Dispose();
            shadowBmp = new Bitmap(this.Width, this.Height, PixelFormat.Format32bppArgb);
        }
        foreach (Control control in shadowControls)
        {
            using (GraphicsPath gp = new GraphicsPath())
            {
                gp.AddRectangle(new Rectangle(control.Location.X, control.Location.Y, control.Size.Width, control.Size.Height));
                DrawShadowSmooth(gp, 100, 60, shadowBmp);
            }
            e.Graphics.DrawImage(shadowBmp, new Point(0, 0));
        }
    }
    private static void DrawShadowSmooth(GraphicsPath gp, int intensity, int radius, Bitmap dest)
    {
        using (Graphics g = Graphics.FromImage(dest))
        {
            g.Clear(Color.Transparent);
            g.CompositingMode = CompositingMode.SourceCopy;
            double alpha = 0;
            double astep = 0;
            double astepstep = (double)intensity / radius / (radius / 2D);
            for (int thickness = radius; thickness > 0; thickness--)
            {
                using (Pen p = new Pen(Color.FromArgb((int)alpha, 0, 0, 0), thickness))
                {
                    p.LineJoin = LineJoin.Round;
                    g.DrawPath(p, gp);
                }
                alpha += astep;
                astep += astepstep;
            }
        }
    }
}

In this implementation, all Controls added to the shadowControls will be painted with a smooth shadow. You should be able to implement this for non-rectangular shapes because the main function to generate the shadows takes a GraphicsPath. Please note that it's important you draw the shadow to another bitmap before drawing it to the form because the main function requires a compositing mode of SourceCopy to work, which means if you don't draw it to another surface first anything behind the shadow will be completely replaced and the transparency aspect is useless. I'm on a roll of answering 10-year-old questions, but hopefully, this helps someone!

亽野灬性zι浪 2024-09-01 16:17:59

如果您可以使用 WPF 中的替代方案,我不认为 Windows 窗体中存在替代方案,因为 GDI+ 的功能有限。

There is in WPF if you can stretch to using that instead, I don't believe there is an alternative in Windows Forms due to the limited capabilities of GDI+.

最佳男配角 2024-09-01 16:17:59

一种方法是将控件放入具有以下属性的表格布局中:

  • 3 列(5px、100%、5px)
  • 3 行(5px、100%、5px)
  • 您的控件
    • 左上角 (0,0)
    • 列跨度 = 2 且行跨度 = 2
    • 0 边距
    • 停靠栏设置为填充
  • 添加面板
    • 将阴影颜色设置为背景
    • 行 = 1,列 = 3
    • 0 边距
    • 停靠栏设置为填充
  • 添加另一个面板
    • 将阴影颜色设置为背景
    • 行 = 3,列 = 1,列跨度 = 2
    • 0 边距
    • 停靠栏设置为填充

这将使您可以通过调整外部列和行的大小来灵活调整大小。下面是一个快速草图,可直观地看到设计器中表格布局的外观:

表格布局草图

表格布局草图 2

应用程序中最终结果的实际屏幕截图:

截图

One way would be to put your control in a table layout with these properties:

  • 3 columns (5px, 100%, 5px)
  • 3 rows (5px, 100%, 5px)
  • Your control
    • top left corner (0,0)
    • columnSpan = 2 and rowSpan = 2
    • 0 margin
    • Dock set to fill
  • Add a panel
    • set with your shadow color as the background
    • row = 1, column = 3
    • 0 margin
    • Dock set to fill
  • Add another panel
    • set with your shadow color as the background
    • row = 3, column = 1, columnSpan = 2
    • 0 margin
    • Dock set to fill

This will give you flexibility over sizing by sizing the outer columns and rows. Here is a quick sketch to visualize what the table layout would look like in the designer:

Table Layout Sketch

Table Layout Sketch 2

Actual screenshot of the end result in an application:

Screenshot

醉态萌生 2024-09-01 16:17:59

这是一个有争议的观点,你不用代码就可以做到。
将主面板边框样式设置为“固定单一”。
在其下方创建 3 个面板,每个方向各大 1 像素。
3 个面板均采用浅灰色。
不完美但便宜又简单。

带有伪阴影的面板

Here's a controversial opinion, you do it without code.
Set your main panel Border Style to Fixed Single.
Create 3 panels below it, each 1 pixel larger in every direction.
Each of the 3 panels is of a lighter shade of gray.
Not perfect but cheap and easy.

panel with pseudo-shadow

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文