2011-01-11 4 views
11

実用的な脇に、Windowsを実行しているデスクトップPCに「スノーリング」エフェクトを作成する方法はありますか?好ましくは、生のC/C++とWinAPIだけを使用してください。Windowsデスクトップに吹雪を作成するには?

雪のための要件は次のとおりです。

  • は、他のすべてに示す(上に表示されます注意:最前面ウィンドウは、まだ雪の上に得ることができ、それはOKです、私はありませんがあることを理解して」。任意のアプリの「絶対上の」フラグ)
  • スノーフレークは小さく、おそらくはシンプルなドットまたは数個の白いピクセルのクラスターです。
  • コンピュータでの作業は煩わしくはありません(スノーフレークをクリックすると、そのウィンドウにクリックスルーが送信されます)。
  • ユーザーがウィンドウをドラッグするとうまくいきます。
  • マルチモニタ対応。以下の特徴のいずれかのために

ボーナスポイント:

  • 雪が(それが画面の下部にあるの場合)ウィンドウまたはタスクバーの下縁部に蓄積。
  • 雪はトップレベルのウィンドウにも蓄積されます。またはおそらくいくつかの雪が蓄積し、いくつかは続けて、タイトルバーですべてのウィンドウに蓄積します。
  • ウィンドウに蓄積された雪は、ウィンドウがドラッグされたときに「震え」ます。
  • タスクバーに蓄積された雪は、Vista/7の下にある拡張「スタート」ボタンを認識しています。
  • スノーフレークにはシャドウ/アウトラインがあるため、白い背景に表示されます。
  • 雪片は複雑な雪のような形をしています(まだ小さいはずです)。
  • スノーフレークをクリックすると、クリックスルーが下にあるウィンドウに送られますが、スノーフレークは少しクールなアニメーションで蒸発します。

これらの効果のほとんどは、雪がクリックスルーされ、ウィンドウのドラッグでうまくいく部分を除いて、十分に簡単です。私の初期の段階では、GetDesktopWindow()から取得したHDCを利用した実装を行いましたが、これはクリックスルーでしたが、ユーザーがウィンドウをドラッグする際に問題がありました(レンダリングされた雪片は「ドラッグ」されました)。

解決策はVista/7 Aero機能を使用することができますが、勿論、普遍的な解決策が好まれます。何か案は?

+10

今日の夕方、NYCの私の家の前に私のコンピュータを置いておくことで、5つの必要な機能をすべて満たすことができます。 –

+0

@ラリー・ルスティグ - しかし、私はより多くのソフトウェアソリューションを望んでいましたが、それをSOと全部で投稿すると何が... –

+0

naysayer(close投票者)に - あなたは何を理解していますか?もっと明確にするか? –

答えて

6

この簡潔さと簡潔さのために、この回答は限られた要件のセットに調整されています。これを拡張してより堅牢にするのは簡単です。

この回答はWindows XPでWPFを使用しています。最大2台のモニターで動作し、他のWindowsシステムでも動作するはずです。それは簡単なウィンドウで始まる

:このウィンドウに

<Window x:Class="TestDump.Window1" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
Title="Window1" WindowStartupLocation="Manual" Loaded="Window_Loaded" 
WindowStyle="None" AllowsTransparency="True" Background="Transparent" 
> 
    <Grid x:Name="FieldOfSnow"/> 
</Window> 

、我々は次のように定義された雪片を追加します。

<UserControl x:Class="TestDump.SnowFlake" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
Height="5" Width="5"> 
    <Border Background="White" CornerRadius="2" BorderThickness="1" BorderBrush="LightGray"/> 
</UserControl> 

雪がデフォルトのユーザーコントロールのコードビハインド変更なしを持っています。最後に

、ウィンドウの分離コード

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Data; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Imaging; 
using System.Windows.Navigation; 
using System.Windows.Shapes; 
using System.Runtime.InteropServices; 
using System.Windows.Interop; 

namespace TestDump 
{ 
    /// <summary> 
    /// Interaction logic for Window1.xaml 
    /// </summary> 
    public partial class Window1 : Window 
    { 
     private TimeSpan _lastRender; 

     public Window1() 
     { 
      InitializeComponent(); 
      _lastRender = TimeSpan.FromTicks(0); 
      CompositionTarget.Rendering += SnowflakeTick; 
     } 

     private void Window_Loaded(object sender, RoutedEventArgs e) 
     { 
      this.Topmost = true; 
      this.Top = 0; 
      this.Left = 0; 

      this.Width = System.Windows.SystemParameters.PrimaryScreenWidth; 
      this.Height = System.Windows.SystemParameters.PrimaryScreenHeight; 

      if (System.Windows.Forms.SystemInformation.MonitorCount == 2) 
      { 
       System.Drawing.Rectangle SecondScreenArea = System.Windows.Forms.Screen.AllScreens[1].Bounds; 

       this.Width += SecondScreenArea.Width; 
       this.Height = this.Height > SecondScreenArea.Height ? this.Height : SecondScreenArea.Height; 
      } 
     } 

     public const int WS_EX_TRANSPARENT = 0x00000020; 
     public const int GWL_EXSTYLE = (-20); 

     [DllImport("user32.dll")] 
     public static extern int GetWindowLong(IntPtr hwnd, int index); 

     [DllImport("user32.dll")] 
     public static extern int SetWindowLong(IntPtr hwnd, int index, int newStyle); 

     protected override void OnSourceInitialized(EventArgs e) 
     { 
      base.OnSourceInitialized(e); 

      // Get this window's handle 
      IntPtr hwnd = new WindowInteropHelper(this).Handle; 

      // Change the extended window style to include WS_EX_TRANSPARENT 
      int extendedStyle = GetWindowLong(hwnd, GWL_EXSTYLE); 
      SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle | WS_EX_TRANSPARENT); 
     } 

     List<TranslateTransform> Flakes = new List<TranslateTransform>(); 
     Random rand = new Random(); 

     private void SnowflakeTick(object sender, EventArgs e) 
     { 
      RenderingEventArgs renderingArgs = (RenderingEventArgs)e; 
      TimeSpan dTime = (renderingArgs.RenderingTime - _lastRender); 
      double deltaTime = dTime.TotalMilliseconds; 
      _lastRender = renderingArgs.RenderingTime; 

      if (_lastRender.Milliseconds < deltaTime) 
      { 
       TranslateTransform SnowPos = new TranslateTransform(this.Width * rand.Next(1000)/1000.0 - this.Width/2, -this.Height/2); 

       SnowFlake sf = new SnowFlake(); 
       sf.RenderTransform = SnowPos; 

       // The flakes are centered when added, so all positions must be translated with this in mind. 
       FieldOfSnow.Children.Add(sf); 
       Flakes.Add(SnowPos); 
      } 

      foreach (TranslateTransform Flake in Flakes) 
      { 
       double ScreenHeight = this.Height/2 - 2; 

       if (Flake.Y < ScreenHeight) 
       { 
        Flake.Y += deltaTime/50; 
       } 
      } 
     } 
    } 
} 

私は、マルチスクリーンのものを得るために、フォームのコードのビットを使用していた、と私は私のプロジェクトでのアセンブリへの参照を含める必要がありました。

私はそれほど多くのテストをしていませんが、私のシステムでは動作し、完了すると雪は画面の下部に座ります。

クリックスルー動作のためにthisリファレンスを使用しました。

私は、thisに適応できるはずですが、雪が他の場所に座ってしまうようなエッジ検出があります。

この例では、雪片は決して掃除されず、十分に長い時間が経過した後、雪が降りることがあります。

楽しいよ!

+0

あなたのトリックもWS_EX_TRANSPARENT(別名レイヤードウィンドウ)です。これが動作することを確認していただきありがとうございます! :) –

+0

非常に良い答え、+1 –

+0

どのようにJavaでそれを作る考えですか? – Alpine

関連する問題