WINAPI/DWMAPI具有不规则形状的模糊窗口 [英] WINAPI/DWMAPI Blur-behind window with irregular shape
问题描述
注意:这不是关于无边框窗口的问题.
因此,前几天在Windows 7上浏览开始"菜单时,我偶然发现了该程序:
So, I stumbled upon this program while I was exploring my Start menu the other day on Windows 7:
这是一个本地Windows程序,称为数学输入面板".现在,我对窗口形状感到好奇.我知道它不是完全由DWM绘制的,因为边框和关闭"按钮看起来像是腥的,并且窗口没有阴影(我启用了阴影).关于如何进行此操作的第一个猜测是使用DwmEnableBlurBehindWindow
,但是我无法想象它可以用于不规则的窗口形状,对吗? (或者还有另一种方法可以做到,或者完全是微软的巫术?)
It's a native Windows program, called "Math Input Panel." Now, I'm curious about the window shape. I know that it's not completely drawn by DWM, because the borders and Close button look fishy and the window has no drop shadow (I have drop shadows enabled). My first guess as to how this was made would be using DwmEnableBlurBehindWindow
, but I can't imagine that works on irregular window shapes, does it? (Or is there another way to do this, or is it just completely Microsoft sorcery?)
推荐答案
因此,我不知道,hRgn
可以采用不规则形状(而DwmEnableBlurBehindWindow
可以采用hRgn
,但我知道).因此,这是我的解决方案(或多或少)与WPF兼容:
So, unbeknownst to me, hRgn
can take an irregular shape (and DwmEnableBlurBehindWindow
takes an hRgn
, but I knew that). So, here's my solution that's (more or less) compatible with WPF:
...和源代码:
MainWindow.xaml:
MainWindow.xaml:
<Window x:Class="IrregularGlassWindow.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Height="500"
Width="500"
Background="#01FFFFFF"
AllowsTransparency="True"
WindowStyle="None"
ResizeMode="NoResize">
<Window.Clip>
<PathGeometry>
<PathFigure StartPoint="250,0">
<ArcSegment Point="250,500"
RotationAngle="180"
Size="250,250"
SweepDirection="Clockwise" />
<ArcSegment Point="250,0"
RotationAngle="180"
Size="250,250"
SweepDirection="Clockwise" />
</PathFigure>
</PathGeometry>
</Window.Clip>
<Grid>
<Ellipse Margin="1"
Width="498"
Height="498"
Stroke="#8FFF"
StrokeThickness="1.25" />
<Ellipse Width="500"
Height="500"
Stroke="#C000"
StrokeThickness="1"/>
</Grid>
</Window>
MainWindow.xaml.cs:
MainWindow.xaml.cs:
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
this.SourceInitialized += MainWindow_SourceInitialized;
this.KeyDown += MainWindow_KeyDown;
}
void MainWindow_KeyDown(object sender, KeyEventArgs e) {
if (e.Key == Key.Escape) this.Close();
}
void MainWindow_SourceInitialized(object sender, EventArgs e) {
var helper = new WindowInteropHelper(this);
var hwnd = helper.Handle;
var src = HwndSource.FromHwnd(hwnd);
src.CompositionTarget.BackgroundColor = Colors.Transparent;
WindowChrome.SetWindowChrome(this, new WindowChrome {
CaptionHeight = 500,
CornerRadius = new CornerRadius(0),
GlassFrameThickness = new Thickness(0),
NonClientFrameEdges = NonClientFrameEdges.None,
ResizeBorderThickness = new Thickness(0),
UseAeroCaptionButtons = false
});
GraphicsPath path = new GraphicsPath(FillMode.Alternate);
path.StartFigure();
path.AddArc(new RectangleF(0, 0, 500, 500), 0, 360);
path.CloseFigure();
var dbb = new DwmBlurBehind(true);
dbb.SetRegion(Graphics.FromHwnd(hwnd), new Region(path));
DwmApi.DwmEnableBlurBehindWindow(hwnd, ref dbb);
}
}
我认为有人击败了我,但这是我的解决方案的工作原理:
I think somebody else beat me to it, but here's how my solution works:
当触发窗口的SourceInitialized
事件时,这意味着我们拥有窗口的句柄.因此,在此函数的处理程序中,我得到了窗口句柄.然后,调用从dwmapi.dll导入的名为DwmEnableBlurBehindWindow
的函数.基本上,这会将窗口的透明区域变成特定区域的玻璃.我从pinvoke.net获得的DwmBlurBehind
结构,它将GDI + System.Drawing.Region
转换为hRgn
. hRgn
传递到DwmEnableBlurBehindWindow
,并将透明部分剪切到Region
.在这种情况下,我使用了一个圆圈.那么XAML只是重音边界.值得注意的是,由于某些原因,当AllowsTransparency
为true时,将Window.Background
设置为Transparent
不会启用命中测试.不知道为什么,但是它可能与背后的代码有关.
When the window's SourceInitialized
event is fired, that means that we have a handle for our window. So in the handler of this function, I get the window handle. Then I make a call to a function I imported from dwmapi.dll called DwmEnableBlurBehindWindow
. This basically turns transparent areas of the window into glass for a certain region. The DwmBlurBehind
struct I got from pinvoke.net, and it converts a GDI+ System.Drawing.Region
into an hRgn
. The hRgn
is passed to DwmEnableBlurBehindWindow
, and it clips the transparent parts to the Region
. In this case, I used a circle. Then the XAML is just the accent borders. It's worth noting that, for some reason, setting Window.Background
to Transparent
doesn't enable hit-testing when AllowsTransparency
is true here. No idea why, but it probably has something to do with the code-behind.
这篇关于WINAPI/DWMAPI具有不规则形状的模糊窗口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!