WinForms中的图层效果(模糊等)

时间:2010-08-30 08:02:04

标签: .net winforms

在WinForms中,我正在寻找一种方法来实现类似于Java Swing中JXLayer类的功能。 更具体。我想模糊一个窗口的整个内容,并在其上绘制一些东西(例如,一个等待的圆圈)。 任何想法将受到高度赞赏:)

5 个答案:

答案 0 :(得分:9)

这是我的解决方案。

  1. 截屏。
  2. 模糊它。
  3. 将模糊的图片放在一切的前面。
  4. 给定一个带有Button button1和Panel panel1的表单(上面有列表框和进度条),以下代码运行良好:

    using System;
    using System.ComponentModel;
    using System.Drawing;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    using System.Drawing.Imaging;
    
    namespace Blur
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                Bitmap bmp = Screenshot.TakeSnapshot(panel1);
                BitmapFilter.GaussianBlur(bmp, 4);
    
                PictureBox pb = new PictureBox();
                panel1.Controls.Add(pb);
                pb.Image = bmp;
                pb.Dock = DockStyle.Fill;
                pb.BringToFront();            
            }
        }
    
        public class ConvMatrix
        {
            public int TopLeft = 0, TopMid = 0, TopRight = 0;
            public int MidLeft = 0, Pixel = 1, MidRight = 0;
            public int BottomLeft = 0, BottomMid = 0, BottomRight = 0;
            public int Factor = 1;
            public int Offset = 0;
            public void SetAll(int nVal)
            {
                TopLeft = TopMid = TopRight = MidLeft = Pixel = MidRight = BottomLeft = BottomMid = BottomRight = nVal;
            }
        }
    
        public class BitmapFilter
        {
            private static bool Conv3x3(Bitmap b, ConvMatrix m)
            {
                // Avoid divide by zero errors
                if (0 == m.Factor) return false;
    
                Bitmap bSrc = (Bitmap)b.Clone();
    
                // GDI+ still lies to us - the return format is BGR, NOT RGB.
                BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                BitmapData bmSrc = bSrc.LockBits(new Rectangle(0, 0, bSrc.Width, bSrc.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
    
                int stride = bmData.Stride;
                int stride2 = stride * 2;
                System.IntPtr Scan0 = bmData.Scan0;
                System.IntPtr SrcScan0 = bmSrc.Scan0;
    
                unsafe
                {
                    byte* p = (byte*)(void*)Scan0;
                    byte* pSrc = (byte*)(void*)SrcScan0;
    
                    int nOffset = stride + 6 - b.Width * 3;
                    int nWidth = b.Width - 2;
                    int nHeight = b.Height - 2;
    
                    int nPixel;
    
                    for (int y = 0; y < nHeight; ++y)
                    {
                        for (int x = 0; x < nWidth; ++x)
                        {
                            nPixel = ((((pSrc[2] * m.TopLeft) + (pSrc[5] * m.TopMid) + (pSrc[8] * m.TopRight) +
                                (pSrc[2 + stride] * m.MidLeft) + (pSrc[5 + stride] * m.Pixel) + (pSrc[8 + stride] * m.MidRight) +
                                (pSrc[2 + stride2] * m.BottomLeft) + (pSrc[5 + stride2] * m.BottomMid) + (pSrc[8 + stride2] * m.BottomRight)) / m.Factor) + m.Offset);
    
                            if (nPixel < 0) nPixel = 0;
                            if (nPixel > 255) nPixel = 255;
    
                            p[5 + stride] = (byte)nPixel;
    
                            nPixel = ((((pSrc[1] * m.TopLeft) + (pSrc[4] * m.TopMid) + (pSrc[7] * m.TopRight) +
                                (pSrc[1 + stride] * m.MidLeft) + (pSrc[4 + stride] * m.Pixel) + (pSrc[7 + stride] * m.MidRight) +
                                (pSrc[1 + stride2] * m.BottomLeft) + (pSrc[4 + stride2] * m.BottomMid) + (pSrc[7 + stride2] * m.BottomRight)) / m.Factor) + m.Offset);
    
                            if (nPixel < 0) nPixel = 0;
                            if (nPixel > 255) nPixel = 255;
    
                            p[4 + stride] = (byte)nPixel;
    
                            nPixel = ((((pSrc[0] * m.TopLeft) + (pSrc[3] * m.TopMid) + (pSrc[6] * m.TopRight) +
                                (pSrc[0 + stride] * m.MidLeft) + (pSrc[3 + stride] * m.Pixel) + (pSrc[6 + stride] * m.MidRight) +
                                (pSrc[0 + stride2] * m.BottomLeft) + (pSrc[3 + stride2] * m.BottomMid) + (pSrc[6 + stride2] * m.BottomRight)) / m.Factor) + m.Offset);
    
                            if (nPixel < 0) nPixel = 0;
                            if (nPixel > 255) nPixel = 255;
    
                            p[3 + stride] = (byte)nPixel;
    
                            p += 3;
                            pSrc += 3;
                        }
    
                        p += nOffset;
                        pSrc += nOffset;
                    }
                }
    
                b.UnlockBits(bmData);
                bSrc.UnlockBits(bmSrc);
    
                return true;
            }
    
            public static bool GaussianBlur(Bitmap b, int nWeight /* default to 4*/)
            {
                ConvMatrix m = new ConvMatrix();
                m.SetAll(1);
                m.Pixel = nWeight;
                m.TopMid = m.MidLeft = m.MidRight = m.BottomMid = 2;
                m.Factor = nWeight + 12;
    
                return BitmapFilter.Conv3x3(b, m);
            }
        }
    
        class Screenshot
        {
            public static Bitmap TakeSnapshot(Control ctl)
            {
                Bitmap bmp = new Bitmap(ctl.Size.Width, ctl.Size.Height);
                using (Graphics g = System.Drawing.Graphics.FromImage(bmp))
                {
                    g.CopyFromScreen(
                        ctl.PointToScreen(ctl.ClientRectangle.Location),
                        new Point(0, 0), ctl.ClientRectangle.Size
                    );
                }
                return bmp; 
            }            
        }
    }
    

    alt text alt text 高斯模糊的代码来自here

答案 1 :(得分:1)

这个VB.Net代码将

  1. 创建表单图片
  2. 添加模糊到图片
  3. 将图片添加到图片框
  4. 添加单击处理程序,在单击时删除图片。
  5. 将图片框添加到表单并设置为bringtofront
  6. 唯一的问题是模糊很慢。所以我会继续努力。

    Imports System.Drawing.Imaging
    Public Class Form1
    
    Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
        ShowBlurredPicture()
    End Sub
    
    Sub ShowBlurredPicture()
        Dim blurredpic As Bitmap = gausianBlur(False, New Size(5, 5), GetFormPic)
        Dim p As New PictureBox
        p.Image = blurredpic
    
        p.Location = New Point(-System.Windows.Forms.SystemInformation.FrameBorderSize.Width, -(System.Windows.Forms.SystemInformation.CaptionHeight + System.Windows.Forms.SystemInformation.FrameBorderSize.Height))
        p.Size = New Size(Me.Size)
        Me.Controls.Add(p)
        p.Visible = True
        p.BringToFront()
        AddHandler p.Click, AddressOf picclick
    End Sub
    Sub picclick(ByVal sender As Object, ByVal e As System.EventArgs)
        Me.Controls.Remove(sender)
    End Sub
    Function GetFormPic() As Bitmap
        Dim ScreenSize As Size = Me.Size
        Dim screenGrab As New Bitmap(Me.Width, Me.Height)
        Dim g As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(screenGrab)
        g.CopyFromScreen(Me.Location, New Point(0, 0), Me.Size)
        Return screenGrab
    End Function
    Private Function Average(ByVal Size As Size, ByVal imageSize As SizeF, ByVal PixelX As Integer, ByVal Pixely As Integer, ByVal theimage As Bitmap) As Color
        Dim pixels As New ArrayList
        Dim x As Integer, y As Integer
        Dim bmp As Bitmap = theimage.Clone
        For x = PixelX - CInt(Size.Width / 2) To PixelX + CInt(Size.Width / 2)
            For y = Pixely - CInt(Size.Height / 2) To Pixely + CInt(Size.Height / 2)
                If (x > 0 And x < imageSize.Width) And (y > 0 And y < imageSize.Height) Then
                    pixels.Add(bmp.GetPixel(x, y))
                End If
            Next
        Next
        Dim thisColor As Color
        Dim alpha As Integer = 0
        Dim red As Integer = 0
        Dim green As Integer = 0
        Dim blue As Integer = 0
    
        For Each thisColor In pixels
            alpha += thisColor.A
            red += thisColor.R
            green += thisColor.G
            blue += thisColor.B
        Next
    
        Return Color.FromArgb(alpha / pixels.Count, red / pixels.Count, green / pixels.Count, blue / pixels.Count)
    End Function
    
    
    Private Function gausianBlur(ByVal alphaEdgesOnly As Boolean, ByVal blurSize As Size, ByVal theimage As Bitmap) As Bitmap
        Dim PixelY As Integer
        Dim PixelX As Integer
        Dim bmp As Bitmap = theimage.Clone
    
        For PixelY = 0 To bmp.Width - 1
            For PixelX = 0 To bmp.Height - 1
                If Not alphaEdgesOnly Then     ' Blur everything
                    bmp.SetPixel(PixelX, PixelY, Average(blurSize, bmp.PhysicalDimension, PixelX, PixelY, theimage))
                ElseIf bmp.GetPixel(PixelX, PixelY).A <> 255 Then  ' Alpha blur channel check
                    bmp.SetPixel(PixelX, PixelY, Average(blurSize, bmp.PhysicalDimension, PixelX, PixelY, theimage))
                End If
    
                Application.DoEvents()
            Next
        Next
    
        Return bmp.Clone
        bmp.Dispose()
    End Function
    
    End Class
    

    alt text

    我在这里找到了执行GasuianBlur的代码:http://www.codeproject.com/KB/GDI-plus/GausianBlur.aspx

    此处将表单复制到位图的代码:http://www.daniweb.com/forums/thread94348.html

答案 2 :(得分:0)

   Imports System.Drawing
   Imports System.Drawing.Imaging
   Public Class Form1
    #Region "Declarations"
   Dim imagebitmap As Bitmap
   Dim graphicsvariable As Graphics
   Dim WithEvents v As New PictureBox
   Dim panel1 As Panel

  #End Region

  #Region "function for getting screenshot"
     Public Function getscreenshot()
      imagebitmap = New Bitmap(Me.Size.Width, Me.Size.Height) 'creates a new blank bitmap having size of the form'
       graphicsvariable = Graphics.FromImage(imagebitmap)      'creates a      picture template that enables the graphics variable to draw on'
                graphicsvariable.CopyFromScreen(Me.PointToScreen(Me.ClientRectangle.Location), New Point(0, 0), Me.ClientRectangle.Size)    'copies graphics that is on the screen to the imagebitmap'
        Return imagebitmap
       End Function
     #End Region

#Region "method for blurring"
Sub BlurBitmap(ByRef image As Bitmap, Optional ByVal BlurForce As Integer = 2)
    'We get a graphics object from the image'
      Dim g As Graphics = Graphics.FromImage(image)
    'declare an ImageAttributes to use it when drawing'
      Dim att As New ImageAttributes
    'declare a ColorMatrix'
      Dim m As New ColorMatrix
    ' set Matrix33 to 0.5, which represents the opacity. so the drawing will be semi-trasparent.'
      m.Matrix33 = 0.4
    'Setting this ColorMatrix to the ImageAttributes.'
      att.SetColorMatrix(m)
    'drawing the image on it self, but not in the same coordinates, in a way that every pixel will be drawn on the pixels arround it.'
      For x = -1 To BlurForce
          For y = -1 To BlurForce
            'Drawing image on it self using out ImageAttributes to draw it semi-transparent.'
              g.DrawImage(image, New Rectangle(x, y, image.Width, image.Height), 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, att)
          Next
      Next
    'disposing ImageAttributes and Graphics. the effect is then applied. '
      att.Dispose() 'dispose att'
      g.Dispose() 'dispose g'
    End Sub
  #End Region

 #Region "event that handles the removal of the blurred image when clicked"
    Private Sub v_Click(sender As Object, e As EventArgs) Handles v.Click
    Panel1.Controls.Remove(sender) 'removes the picturebox from the panel'
     Me.Controls.Remove(Panel1)    'removes the panel from the form'
  End Sub
#End Region


   Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
      panel1 = New Panel
      panel1.Size = New Size(763, 441)
      Me.Controls.Add(panel1)

     panel1.Controls.Add(v)  'add picturebox to panel1, pls also note that i made the panel cover the whole form'
     Dim b As Bitmap = getscreenshot() 'get the screen shot'
     BlurBitmap(b) 'blur the screen shot'
     v.Image = b 'set the picturebox image as b (the blurred image)'
     v.Dock = DockStyle.Fill
     v.BringToFront()
     v.Size = Me.Size
     panel1.BringToFront()
    End Sub
End Class

答案 3 :(得分:-1)

我做了一次,模态形式的位置和大小与模糊的形式完全相同。然后在该表格上将不透明度提高到50%。

概念证明(创建表单,并在表单上放置button1,粘贴此代码):

Public Class Form1
Private BlurrForm As New Form
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    BlurrForm.StartPosition = FormStartPosition.Manual
    BlurrForm.Opacity = 0.5
    BlurrForm.Location = Me.Location
    BlurrForm.Size = Me.Size
    BlurrForm.Owner = Me
    BlurrForm.FormBorderStyle = Windows.Forms.FormBorderStyle.None
    AddHandler BlurrForm.Click, AddressOf BlurredFormClicked
    BlurrForm.Show(Me)
End Sub
Sub BlurredFormClicked(ByVal sender As System.Object, ByVal e As EventArgs)
    BlurrForm.Hide()
End Sub

End Class

当您按下按钮1时,整个表格将显示为灰色,当按下鼠标按钮时它将消失。

答案 4 :(得分:-1)

我不确定模糊,但你可以做的一件事是在前面有一个半透明的控件。

如果你真的想要它在整个窗口(包括标题栏等)前面,这意味着一个半透明的形式直接放置并直接调整你的主要形式。它需要是模态的(ShowDialog()),否则用户可能会“丢失”一个表单而不是另一个...

如果您尝试在后面的窗口中同时执行任何操作(如您的问题所示),这会出现问题,因为ShowDialog会阻止调用代码......

在这种情况下,你可以将表单设置为'TopMost' - 这非常糟糕,因为它可以阻止用户在等待你的时候与alt-tabs相关的另一个应用程序进行交互,并且恰好在你的等待形式下。我不知道有一个更好的解决方案与香草winforms。你可以用低级别的东西做些什么,但我对此并不了解。