除了实用之外,如何(如果可能的话)你可以在运行Windows的台式机上产生“下雪”效果吗?最好只使用原始C / C ++和WinAPI。
对雪的要求是:
以下任何功能的加分点:
这些效果中的大多数都很简单,除了雪是点击的部分,并且可以很好地拖动窗户。在我的早期,我已经实现了一个实现,它使用了GetDesktopWindow()
获得的HDC,这是点击,但是用户拖动窗口时出现了问题(渲染在它们上面的雪花被“拖着”)。 / p>
该解决方案可能使用Vista / 7 Aero功能,但当然,首选通用解决方案。有什么想法吗?
答案 0 :(得分: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>
在此窗口中,我们将添加定义如下的Snowflakes:
<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>
雪花具有默认的UserControl代码隐藏,无需更改。
最后,Window CodeBehind
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,加上一些边缘检测到让雪落在其他地方的任务。
请注意,在此示例中永远不会清理雪花,并且在运行足够长时间之后,您可能会注意到一些减速。
玩得开心!