2012-06-14 153 views
3

是否可以在灰度中绘制任何表格(无需重写Paint方法)。以灰度显示表格

如果我表现出一个模式()对话形式,我wan't做显示其为灰度父。 我在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窗口装饰器对没有反应的应用程序做了这个。

+1

一个快速和肮脏的把戏,我使用,使灰色显示的形式是一个额外的控件添加到窗体。该控件将对其父图像('Form.DrawToBitmap()')进行处理,对其进行处理,将其用作背景并将最大化以填充完整的表单。 – Bobby

+0

灰度,而不是灰度 – Indy9000

+0

@Indeera无论是正确的。 http://en.wikipedia.org/wiki/Grayscale – Keplah

回答

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这将是一个容易得多。

来源:

+0

需要一些改进,但乍一看看起来不错。 –

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; 
      } 
     } 
    }