正如已经说过的那样,这样做的方法是在现有表单的顶部覆盖另一个控件/表单,并让它在顶部呈现这个的灰度版本,您可以使用恰好放置在原始表单上的附加表单来执行此操作, 或使用类似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 方法只需要绘制预绘制的缓冲区内容。请参阅C# 中的自定义绘图控件 - 手动双缓冲
ConvertToGrayscale
有点慢,但可能会加快
- 如果有人出于任何原因设法移动原始表格,事情就会出错
- 图像是静态的,如果基础控件被重绘,那么理想情况下顶部表单也应该重绘。我不确定如何最好地检测另一个表单的一部分何时失效。
如果我有时间我会尝试解决其中的一些问题,但以上至少给了你一个大致的想法。
请注意,在 WPF 中,这会容易得多。
资料来源: