add:点名快抽

This commit is contained in:
2025-10-26 00:21:10 +08:00
parent 60b0149a9c
commit 61dbcf762c
10 changed files with 652 additions and 2 deletions
@@ -0,0 +1,125 @@
using Ink_Canvas.Helpers;
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Runtime.InteropServices;
using System.Windows.Threading;
namespace Ink_Canvas
{
/// <summary>
/// 快抽悬浮按钮
/// </summary>
public partial class QuickDrawFloatingButton : Window
{
public QuickDrawFloatingButton()
{
InitializeComponent();
// 设置无焦点状态
this.Focusable = false;
this.ShowInTaskbar = false;
}
private void FloatingButton_Loaded(object sender, RoutedEventArgs e)
{
// 设置位置到屏幕右下角稍微靠近中部
SetPositionToBottomRight();
// 应用置顶
ApplyFloatingButtonTopmost();
}
private void SetPositionToBottomRight()
{
try
{
// 获取主屏幕的工作区域
var workingArea = SystemParameters.WorkArea;
this.Left = workingArea.Right - this.Width - 0;
this.Top = workingArea.Bottom - this.Height - 200;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"设置悬浮按钮位置失败: {ex.Message}", LogHelper.LogType.Error);
// 如果计算失败,使用默认位置
this.Left = 720;
this.Top = 400;
}
}
private void FloatingButton_Click(object sender, MouseButtonEventArgs e)
{
try
{
// 打开快抽窗口
var quickDrawWindow = new QuickDrawWindow();
quickDrawWindow.ShowDialog();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"打开快抽窗口失败: {ex.Message}", LogHelper.LogType.Error);
}
}
#region Win32 API
[DllImport("user32.dll")]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
[DllImport("user32.dll")]
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
private const int GWL_EXSTYLE = -20;
private const int WS_EX_TOPMOST = 0x00000008;
private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
private const uint SWP_NOMOVE = 0x0002;
private const uint SWP_NOSIZE = 0x0001;
private const uint SWP_NOACTIVATE = 0x0010;
private const uint SWP_SHOWWINDOW = 0x0040;
private const uint SWP_NOOWNERZORDER = 0x0200;
/// <summary>
/// 应用悬浮按钮置顶
/// </summary>
private void ApplyFloatingButtonTopmost()
{
try
{
var hwnd = new WindowInteropHelper(this).Handle;
if (hwnd == IntPtr.Zero) return;
// 强制激活窗口
Activate();
Focus();
// 设置WPF的Topmost属性
Topmost = true;
// 使用Win32 API强制置顶
// 1. 设置窗口样式为置顶
int exStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
SetWindowLong(hwnd, GWL_EXSTYLE, exStyle | WS_EX_TOPMOST);
// 2. 使用SetWindowPos确保窗口在最顶层
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOOWNERZORDER);
LogHelper.WriteLogToFile("快抽悬浮按钮已应用置顶", LogHelper.LogType.Trace);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"应用快抽悬浮按钮置顶失败: {ex.Message}", LogHelper.LogType.Error);
}
}
#endregion
}
}
@@ -0,0 +1,43 @@
<Window x:Class="Ink_Canvas.QuickDrawFloatingButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Topmost="True" Background="Transparent"
mc:Ignorable="d" WindowStyle="None" AllowsTransparency="True"
Loaded="FloatingButton_Loaded" WindowStartupLocation="Manual"
ShowInTaskbar="False" Focusable="False"
Title="快抽悬浮按钮" Height="45" Width="45">
<Window.Resources>
<ResourceDictionary>
<!-- 悬浮按钮资源 -->
<SolidColorBrush x:Key="QuickDrawFloatingButtonBackground" Color="#80000000"/>
<SolidColorBrush x:Key="QuickDrawFloatingButtonBorderBrush" Color="#40000000"/>
<SolidColorBrush x:Key="QuickDrawFloatingButtonIconForeground" Color="White"/>
</ResourceDictionary>
</Window.Resources>
<Border Background="{DynamicResource QuickDrawFloatingButtonBackground}"
CornerRadius="8"
BorderThickness="1"
BorderBrush="{DynamicResource QuickDrawFloatingButtonBorderBrush}"
MouseLeftButtonDown="FloatingButton_Click"
Cursor="Hand">
<Border.Effect>
<DropShadowEffect Color="Black" Direction="315" ShadowDepth="3" Opacity="0.3" BlurRadius="5"/>
</Border.Effect>
<Grid>
<Path Data="M5 7C5 8.06087 5.42143 9.07828 6.17157 9.82843C6.92172 10.5786 7.93913 11 9 11C10.0609 11 11.0783 10.5786 11.8284 9.82843C12.5786 9.07828 13 8.06087 13 7C13 5.93913 12.5786 4.92172 11.8284 4.17157C11.0783 3.42143 10.0609 3 9 3C7.93913 3 6.92172 3.42143 6.17157 4.17157C5.42143 4.92172 5 5.93913 5 7Z M3 21V19C3 17.9391 3.42143 16.9217 4.17157 16.1716C4.92172 15.4214 5.93913 15 7 15H11C12.0609 15 13.0783 15.4214 13.8284 16.1716C14.5786 16.9217 15 17.9391 15 19V21 M16 3.13C16.8604 3.35031 17.623 3.85071 18.1676 4.55232C18.7122 5.25392 19.0078 6.11683 19.0078 7.005C19.0078 7.89318 18.7122 8.75608 18.1676 9.45769C17.623 10.1593 16.8604 10.6597 16 10.88 M21 21V19C20.9949 18.1172 20.6979 17.2608 20.1553 16.5644C19.6126 15.868 18.8548 15.3707 18 15.15"
Stroke="{DynamicResource QuickDrawFloatingButtonIconForeground}"
StrokeThickness="2"
StrokeLineJoin="Round"
Fill="Transparent"
Width="20" Height="20"
Stretch="Uniform"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</Border>
</Window>
+283
View File
@@ -0,0 +1,283 @@
using Ink_Canvas.Helpers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Threading;
using System.Runtime.InteropServices;
using Newtonsoft.Json;
using System.IO;
namespace Ink_Canvas
{
/// <summary>
/// 快抽窗口
/// </summary>
public partial class QuickDrawWindow : Window
{
private Random random = new Random();
private int autoCloseWaitTime = 2500; // 自动关闭等待时间(毫秒)
private List<string> nameList = new List<string>(); // 名单列表
public QuickDrawWindow()
{
InitializeComponent();
this.Focusable = false;
this.ShowInTaskbar = false;
InitializeSettings();
LoadNamesFromFile();
StartQuickDraw();
}
private void InitializeSettings()
{
try
{
if (MainWindow.Settings?.RandSettings != null)
{
autoCloseWaitTime = (int)MainWindow.Settings.RandSettings.RandWindowOnceCloseLatency * 1000;
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"初始化快抽窗口设置失败: {ex.Message}", LogHelper.LogType.Error);
}
}
private void LoadNamesFromFile()
{
try
{
string namesFilePath = App.RootPath + "Names.txt";
if (File.Exists(namesFilePath))
{
string content = File.ReadAllText(namesFilePath);
nameList = content.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries)
.Select(name => name.Trim())
.Where(name => !string.IsNullOrEmpty(name))
.ToList();
}
else
{
nameList.Clear();
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"加载名单文件失败: {ex.Message}", LogHelper.LogType.Error);
nameList.Clear();
}
}
private void StartQuickDraw()
{
try
{
// 延迟100ms后开始抽选动画
new System.Threading.Thread(() =>
{
System.Threading.Thread.Sleep(100);
Application.Current.Dispatcher.Invoke(() =>
{
StartQuickDrawAnimation();
});
}).Start();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"开始快抽失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 快抽动画
/// </summary>
private void StartQuickDrawAnimation()
{
const int animationTimes = 100; // 动画次数
const int sleepTime = 5; // 每次动画间隔(毫秒)
new System.Threading.Thread(() =>
{
if (nameList.Count > 0)
{
// 有名单时,从名单中抽选
StartNameDrawAnimation(animationTimes, sleepTime);
}
else
{
// 没有名单时,从1-60数字中抽选
StartNumberDrawAnimation(animationTimes, sleepTime);
}
}).Start();
}
/// <summary>
/// 名单抽选动画
/// </summary>
private void StartNameDrawAnimation(int animationTimes, int sleepTime)
{
List<string> usedNames = new List<string>();
for (int i = 0; i < animationTimes; i++)
{
// 随机选择一个名字进行动画显示,避免立即重复
string randomName;
do
{
randomName = nameList[random.Next(0, nameList.Count)];
} while (usedNames.Count > 0 && usedNames[usedNames.Count - 1] == randomName);
usedNames.Add(randomName);
Application.Current.Dispatcher.Invoke(() =>
{
MainResultDisplay.Text = randomName;
});
System.Threading.Thread.Sleep(sleepTime);
}
// 动画结束,显示最终结果
Application.Current.Dispatcher.Invoke(() =>
{
// 随机选择一个最终名字
string finalName = nameList[random.Next(0, nameList.Count)];
MainResultDisplay.Text = finalName;
});
// 显示结果后,等待一段时间让用户看到结果,然后关闭窗口
new System.Threading.Thread(() =>
{
System.Threading.Thread.Sleep(autoCloseWaitTime);
Application.Current.Dispatcher.Invoke(() =>
{
Close();
});
}).Start();
}
/// <summary>
/// 数字抽选动画
/// </summary>
private void StartNumberDrawAnimation(int animationTimes, int sleepTime)
{
List<int> usedNumbers = new List<int>();
for (int i = 0; i < animationTimes; i++)
{
// 随机选择一个数字进行动画显示,避免立即重复
int randomNumber;
do
{
randomNumber = random.Next(1, 61); // 1-60
} while (usedNumbers.Count > 0 && usedNumbers[usedNumbers.Count - 1] == randomNumber);
usedNumbers.Add(randomNumber);
Application.Current.Dispatcher.Invoke(() =>
{
MainResultDisplay.Text = randomNumber.ToString();
});
System.Threading.Thread.Sleep(sleepTime);
}
// 动画结束,显示最终结果
Application.Current.Dispatcher.Invoke(() =>
{
// 随机选择一个最终数字
int finalNumber = random.Next(1, 61);
MainResultDisplay.Text = finalNumber.ToString();
});
// 显示结果后,等待一段时间让用户看到结果,然后关闭窗口
new System.Threading.Thread(() =>
{
System.Threading.Thread.Sleep(autoCloseWaitTime);
Application.Current.Dispatcher.Invoke(() =>
{
Close();
});
}).Start();
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
// 窗口关闭时的清理工作
}
private void WindowDragMove(object sender, MouseButtonEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
DragMove();
}
#region Win32 API
[DllImport("user32.dll")]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
[DllImport("user32.dll")]
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
private const int GWL_EXSTYLE = -20;
private const int WS_EX_TOPMOST = 0x00000008;
private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
private const uint SWP_NOMOVE = 0x0002;
private const uint SWP_NOSIZE = 0x0001;
private const uint SWP_NOACTIVATE = 0x0010;
private const uint SWP_SHOWWINDOW = 0x0040;
private const uint SWP_NOOWNERZORDER = 0x0200;
/// <summary>
/// 应用快抽窗口置顶
/// </summary>
private void ApplyQuickDrawWindowTopmost()
{
try
{
var hwnd = new WindowInteropHelper(this).Handle;
if (hwnd == IntPtr.Zero) return;
// 设置WPF的Topmost属性
Topmost = true;
// 使用Win32 API强制置顶
// 1. 设置窗口样式为置顶
int exStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
SetWindowLong(hwnd, GWL_EXSTYLE, exStyle | WS_EX_TOPMOST);
// 2. 使用SetWindowPos确保窗口在最顶层
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOOWNERZORDER);
LogHelper.WriteLogToFile("快抽窗口已应用置顶", LogHelper.LogType.Trace);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"应用快抽窗口置顶失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 窗口加载事件处理,确保置顶
/// </summary>
private void QuickDrawWindow_Loaded(object sender, RoutedEventArgs e)
{
// 使用延迟确保窗口完全加载后再应用置顶
Dispatcher.BeginInvoke(new Action(() =>
{
ApplyQuickDrawWindowTopmost();
}), DispatcherPriority.Loaded);
}
#endregion
}
}
+77
View File
@@ -0,0 +1,77 @@
<Window x:Class="Ink_Canvas.QuickDrawWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Ink_Canvas"
Topmost="True" Background="Transparent"
mc:Ignorable="d" WindowStyle="None" AllowsTransparency="True"
Loaded="QuickDrawWindow_Loaded" Closing="Window_Closing" WindowStartupLocation="CenterScreen"
Title="快抽窗口" Height="200" Width="400" Focusable="False" ShowInTaskbar="False">
<Window.Resources>
<ResourceDictionary>
<!-- 快抽窗口资源 -->
<SolidColorBrush x:Key="QuickDrawWindowBackground" Color="#1f1f1f"/>
<SolidColorBrush x:Key="QuickDrawWindowBorderBrush" Color="#E0E0E0"/>
<SolidColorBrush x:Key="QuickDrawWindowTitleForeground" Color="White"/>
<SolidColorBrush x:Key="QuickDrawWindowDigitForeground" Color="White"/>
</ResourceDictionary>
</Window.Resources>
<Border Background="{DynamicResource QuickDrawWindowBackground}"
CornerRadius="15"
BorderThickness="1"
BorderBrush="{DynamicResource QuickDrawWindowBorderBrush}"
Margin="10"
x:Name="MainBorder"
MouseLeftButtonDown="WindowDragMove">
<Grid>
<!-- 主要内容区域 -->
<Grid>
<!-- 顶部标题栏 -->
<Grid Height="50" Background="{DynamicResource QuickDrawWindowBackground}"
x:Name="TitleBar"
VerticalAlignment="Top"
MouseLeftButtonDown="WindowDragMove"
Margin="10,8,40,0">
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Margin="22,0,0,0">
<!-- 快抽图标 -->
<Path Data="M5 7C5 8.06087 5.42143 9.07828 6.17157 9.82843C6.92172 10.5786 7.93913 11 9 11C10.0609 11 11.0783 10.5786 11.8284 9.82843C12.5786 9.07828 13 8.06087 13 7C13 5.93913 12.5786 4.92172 11.8284 4.17157C11.0783 3.42143 10.0609 3 9 3C7.93913 3 6.92172 3.42143 6.17157 4.17157C5.42143 4.92172 5 5.93913 5 7Z M3 21V19C3 17.9391 3.42143 16.9217 4.17157 16.1716C4.92172 15.4214 5.93913 15 7 15H11C12.0609 15 13.0783 15.4214 13.8284 16.1716C14.5786 16.9217 15 17.9391 15 19V21 M16 3.13C16.8604 3.35031 17.623 3.85071 18.1676 4.55232C18.7122 5.25392 19.0078 6.11683 19.0078 7.005C19.0078 7.89318 18.7122 8.75608 18.1676 9.45769C17.623 10.1593 16.8604 10.6597 16 10.88 M21 21V19C20.9949 18.1172 20.6979 17.2608 20.1553 16.5644C19.6126 15.868 18.8548 15.3707 18 15.15"
Stroke="{DynamicResource QuickDrawWindowTitleForeground}"
StrokeThickness="2"
StrokeLineJoin="Round"
Fill="Transparent"
Width="24" Height="24"
Stretch="Uniform"
Margin="0,0,8,0"/>
<!-- 快抽文字 -->
<TextBlock Text="快抽" FontSize="20" FontWeight="Bold"
Foreground="{DynamicResource QuickDrawWindowTitleForeground}"
x:Name="TitleText"/>
</StackPanel>
</Grid>
<!-- 主要内容区域 -->
<Grid Margin="20,60,20,20">
<!-- 结果显示区域 -->
<Grid x:Name="ResultGrid" HorizontalAlignment="Center" VerticalAlignment="Center">
<!-- 主结果显示 -->
<TextBlock x:Name="MainResultDisplay"
Text="准备抽选..."
FontSize="48"
FontWeight="Bold"
Foreground="{DynamicResource QuickDrawWindowDigitForeground}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
TextAlignment="Center"/>
</Grid>
</Grid>
</Grid>
</Grid>
</Border>
</Window>