2015-01-05 2 views
3

NB : 이것은 Borderless Window에 관한 질문이 아닙니다. 나는 윈도우 7에 다른 일 내 시작 메뉴를 탐험하는 동안WINAPI/DWMAPI 불규칙한 모양의 흐리게 처리되는 창

그래서, 난이 프로그램을 우연히 :

Math input panel

그것은이다라는 기본 Windows 프로그램, "수학 입력 판." 이제 저는 창 모양에 대해 궁금합니다. DWM에 의해 완전히 그려지지는 않는다는 것을 알고 있습니다. 왜냐하면 테두리와 닫기 버튼이 물고기 모양으로 보이고 창에 그림자가 전혀 없기 때문입니다 (나는 그림자를 사용할 수 있습니다). 이것이 어떻게 만들어 졌는지에 대한 내 첫 번째 추측은 DwmEnableBlurBehindWindow을 사용하는 것이지만 불규칙한 창 모양에서 작동하는 것을 상상할 수는 없습니까? (아니면 다른 방법이 있을까요? 아니면 완전히 마이크로 소프트의 마법입니까?)

+0

달리 증명할 수없는 경우 wpf가 아닙니다. 하지만 (스눕을 사용하여) 시도했다면 답을 얻을 수 있습니다. – Will

+1

WPF가 아닌 것을 압니다. 아마 Winapi의 영역에 있지만 WPF와 함께 작동하는 솔루션을 선호합니다. 사실, 나는 hRgn이 대답일지도 모른다고 생각합니다 ... – rookie1024

+0

그것은 술입니다. wpf 솔루션이 없습니다. 또한 라이브러리 (예 : 특수한 창 크롬 라이브러리)를 요청하는 경우에도 문제가 발생합니다. 해킹 윈도우 크롬은 엉덩이에 왕실의 고통이 거의 없다. (내가 본 적이없는 크롬 해킹은 그저 빨지 않았다 ... 크롬). – Will

답변

2

그래서, 나에게 미지, hRgn은 불규칙한 형태를 취할 수 (및 DwmEnableBlurBehindWindow는 소요 hRgn, 그러나 나는 그것을 알았다).

My own custom-shaped glass window

... 그리고 소스 코드 :

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 그래서, 여기에 내 WPF와 (다소) 호환 솔루션입니다. 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); 
    } 
} 

나는 누군가 다른 사람이 나를 때렸다 고 생각하지만 여기는 호다. 내 솔루션 작동 :

창이 SourceInitialized 이벤트가 발생하면 우리는 우리 창에 대한 핸들을 가지고 있음을 의미합니다. 그래서이 함수의 핸들러에서 윈도우 핸들을 얻습니다. 그런 다음 DwmEnableBlurBehindWindow이라는 dwmapi.dll에서 가져온 함수를 호출합니다. 기본적으로 투명 영역을 특정 영역의 유리로 바꿉니다. DwmBlurBehind struct는 pinvoke.net에서 가져 왔으며 GDI + System.Drawing.RegionhRgn으로 변환합니다. hRgnDwmEnableBlurBehindWindow으로 전달되고 투명 부분은 Region으로 잘립니다. 이 경우 원을 사용했습니다. 그런 다음 XAML은 액센트 테두리에 불과합니다.웬일인지 을 Transparent으로 설정하면 AllowsTransparency이 참일 때 히트 테스트가 활성화되지 않습니다. 이유는 모르겠지만, 아마도 코드 숨김과 관련이있을 것입니다.

+1

winform에서 이것을 구현하는 방법은 무엇입니까? – IlPADlI

+0

@IlPADlI 글쎄요, WinForms의 배후에 대해 많이 알지 못합니다.이 솔루션은 특별한 WPF 도우미 ('WindowChrome')를 사용하여 WPF에만 적용될 수 있지만 가능한 해결책은 윈도우의'HWND'를 가져 왔고 P/Invoke를 사용하여 DWMAPI 메소드를 실행할 수 있습니다. 당신은 아마도 그것을 별도의 질문으로 물어보고 싶을 것입니다. – rookie1024

+1

답장을 보내 주셔서 감사합니다! 나는 그것을 구현하는 방법을 발견했다. 검정 또는 알파 색상을 지우는 OnPaintBackground, Gdi Rgn 및 DwmEnableBlurBehindWindow를 만들려면 OnSizeChanged. – IlPADlI

3

여기에 신속하게 해킹 된 WPF 솔루션이 있습니다. DWM_BLURBEHIND 구조의 hRgnBlur과 일부 interop을 사용합니다.

이 예에서는 창에 타원 모양의 배경 흐림 효과가 적용됩니다.

MVVM에 대한 친숙한 속성이나 동작으로 쉽게 변환 할 수 있습니다. WM_DWMCOMPOSITIONCHANGED 메시지를 듣고 필요한 경우 흐림을 다시 적용하는 것도 좋은 생각입니다.

<Window x:Class="WpfTest.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="200" Width="300" WindowStartupLocation="CenterScreen"> 

    <Border Background="#800000FF" Margin="30"> 
     <TextBlock Text="Hello, world!" VerticalAlignment="Center" HorizontalAlignment="Center" /> 
    </Border> 
</Window> 

결과는 다음과 같습니다 : 다음 XAML와 함께 사용

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 

     WindowStyle = WindowStyle.None; 
     AllowsTransparency = true; 

     SourceInitialized += OnSourceInitialized; 
    } 

    private void OnSourceInitialized(object sender, EventArgs eventArgs) 
    { 
     if (!NativeMethods.DwmIsCompositionEnabled()) 
      return; 

     var hwnd = new WindowInteropHelper(this).Handle; 

     var hwndSource = HwndSource.FromHwnd(hwnd); 
     var sizeFactor = hwndSource.CompositionTarget.TransformToDevice.Transform(new Vector(1.0, 1.0)); 

     Background = System.Windows.Media.Brushes.Transparent; 
     hwndSource.CompositionTarget.BackgroundColor = Colors.Transparent; 

     using (var path = new GraphicsPath()) 
     { 
      path.AddEllipse(0, 0, (int)(ActualWidth * sizeFactor.X), (int)(ActualHeight * sizeFactor.Y)); 

      using (var region = new Region(path)) 
      using (var graphics = Graphics.FromHwnd(hwnd)) 
      { 
       var hRgn = region.GetHrgn(graphics); 

       var blur = new NativeMethods.DWM_BLURBEHIND 
       { 
        dwFlags = NativeMethods.DWM_BB.DWM_BB_ENABLE | NativeMethods.DWM_BB.DWM_BB_BLURREGION | NativeMethods.DWM_BB.DWM_BB_TRANSITIONONMAXIMIZED, 
        fEnable = true, 
        hRgnBlur = hRgn, 
        fTransitionOnMaximized = true 
       }; 

       NativeMethods.DwmEnableBlurBehindWindow(hwnd, ref blur); 

       region.ReleaseHrgn(hRgn); 
      } 
     } 
    } 

    [SuppressUnmanagedCodeSecurity] 
    private static class NativeMethods 
    { 
     [StructLayout(LayoutKind.Sequential)] 
     public struct DWM_BLURBEHIND 
     { 
      public DWM_BB dwFlags; 
      public bool fEnable; 
      public IntPtr hRgnBlur; 
      public bool fTransitionOnMaximized; 
     } 

     [Flags] 
     public enum DWM_BB 
     { 
      DWM_BB_ENABLE = 1, 
      DWM_BB_BLURREGION = 2, 
      DWM_BB_TRANSITIONONMAXIMIZED = 4 
     } 

     [DllImport("dwmapi.dll", PreserveSig = false)] 
     public static extern bool DwmIsCompositionEnabled(); 

     [DllImport("dwmapi.dll", PreserveSig = false)] 
     public static extern void DwmEnableBlurBehindWindow(IntPtr hwnd, ref DWM_BLURBEHIND blurBehind); 
    } 
} 

blur example

+0

[내 대답] (http://stackoverflow.com/a/27789036/1852105)과 비슷하게 보입니다. 일부 자료는 폐기하는 것을 잊어 버렸을지라도 사용할 수 있습니다. 오, 음, 가비지 수집 (나는 희망)에 의해 처리되어야한다. 그게 문제라고 생각하니? – rookie1024

+1

@ rookie1024 이것이 자주 호출되면 문제가되지만, 한 번만 호출하면 문제가되지 않습니다. 래퍼의 파이널 라이저가 모든 것을 처리합니다. 그러나 내가 당신의 솔루션에 추가하는 것은'sizeFactor'로했던 것입니다 - 이것은 사용자의 DPI 설정 (제어판 -> 디스플레이)을 고려합니다. 또한 Aero on/off 스위치 후에 앱이보기 싫어 지길 원하지 않는다면'WM_DWMCOMPOSITIONCHANGED'도 처리 할 것을 제안합니다. –

+0

흐린 배경의 색상을 설정할 수있는 방법이 있습니까? 바탕 화면의 내 Areo 설정이 주황색입니까? 그러나 사용자가 Windows 색상 설정에 상관없이 앱을 흰색으로하고 싶습니다. – Mike

관련 문제