如何在无边框的窗体上创建玻璃模糊效果? [英] How do I create a blurred-glass effect on a border-less Form?

查看:103
本文介绍了如何在无边框的窗体上创建玻璃模糊效果?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在无边框的窗体上绘制平滑的模糊玻璃效果?我已尝试在



我目前有只有一台Windows 8机器(默认情况下,它们在其中取消了这种模糊和透明),所以我没有测试环境来检查这一点。我将在本周晚些时候讨论一个示例代码,



一旦您使用了桌面窗口管理器,如果您只是想模糊顶部(如您的图像中一样),请使用DwmExtendFrameIntoClientArea将框架(默认情况下为航空模糊)扩展到窗口中。对于自定义区域,请使用DwmEnableBlurBehindWindow



因此,如果这确实是您想要的(针对Windows 7 / vista的解决方案,其使用方式与现有MS程序相同) ,请告诉我,稍后再更新代码。否则,如果您正在寻找一个通用的解决方案(而不仅仅是Windows Vista / 7),请告诉我省去编写此代码的麻烦...






编辑::鉴于您选择手动制作效果,这里有一些基本的代码可以帮助您入门

  //代码从以下位置钻出:
// http://stackoverflow.com/questions/19867402/how-can-i-use-enumwindows-to-find -windows-with-a-specific-caption-title
// http://www.dotnetframework.org/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/ fx / src / CommonUI / System / Drawing / NativeMethods @ cs / 1305376 / NativeMethods @ cs
// http://stackoverflow.com/questions/7292757/how-to-get-screenshot-of-a-window -as-bitmap-object-in-c
// http://stackoverflow.com/questions/798295/how-can-i-use-getnextwindow-in-c * /

公共静态类WinAPI
{
公共委托bool EnumWindowsProc(IntPtr hWnd,IntPtr lParam);

[StructLayout(LayoutKind.Sequential)]
公共结构RECT
{
public int;
public int top;
公有int权利;
public int bottom;
};

公共枚举GW
{
GW_HWNDFIRST = 0,
GW_HWNDLAST = 1,
GW_HWNDNEXT = 2,
GW_HWNDPREV = 3,
GW_OWNER = 4,
GW_CHILD = 5,
GW_ENABLEDPOPUP = 6
}

[DllImport( User32.dll)]
公共静态extern bool EnumWindows(EnumWindowsProc lpEnumFunc,IntPtr lParam);

[DllImport( User32.dll,CharSet = CharSet.Unicode)]
public static extern int GetWindowText(IntPtr hWnd,StringBuilder strText,int maxCount);

[DllImport( User32.dll)]
public static extern int GetWindowTextLength(IntPtr hWnd);

[DllImport( User32.dll)]
公共静态外部布尔值IsWindowVisible(IntPtr hWnd);

[DllImport( User32.dll)]
公共静态外部布尔IsIconic(IntPtr hWnd);

[DllImport( User32.dll)]
公共静态外部布尔GetClientRect(IntPtr hWnd,参考RECT lpRect);

[DllImport( User32.dll)]
公共静态外部布尔GetWindowRect(IntPtr hWnd,参考RECT lpRect);

[DllImport( User32.dll)]
公共静态外部IntPtr GetDesktopWindow();

[DllImport( User32.dll)]
公共静态外部IntPtr GetTopWindow(IntPtr hWnd);

public static IntPtr GetNextWindow(IntPtr hWnd,GW wCmd)
{
return GetWindow(hWnd,wCmd);
}

public static IntPtr GetWindow(IntPtr hWnd,GW wCmd)
{
return GetWindow(hWnd,(uint)wCmd);
}

[DllImport( User32.dll)]
私有静态外部IntPtr GetWindow(IntPtr hWnd,uint wCmd);

[DllImport( User32.dll)]
public static extern bool PrintWindow(IntPtr hWnd,IntPtr hdcBlt,uint nFlags);

[DllImport( User32.dll)]
公共静态外部IntPtr GetDC(IntPtr hWnd);

[DllImport( Gdi32.dll)]
公共静态外部布尔DeleteDC(IntPtr hdc);

[DllImport( User32.dll)]
公共静态外部IntPtr GetWindowDC(IntPtr hWnd);

[DllImport( User32.dll)]
public static extern int ReleaseDC(IntPtr hWnd,IntPtr hdc);

[DllImport( User32.dll)]
public static extern int GetWindowRgn(IntPtr hWnd,IntPtr hRgn);

[DllImport( Gdi32.dll)]
公共静态外部IntPtr CreateCompatibleDC(IntPtr hWnd);

[DllImport( Gdi32.dll)]
公共静态外部IntPtr CreateCompatibleBitmap(IntPtr hdc,int宽度,int高度);

[DllImport( Gdi32.dll)]
公共静态外部IntPtr CreateBitmap(int width,int height,uint cPlanes,uint cBitsPerPel,IntPtr lpvBits);

[DllImport( Gdi32.dll)]
公共静态外部布尔DeleteObject(IntPtr hGdiObj);

[DllImport( Gdi32.dll)]
公共静态外部布尔SelectObject(IntPtr hdc,IntPtr hGdiObj);

[DllImport( Gdi32.dll)]
公共静态外部IntPtr CreateRectRgn(int nLeftRect,int nTopRect,int nRightRect,int nBottomRect);

公共静态StringBuilder GetWindowText(IntPtr hWnd)
{
int length = GetWindowTextLength(hWnd);
//添加另一个位置以允许空终止符
StringBuilder text = new StringBuilder(length + 1);
GetWindowText(hWnd,text,length + 1);
返回文字;
}

public static bool IsWindowReallyVisible(IntPtr hWnd)
{
if(!IsWindowVisible(hWnd)|| IsIconic(hWnd))
返回false ;
RECT区域=新的RECT();
if(!GetWindowRect(hWnd,ref area))
返回true;
if(area.left == area.right || area.bottom == area.top)
返回false;
返回true;
}

public enum RegionFlags
{
ERROR = 0,
NULLREGION = 1,
SIMPLEREGION = 2,
COMPLEXREGION = 3,
}

}

公共类ScreenShot
{
public static List< IntPtr> GetAllWindows(Func< IntPtr,bool>过滤器,Func< IntPtr,bool>停止)
{
List< IntPtr>结果= new List< IntPtr>();

WinAPI.EnumWindows((wnd,param)=>;
{
bool相关=过滤器(wnd);
如果(相关)
结果.Add(wnd);
bool shouldStop = stop(wnd);
if(shouldStop)
Console.WriteLine( Stop);
return!shouldStop;
},IntPtr.Zero);

返回结果;
}

公共静态IEnumerable< IntPtr> GetWindowsByOrder(Func< IntPtr,bool>过滤器)
{
List< IntPtr>跳过= new List< IntPtr>();
List< IntPtr>结果= new List< IntPtr>();
IntPtr桌面= WinAPI.GetDesktopWindow();

for(IntPtr wnd = WinAPI.GetTopWindow(IntPtr.Zero); wnd!= IntPtr.Zero; wnd = WinAPI.GetNextWindow(wnd,WinAPI.GW.GW_HWNDNEXT))
{
if(result.Contains(wnd)|| skip.Contains(wnd))
中断;
else if(filter(wnd))
result.Add(wnd);
else
skip.Add(wnd);
}

结果。添加(桌面);
的返回结果;
}

公共静态图像GetScreenshot(IntPtr hWnd)
{
IntPtr hdcScreen = WinAPI.GetDC(hWnd);
IntPtr hdc = WinAPI.CreateCompatibleDC(hdcScreen);
WinAPI.RECT区域=新的WinAPI.RECT();

WinAPI.GetWindowRect(hWnd,参考区域);

IntPtr hBitmap = WinAPI.CreateCompatibleBitmap(hdcScreen,area.right-area.left,area.bottom-area.top);
WinAPI.SelectObject(hdc,hBitmap);

WinAPI.PrintWindow(hWnd,hdc,0);

Image resultOpaque = Image.FromHbitmap(hBitmap);

WinAPI.DeleteObject(hBitmap);
WinAPI.DeleteDC(hdc);

IntPtr hRegion = WinAPI.CreateRectRgn(0,0,0,0);
WinAPI.RegionFlags f =(WinAPI.RegionFlags)WinAPI.GetWindowRgn(hWnd,hRegion);
Region region = Region.FromHrgn(hRegion);
WinAPI.DeleteObject(hRegion);

位图结果=新位图(resultOpaque.Width,resultOpaque.Height,System.Drawing.Imaging.PixelFormat.Format32bppArgb);
Graphics g = Graphics.FromImage(result);
g.Clear(Color.Transparent);
if(f!= WinAPI.RegionFlags.ERROR)
g.SetClip(region,System.Drawing.Drawing2D.CombineMode.Replace);
if(f!= WinAPI.RegionFlags.NULLREGION)
g.DrawImageUnscaled(resultOpaque,0,0);

g.Dispose();
region.Dispose();
resultOpaque.Dispose();

返回结果;
}

/ *现在获取获取Windows屏幕快照的实际代码* /
var windows = ScreenShot.GetWindowsByOrder(this.WindowFilter).Intersect(ScreenShot.GetAllWindows( this.WindowFilter,(wnd)=> false))。ToList();

int索引= windows.IndexOf((IntPtr)this.Handle); / *删除窗口后面的所有窗口* /
if(index!= -1)
windows.RemoveRange(index,windows.Count-index + 1);

windows.Reverse();

/ *获取所有窗口的图像* /
为(int i = 0; i< windows.Count; ++ i)
{
var window = windows [i];
using(var img = ScreenShot.GetScreenshot(window))
{
//获取窗口的实际位置
//绘制覆盖在其他窗口上的图像9累积图像)
}
}

在哪里仍然有错误(在我的Windows 8.1中的测试套件)?




  • 我仍然在透明度方面遇到麻烦-在其剪切区域内半透明的窗口仍然会出现涂成黑色

  • 我还有一些未知的黑色窗口(可能是透明的)仍然出现

  • 任务栏无法正确绘制


How do I draw a smooth blurred-glass effect on a border-less Form? I have tried the code listed on Image Processing for Dummies with C and GDI+ page but I'm sure it's not what I should be using. No amount of playing around with it has yielded any kind of result that is what I'm after.

This is basically what I'm trying to achieve:

解决方案

I'll assume you are talking about Windows 7 / Vista, and you'd like to achieve the blurry transparent areas that some MS programs have in the same way. For the general case, you do need some image processing which I'm not going to cover.

For the case I mentioned above, you are not supposed to do this yourself - this is sort of re-inventing the wheel. Basically, you can use the window manager to achieve this effect (which is called aero glass) by using the methods described by this article: http://msdn.microsoft.com/en-us/magazine/cc163435.aspx

I currently have only a windows 8 machine (in which they cancelled this blurring and transparency by default) so I don't have a test environment to check this. I'll get to one later this week and set-up a sample code to do this,

Once you are using the desktop window manager, if you want just to blur the top part (like in your image), use DwmExtendFrameIntoClientArea to extend the frame (which is aero blurred by default) into your window. For a custom area, use DwmEnableBlurBehindWindow

So, in case this is really what you are looking for (solution for windows 7 / vista in the same way existing MS programs work), tell me and I'll update with code later. Otherwise, if you are looking for a general solution (not just windows vista / 7), tell me to save me the effort of coding this...


EDIT: Given the fact that you chose to manually make the effect, here is some basic code to get you started

// Code was burrowed from:
//   http://stackoverflow.com/questions/19867402/how-can-i-use-enumwindows-to-find-windows-with-a-specific-caption-title
//   http://www.dotnetframework.org/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/fx/src/CommonUI/System/Drawing/NativeMethods@cs/1305376/NativeMethods@cs
//   http://stackoverflow.com/questions/7292757/how-to-get-screenshot-of-a-window-as-bitmap-object-in-c
//   http://stackoverflow.com/questions/798295/how-can-i-use-getnextwindow-in-c */

public static class WinAPI
{
   public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);

    [StructLayout(LayoutKind.Sequential)]
    public struct RECT
    {
        public int left;
        public int top;
        public int right;
        public int bottom;
    };

    public enum GW
    {
        GW_HWNDFIRST = 0,
        GW_HWNDLAST = 1,
        GW_HWNDNEXT = 2,
        GW_HWNDPREV = 3,
        GW_OWNER = 4,
        GW_CHILD = 5,
        GW_ENABLEDPOPUP = 6
    }

    [DllImport("User32.dll")]
    public static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);

    [DllImport("User32.dll", CharSet = CharSet.Unicode)]
    public static extern int GetWindowText(IntPtr hWnd, StringBuilder strText, int maxCount);

    [DllImport("User32.dll")]
    public static extern int GetWindowTextLength(IntPtr hWnd);

    [DllImport("User32.dll")]
    public static extern bool IsWindowVisible(IntPtr hWnd);

    [DllImport("User32.dll")]
    public static extern bool IsIconic(IntPtr hWnd);

    [DllImport("User32.dll")]
    public static extern bool GetClientRect(IntPtr hWnd, ref RECT lpRect);

    [DllImport("User32.dll")]
    public static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);

    [DllImport("User32.dll")]
    public static extern IntPtr GetDesktopWindow();

    [DllImport("User32.dll")]
    public static extern IntPtr GetTopWindow(IntPtr hWnd);

    public static IntPtr GetNextWindow(IntPtr hWnd, GW wCmd)
    {
        return GetWindow(hWnd, wCmd);
    }

    public static IntPtr GetWindow(IntPtr hWnd, GW wCmd)
    {
        return GetWindow(hWnd, (uint)wCmd);
    }

    [DllImport("User32.dll")]
    private static extern IntPtr GetWindow(IntPtr hWnd, uint wCmd);

    [DllImport("User32.dll")]
    public static extern bool PrintWindow(IntPtr hWnd, IntPtr hdcBlt, uint nFlags);

    [DllImport("User32.dll")]
    public static extern IntPtr GetDC(IntPtr hWnd);

    [DllImport("Gdi32.dll")]
    public static extern bool DeleteDC(IntPtr hdc);

    [DllImport("User32.dll")]
    public static extern IntPtr GetWindowDC(IntPtr hWnd);

    [DllImport("User32.dll")]
    public static extern int ReleaseDC(IntPtr hWnd, IntPtr hdc);

    [DllImport("User32.dll")]
    public static extern int GetWindowRgn(IntPtr hWnd, IntPtr hRgn);

    [DllImport("Gdi32.dll")]
    public static extern IntPtr CreateCompatibleDC(IntPtr hWnd);

    [DllImport("Gdi32.dll")]
    public static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int width, int height);

    [DllImport("Gdi32.dll")]
    public static extern IntPtr CreateBitmap(int width, int height, uint cPlanes, uint cBitsPerPel, IntPtr lpvBits);

    [DllImport("Gdi32.dll")]
    public static extern bool DeleteObject(IntPtr hGdiObj);

    [DllImport("Gdi32.dll")]
    public static extern bool SelectObject(IntPtr hdc, IntPtr hGdiObj);

    [DllImport("Gdi32.dll")]
    public static extern IntPtr CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect);

    public static StringBuilder GetWindowText(IntPtr hWnd)
    {
        int length = GetWindowTextLength(hWnd);
        // Add another place to allow null terminator
        StringBuilder text = new StringBuilder(length + 1);
        GetWindowText(hWnd, text, length + 1);
        return text;    
    }

    public static bool IsWindowReallyVisible(IntPtr hWnd)
    {
        if (!IsWindowVisible(hWnd) || IsIconic(hWnd))
            return false;
        RECT area = new RECT();
        if (!GetWindowRect(hWnd, ref area))
            return true;
        if (area.left == area.right || area.bottom == area.top)
            return false;
        return true;
    }

    public enum RegionFlags
    {
        ERROR = 0,
        NULLREGION = 1,
        SIMPLEREGION = 2,
        COMPLEXREGION = 3,
    } 

}

public class ScreenShot
{
    public static List<IntPtr> GetAllWindows(Func<IntPtr, bool> filter, Func<IntPtr, bool> stop)
    {
        List<IntPtr> result = new List<IntPtr>();

        WinAPI.EnumWindows((wnd, param) =>
        {
            bool relevant = filter(wnd);
            if (relevant)
                result.Add(wnd);
            bool shouldStop = stop(wnd);
            if (shouldStop)
                Console.WriteLine("Stop");
            return !shouldStop;
        }, IntPtr.Zero);

        return result;
    }

    public static IEnumerable<IntPtr> GetWindowsByOrder(Func<IntPtr, bool> filter)
    {
        List<IntPtr> skip = new List<IntPtr>();
        List<IntPtr> result = new List<IntPtr>();
        IntPtr desktop = WinAPI.GetDesktopWindow();

        for (IntPtr wnd = WinAPI.GetTopWindow(IntPtr.Zero); wnd != IntPtr.Zero; wnd = WinAPI.GetNextWindow(wnd, WinAPI.GW.GW_HWNDNEXT))
        {
            if (result.Contains(wnd) || skip.Contains(wnd))
                break;
            else if (filter(wnd))
                result.Add(wnd);
            else
                skip.Add(wnd);
        }

        result.Add(desktop);
        return result;
    }

    public static Image GetScreenshot(IntPtr hWnd)
    {
        IntPtr hdcScreen = WinAPI.GetDC(hWnd);
        IntPtr hdc = WinAPI.CreateCompatibleDC(hdcScreen);
        WinAPI.RECT area = new WinAPI.RECT();

        WinAPI.GetWindowRect(hWnd, ref area);

        IntPtr hBitmap = WinAPI.CreateCompatibleBitmap(hdcScreen, area.right - area.left, area.bottom - area.top);
        WinAPI.SelectObject(hdc, hBitmap);

        WinAPI.PrintWindow(hWnd, hdc, 0);

        Image resultOpaque = Image.FromHbitmap(hBitmap);

        WinAPI.DeleteObject(hBitmap);
        WinAPI.DeleteDC(hdc);

        IntPtr hRegion = WinAPI.CreateRectRgn(0, 0, 0, 0);
        WinAPI.RegionFlags f = (WinAPI.RegionFlags) WinAPI.GetWindowRgn(hWnd, hRegion);
        Region region = Region.FromHrgn(hRegion);
        WinAPI.DeleteObject(hRegion);

        Bitmap result = new Bitmap(resultOpaque.Width, resultOpaque.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
        Graphics g = Graphics.FromImage(result);
        g.Clear(Color.Transparent);
        if (f != WinAPI.RegionFlags.ERROR)
            g.SetClip(region, System.Drawing.Drawing2D.CombineMode.Replace);
        if (f != WinAPI.RegionFlags.NULLREGION)
            g.DrawImageUnscaled(resultOpaque, 0, 0);

        g.Dispose();
        region.Dispose();
        resultOpaque.Dispose();

        return result;
    }

/* And now for the actual code of getting screenshots of windows */
var windows = ScreenShot.GetWindowsByOrder(this.WindowFilter).Intersect(ScreenShot.GetAllWindows(this.WindowFilter, (wnd) => false)).ToList();

int index = windows.IndexOf((IntPtr)this.Handle); /* Remove all the windows behind your windows */
if (index != -1)
    windows.RemoveRange(index, windows.Count - index + 1);

windows.Reverse();

/* Get the images of all the windows */
for (int i = 0; i < windows.Count; ++i )
{
    var window = windows[i];
    using (var img = ScreenShot.GetScreenshot(window))
    {
        // Get the actual position of the window
        // Draw it's image overlayed on the other windows 9have an accumulating image)
    }
}

Where does this still have bugs (on my testsuite in Windows 8.1)?

  • I'm still having troubles with transparency - windows which are semi-transparent inside their clipping region still get painted black
  • I have some unknown black windows (probably transparent) that still appear
  • The taskbar doesn't paint correctly

这篇关于如何在无边框的窗体上创建玻璃模糊效果?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆