WINAPI/DWMAPI具有不规则形状的模糊窗口 [英] WINAPI/DWMAPI Blur-behind window with irregular shape

查看:131
本文介绍了WINAPI/DWMAPI具有不规则形状的模糊窗口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意:这不是关于无边框窗口的问题.

因此,前几天在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屋!

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