2012-06-14 113 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; 
      } 
     } 
    }