如何在无边框表格上创建模糊玻璃效果?

如何在无边框表格上绘制平滑的模糊玻璃效果? 我已尝试使用C和GDI +页面在Image Processing for Dummies上列出的代码,但我确定这不是我应该使用的。 没有多少玩弄它已经产生了我所追求的任何结果。

这基本上就是我想要实现的目标:

在此处输入图像描述

我假设您正在谈论Windows 7 / Vista,并且您希望以相同的方式实现某些MS程序所具有的模糊透明区域。 对于一般情况,您需要一些我不会涵盖的图像处理。

对于我上面提到的情况,你不应该自己这样做 – 这有点重新发明轮子。 基本上,您可以使用窗口管理器通过使用本文所述的方法来实现此效果(称为空气玻璃): http : //msdn.microsoft.com/en-us/magazine/cc163435.aspx

我目前只有一台Windows 8机器(默认情况下它们取消了这种模糊和透明度)所以我没有测试环境来检查这一点。 我将在本周晚些时候找到一个并设置一个示例代码来执行此操作,

使用桌面窗口管理器后,如果只想模糊顶部(如图像中),请使用DwmExtendFrameIntoClientArea将框架(默认为空气模糊)扩展到窗口中。 对于自定义区域,请使用DwmEnableBlurBehindWindow

所以,如果这真的是你正在寻找的(Windows 7 / vista的解决方案与现有MS程序的工作方式相同),请告诉我,稍后我会用代码更新。 否则,如果您正在寻找一般解决方案(不仅仅是windows vista / 7),请告诉我省去编写此代码的工作……


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

// 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 GetAllWindows(Func filter, Func stop) { List result = new List(); 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 GetWindowsByOrder(Func filter) { List skip = new List(); List result = new List(); 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) } } 

这还有什么错误(在我的Windows 8.1中的测试套件上)?

  • 我仍然遇到透明问题 - 在剪裁区域内半透明的窗户仍然涂成黑色
  • 我还有一些未知的黑色窗户(可能是透明的)
  • 任务栏无法正确绘制

Winform的

像DwmEnableBlurBehindWindow一样使用Win API

  [DllImport("gdi32")] private static extern IntPtr CreateEllipticRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect); [DllImport("dwmapi")] private static extern int DwmEnableBlurBehindWindow(IntPtr hWnd, ref DwmBlurbehind pBlurBehind); public struct DwmBlurbehind { public int DwFlags; public bool FEnable; public IntPtr HRgnBlur; public bool FTransitionOnMaximized; } public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { var hr = CreateEllipticRgn(0, 0, Width, Height); var dbb = new DwmBlurbehind {FEnable = true, DwFlags = 1, HRgnBlur = hr, FTransitionOnMaximized = false}; DwmEnableBlurBehindWindow(Handle, ref dbb); } protected override void OnPaint(PaintEventArgs e) { e.Graphics.FillRectangle(new SolidBrush(Color.Black), new Rectangle(0, 0, Width, Height)); } 

例1:

在此处输入图像描述

示例2:您可以更改画笔颜色(例如:DarkRed)以获得更好的效果

在此处输入图像描述

这里要注意的是,你可以选择一个适用的区域,你可以有超过1的区域。

WPF

您可以使用相同的方法 。

Wpf对着色器有更好的支持,你可以添加模糊效果,但你的性能更重。 您的图像也很可能来自WPF和Blend创建的程序。

如果我没记错的话就不能在纯色画笔上使用像模糊一样的着色器。 因此,以下不会产生同样的效果。 设置背景50%透视( 窗口属性allowsTransparency =“True”WindowStyle =“None”

    

原生玻璃窗

这里描述了Wpf支持: http : //www.paulrohde.com/native-glass-with-wpf/

我得到了以下结果略有不同的方法: 在此处输入图像描述