是否可以以灰度绘制任何表格(不覆盖Paint方法)。
如果我在模态()对话框中显示表单,我不会将其父级显示为灰度。 我在Visual Studio Extension Manager中注意到了这一点。如果进度条正在下载包,则基础窗口将显示为灰色。
我在想这个:
private void Button1_Click(object sender, EventArgs e)
{
using (var dialog = new Form2())
{
SetGrayscale(this, true);
dialog.ShowDialog();
SetGrayscale(this, false);
}
}
更新
设置Form.Enabled = false;
不是我想要的。这看起来不像我的表单的灰度表示。
我认为Linux的compiz
窗口装饰器使用没有响应的应用程序来做到这一点。
答案 0 :(得分:1)
我认为没有办法直接这样做 - 我认为所有表格都是用sRGB渲染的。 一种hacky方式可能是将表单的副本覆盖为表单(这与Control.DrawToBitMap很简单),然后通过简单的GDI矩阵将其传递给去饱和http://www.bobpowell.net/grayscale.htm。
答案 1 :(得分:1)
正如已经说过的那样,这样做的方法是在现有表单的顶部覆盖另一个控件/表单,并让它在顶部呈现灰度版本,你可以使用一个正好位于其上的附加表单来执行此操作原始表单,或使用位于所有其他控件之上的Panel
之类的内容。
这是一个工作示例,说明如何将另一个表单准确地放在第一个表单的客户区域上。如何使用
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;
}
}
请注意:
Paint
的实现相当差 - 实际上它应该使用双缓冲,以便将灰度图像预渲染到缓冲的图形上下文,因此Paint方法只需要绘制预先绘制的缓冲区内容。请参阅Custom Drawing Controls in C# – Manual Double Buffering ConvertToGrayscale
有点慢,但可能会加速如果我找到时间,我会尝试解决其中的一些问题,但上面至少会给你一般的想法。
请注意,在WPF中,这将更容易。
来源:
答案 2 :(得分:0)
尝试这样的方法,这对大多数简单的控件都有效(你需要递归到容器中才能正确切换所有控件)。
private void button1_Click(object sender, EventArgs e)
{
using (var dialog = new Form())
{
Dictionary<Control, Tuple<Color, Color>> oldcolors = new Dictionary<Control, Tuple<Color, Color>>();
foreach (Control ctl in this.Controls)
{
oldcolors.Add(ctl, Tuple.Create(ctl.BackColor, ctl.ForeColor));
// get rough avg intensity of color
int bg = (ctl.BackColor.R + ctl.BackColor.G + ctl.BackColor.B) / 3;
int fg = (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 (Control ctl in this.Controls)
{
ctl.BackColor = oldcolors[ctl].Item1;
ctl.ForeColor = oldcolors[ctl].Item2;
}
}
}