C# 以灰度显示窗体

C# 以灰度显示窗体,c#,winforms,C#,Winforms,是否可以以灰度绘制任何形状(无需替代绘制方法) 如果在Modal()对话框中显示窗体,则不会将其父窗体显示为灰度。 我在VisualStudio扩展管理器中注意到了这一点。如果progressbar正在下载包,则底层窗口将灰显 我在想: private void Button1_Click(object sender, EventArgs e) { using (var dialog = new Form2()) { SetGrayscale(this, true

是否可以以灰度绘制任何形状(无需替代绘制方法)

如果在Modal()对话框中显示窗体,则不会将其父窗体显示为灰度。 我在VisualStudio扩展管理器中注意到了这一点。如果progressbar正在下载包,则底层窗口将灰显

我在想:

private void Button1_Click(object sender, EventArgs e)
{
    using (var dialog = new Form2())
    {
        SetGrayscale(this, true);
        dialog.ShowDialog();
        SetGrayscale(this, false);
    }
}
更新

仅设置
Form.Enabled=false不是我想要的。这看起来不如我的表单的灰度表示。

我认为compiz
Windows decorator for Linux在没有响应的应用程序中做到了这一点。

尝试类似的方法,它适用于大多数简单的控件(您需要递归到容器中才能正确切换所有控件)

private void按钮1\u单击(对象发送者,事件参数e)
{
使用(var dialog=new Form())
{
字典oldcolors=新字典();
foreach(此.Controls中的控制ctl)
{
添加(ctl,Tuple.Create(ctl.BackColor,ctl.ForeColor));
//获取颜色的粗略平均强度
intbg=(ctl.BackColor.R+ctl.BackColor.G+ctl.BackColor.B)/3;
intfg=(ctl.ForeColor.R+ctl.ForeColor.G+ctl.ForeColor.B)/3;
ctl.BackColor=Color.FromArgb(bg,bg,bg);
ctl.ForeColor=Color.FromArgb(fg,fg,fg);
}
dialog.ShowDialog();
foreach(此.Controls中的控制ctl)
{
ctl.BackColor=oldcolors[ctl].Item1;
ctl.ForeColor=oldcolors[ctl].Item2;
}
}
}

我不认为有直接实现的方法——我认为所有表单都是用sRGB呈现的。
一种常见的方法是将表单的副本作为图像覆盖在表单上(这很简单),然后将其通过一个简单的GDI矩阵进行去饱和。

如前所述,这样做的方法是在现有表单的顶部覆盖另一个控件/表单,并使其在顶部呈现该控件/表单的灰度版本,您可以使用正好放置在原始窗体上的附加窗体,或者使用类似于放置在所有其他控件顶部的控件的方式来执行此操作

下面是一个工作示例,演示了在第一个表单的客户端区域上放置另一个表单时如何执行此操作。如何使用它

using (Grayscale(this))
{
    MessageBox.Show("Test");
}
实施

public static Form Grayscale(Form tocover)
{
    var frm = new Form
        {
            FormBorderStyle = FormBorderStyle.None,
            ControlBox = false,
            ShowInTaskbar = false,
            StartPosition = FormStartPosition.Manual,
            AutoScaleMode = AutoScaleMode.None,
            Location = tocover.PointToScreen(tocover.ClientRectangle.Location),
            Size = tocover.ClientSize
        };
    frm.Paint += (sender, args) =>
        {
            var bmp = GetFormImageWithoutBorders(tocover);
            bmp = ConvertToGrayscale(bmp);
            args.Graphics.DrawImage(bmp, args.ClipRectangle.Location);
        };

    frm.Show(tocover);
    return frm;
}

private static Bitmap ConvertToGrayscale(Bitmap source)
{
    var bm = new Bitmap(source.Width, source.Height);
    for (int y = 0; y < bm.Height; y++)
    {
        for (int x = 0; x < bm.Width; x++)
        {
            Color c = source.GetPixel(x, y);
            var luma = (int)(c.R * 0.3 + c.G * 0.59 + c.B * 0.11);
            bm.SetPixel(x, y, Color.FromArgb(luma, luma, luma));
        }
    }
    return bm;
}

private static Bitmap GetControlImage(Control ctl)
{
    var bm = new Bitmap(ctl.Width, ctl.Height);
    ctl.DrawToBitmap(bm, new Rectangle(0, 0, ctl.Width, ctl.Height));
    return bm;
}

private static Bitmap GetFormImageWithoutBorders(Form frm)
{
    // Get the form's whole image.
    using (Bitmap wholeForm = GetControlImage(frm))
    {
        // See how far the form's upper left corner is
        // from the upper left corner of its client area.
        Point origin = frm.PointToScreen(new Point(0, 0));
        int dx = origin.X - frm.Left;
        int dy = origin.Y - frm.Top;

        // Copy the client area into a new Bitmap.
        int wid = frm.ClientSize.Width;
        int hgt = frm.ClientSize.Height;
        var bm = new Bitmap(wid, hgt);
        using (Graphics gr = Graphics.FromImage(bm))
        {
            gr.DrawImage(wholeForm, 0, 0,
                new Rectangle(dx, dy, wid, hgt),
                GraphicsUnit.Pixel);
        }
        return bm;
    }
}
公共静态表单灰度(表单tocover)
{
var frm=新表格
{
FormBorderStyle=FormBorderStyle.None,
ControlBox=false,
ShowInTaskbar=false,
StartPosition=FormStartPosition.Manual,
AutoScaleMode=AutoScaleMode.None,
Location=tocover.PointToScreen(tocover.ClientRectangle.Location),
Size=tocover.ClientSize
};
frm.Paint+=(发送方,参数)=>
{
var bmp=GetFormImageWithoutBorders(tocover);
bmp=转换光线比例(bmp);
args.Graphics.DrawImage(bmp,args.ClipRectangle.Location);
};
首次展览(tocover);
返回frm;
}
专用静态位图ConvertToGrayscale(位图源)
{
var bm=新位图(source.Width、source.Height);
对于(int y=0;y
请注意:

  • Paint
    的实现相当差-实际上它应该使用双缓冲,以便将灰度图像预渲染到缓冲的图形上下文中,因此Paint方法只需要绘制预绘制的缓冲区内容。看
  • ConvertToGrayscale
    有点慢,但可能会加快速度
  • 如果有人出于任何原因设法移动原始表单,事情就会出问题
  • 图像是静态的,如果基本控件被重画,那么理想情况下顶部窗体也应该重画。我不确定如何最好地检测另一个表单的某个部分何时失效
如果我有时间,我会尝试解决其中的一些问题,但以上内容至少给出了总体思路

注意,在WPF中,这将容易得多

资料来源:


我用来使窗体变灰的一个快速而肮脏的技巧是在窗体中添加一个附加控件。该控件将拍摄其父控件的照片(
Form.DrawToBitmap()
),对其进行操作,将其用作背景,并将最大化以填充整个表单。灰度,而不是greyscale@Indeera两者都是正确的@Kip9000:看情况,英式英语还是美式英语?需要一些改进,但乍一看还是不错的。
public static Form Grayscale(Form tocover)
{
    var frm = new Form
        {
            FormBorderStyle = FormBorderStyle.None,
            ControlBox = false,
            ShowInTaskbar = false,
            StartPosition = FormStartPosition.Manual,
            AutoScaleMode = AutoScaleMode.None,
            Location = tocover.PointToScreen(tocover.ClientRectangle.Location),
            Size = tocover.ClientSize
        };
    frm.Paint += (sender, args) =>
        {
            var bmp = GetFormImageWithoutBorders(tocover);
            bmp = ConvertToGrayscale(bmp);
            args.Graphics.DrawImage(bmp, args.ClipRectangle.Location);
        };

    frm.Show(tocover);
    return frm;
}

private static Bitmap ConvertToGrayscale(Bitmap source)
{
    var bm = new Bitmap(source.Width, source.Height);
    for (int y = 0; y < bm.Height; y++)
    {
        for (int x = 0; x < bm.Width; x++)
        {
            Color c = source.GetPixel(x, y);
            var luma = (int)(c.R * 0.3 + c.G * 0.59 + c.B * 0.11);
            bm.SetPixel(x, y, Color.FromArgb(luma, luma, luma));
        }
    }
    return bm;
}

private static Bitmap GetControlImage(Control ctl)
{
    var bm = new Bitmap(ctl.Width, ctl.Height);
    ctl.DrawToBitmap(bm, new Rectangle(0, 0, ctl.Width, ctl.Height));
    return bm;
}

private static Bitmap GetFormImageWithoutBorders(Form frm)
{
    // Get the form's whole image.
    using (Bitmap wholeForm = GetControlImage(frm))
    {
        // See how far the form's upper left corner is
        // from the upper left corner of its client area.
        Point origin = frm.PointToScreen(new Point(0, 0));
        int dx = origin.X - frm.Left;
        int dy = origin.Y - frm.Top;

        // Copy the client area into a new Bitmap.
        int wid = frm.ClientSize.Width;
        int hgt = frm.ClientSize.Height;
        var bm = new Bitmap(wid, hgt);
        using (Graphics gr = Graphics.FromImage(bm))
        {
            gr.DrawImage(wholeForm, 0, 0,
                new Rectangle(dx, dy, wid, hgt),
                GraphicsUnit.Pixel);
        }
        return bm;
    }
}