update:新建多人跳绳表&新建跳远位置点表&跳远配置页面&管理员密码输入

This commit is contained in:
ltx 2025-11-21 13:23:46 +08:00
parent 68078a2294
commit ec7b800c26
9 changed files with 755 additions and 29 deletions

View File

@ -19,6 +19,7 @@ namespace AiSportsMicrospaceDB.DBContext
public DbSet<BasicConfig> BasicConfig { get; set; } public DbSet<BasicConfig> BasicConfig { get; set; }
public DbSet<SixGroupPoints> SixGroupPoints { get; set; } public DbSet<SixGroupPoints> SixGroupPoints { get; set; }
public DbSet<JumpLongPoints> JumpLongPoints { get; set; }
} }
} }

View File

@ -0,0 +1,25 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AiSportsMicrospaceDB.Entities
{
public class JumpLongPoints {
// ✅ 主键
public int Id { get; set; }
public Point TopPoint1 { get; set; }
public Point TopPoint2 { get; set; }
public Point TopPoint3 { get; set; }
public Point BottomPoint1 { get; set; }
public Point BottomPoint2 { get; set; }
public Point BottomPoint3 { get; set; }
}
}

View File

@ -1,6 +1,7 @@
<Application x:Class="Wpf_AiSportsMicrospace.App" <Application x:Class="Wpf_AiSportsMicrospace.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:local="clr-namespace:Wpf_AiSportsMicrospace.Views" xmlns:local="clr-namespace:Wpf_AiSportsMicrospace.Views"
xmlns:conv="clr-namespace:Wpf_AiSportsMicrospace.Converter"> xmlns:conv="clr-namespace:Wpf_AiSportsMicrospace.Converter">
@ -8,12 +9,33 @@
<!--StartupUri="Views/JumpRope/GroupJumpRope.xaml">--> <!--StartupUri="Views/JumpRope/GroupJumpRope.xaml">-->
<Application.Resources> <Application.Resources>
<FontFamily x:Key="AppFont">./Resoures/Fonts/myFontFamily</FontFamily> <ResourceDictionary>
<Style TargetType="TextBlock"> <!-- 1. 先合并 HandyControl 资源 -->
<Setter Property="FontFamily" Value="./Resoures/Fonts/myFontFamily"/> <ResourceDictionary.MergedDictionaries>
</Style> <ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/SkinDefault.xaml"/>
<conv:DotColorConverter x:Key="DotColorConverter"/> <ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/Theme.xaml"/>
<!--<conv:SpacingConverter x:Key="SpacingConverter"/>--> </ResourceDictionary.MergedDictionaries>
</Application.Resources>
<!-- 2. 你的自定义资源 -->
<!-- 字体 -->
<FontFamily x:Key="AppFont">pack://application:,,,/YourApp;component/Resources/Fonts/#MyFontFamily</FontFamily>
<!-- 文本样式 -->
<Style TargetType="TextBlock" BasedOn="{StaticResource {x:Type TextBlock}}">
<Setter Property="FontFamily" Value="{StaticResource AppFont}"/>
<Setter Property="Foreground" Value="#333333"/>
<Setter Property="FontSize" Value="14"/>
</Style>
<!-- 转换器 -->
<conv:DotColorConverter x:Key="DotColorConverter"/>
<!--<conv:SpacingConverter x:Key="SpacingConverter"/>-->
<!-- 其他自定义样式 -->
<Style x:Key="PrimaryButtonStyle" TargetType="Button" BasedOn="{StaticResource ButtonPrimary}">
<Setter Property="FontFamily" Value="{StaticResource AppFont}"/>
</Style>
</ResourceDictionary>
</Application.Resources>
</Application> </Application>

File diff suppressed because one or more lines are too long

View File

@ -106,12 +106,12 @@ public partial class MainWindow : Window
private void ping_Click(object sender, RoutedEventArgs e) private void ping_Click(object sender, RoutedEventArgs e)
{ {
var config = _context.BasicConfig.FirstOrDefault(); //var config = _context.BasicConfig.FirstOrDefault();
if (config != null) //if (config != null)
{ //{
//var ip = config.Ip; // //var ip = config.Ip;
} //}
var host = this.host.Text.Trim(); var host = this.host.Text.Trim();
if (string.IsNullOrWhiteSpace(host)) if (string.IsNullOrWhiteSpace(host))

View File

@ -3,12 +3,12 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Wpf_AiSportsMicrospace.MyUserControl" xmlns:local="clr-namespace:Wpf_AiSportsMicrospace.MyUserControl"
xmlns:gif="http://wpfanimatedgif.codeplex.com" xmlns:gif="http://wpfanimatedgif.codeplex.com"
xmlns:hc="https://handyorg.github.io/handycontrol"
Height="1080" Width="1920" Loaded="Window_Loaded" Unloaded="Home_Unloaded"> Height="1080" Width="1920" Loaded="Window_Loaded" Unloaded="Home_Unloaded">
<Grid VerticalAlignment="Bottom"> <Grid VerticalAlignment="Bottom">
<Grid.Background> <Grid.Background>
<ImageBrush ImageSource="/Resources/Img/Album/home_bg.png" Stretch="UniformToFill"/> <ImageBrush ImageSource="/Resources/Img/Album/home_bg.png" Stretch="UniformToFill"/>
</Grid.Background> </Grid.Background>
<!-- 顶部图片 --> <!-- 顶部图片 -->
<Image <Image
Source="/Resources/Img/Album/title.png" Source="/Resources/Img/Album/title.png"
@ -74,5 +74,42 @@
Width="880" Width="880"
/> />
<!-- 隐藏的管理员触发按钮(右上角)-->
<Button x:Name="HiddenAdminButton"
Width="60" Height="60"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Margin="0,10,10,0"
Opacity="0"
Background="Transparent"
BorderThickness="0"
Click="HiddenAdminButton_Click"
Focusable="False"
/>
<!-- 密码弹窗 -->
<Grid x:Name="AdminDialogGrid" Visibility="Hidden" Background="#80000000">
<Border CornerRadius="10" Width="420" Height="130" Background="#FFF">
<Grid HorizontalAlignment="Center" hc:BorderElement.CornerRadius="10" VerticalAlignment="Center" Width="420" Height="130" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="请输入管理员密码:" FontSize="16" Margin="12" Grid.Row="0"/>
<hc:PasswordBox x:Name="AdminPasswordBox" Grid.Row="1" Margin="12,4,12,0" FontSize="16" KeyDown="AdminPasswordBox_KeyDown"/>
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right" Margin="12">
<RadioButton Style="{DynamicResource RadioGroupItemSingle}" Content="取消" x:Name="AdminCancelButton" Click="AdminCancelButton_Click" />
<hc:ButtonGroup Margin="30,0,0,0" Orientation="Vertical" Style="{StaticResource ButtonGroupSolid}">
<RadioButton Content="确定" IsChecked="True" x:Name="AdminOkButton" Click="AdminOkButton_Click"/>
</hc:ButtonGroup>
</StackPanel>
</Grid>
</Border>
</Grid>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@ -14,6 +14,7 @@ using System.Windows.Controls;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Animation; using System.Windows.Media.Animation;
using System.Windows.Threading;
using Views.JumpLong; using Views.JumpLong;
using Views.JumpRope; using Views.JumpRope;
using Wpf_AiSportsMicrospace; using Wpf_AiSportsMicrospace;
@ -39,13 +40,23 @@ namespace Wpf_AiSportsMicrospace
{ {
public static Uri loadingImage = new Uri("/Resources/Img/Album/1.gif", UriKind.Relative); public static Uri loadingImage = new Uri("/Resources/Img/Album/1.gif", UriKind.Relative);
public static Uri countDownGif = new Uri("/Resources/Img/gif/time_3.gif", UriKind.Relative); public static Uri countDownGif = new Uri("/Resources/Img/gif/time_3.gif", UriKind.Relative);
private int _adminClickCount = 0;
private readonly DispatcherTimer _resetTimer;
private Main _mainWin => Application.Current.MainWindow as Main; private Main _mainWin => Application.Current.MainWindow as Main;
public Home() public Home()
{ {
InitializeComponent(); InitializeComponent();
// 初始化隐藏按钮点击计数重置定时器3 秒无操作则重置计数)
_resetTimer = new DispatcherTimer
{
Interval = TimeSpan.FromSeconds(3)
};
_resetTimer.Tick += (s, e) =>
{
_adminClickCount = 0;
_resetTimer.Stop();
};
string projectRoot = Path.Combine(AppContext.BaseDirectory, @"..\..\.."); string projectRoot = Path.Combine(AppContext.BaseDirectory, @"..\..\..");
string albumPath = Path.Combine(projectRoot, "Resources", "Img"); string albumPath = Path.Combine(projectRoot, "Resources", "Img");
@ -161,5 +172,77 @@ namespace Wpf_AiSportsMicrospace
var mainWin = Application.Current.MainWindow as Main; var mainWin = Application.Current.MainWindow as Main;
mainWin!.ShowCountDownAnimation(); mainWin!.ShowCountDownAnimation();
} }
// 隐藏按钮点击处理:连续点击五次显示内嵌密码弹窗
private void HiddenAdminButton_Click(object sender, RoutedEventArgs e)
{
_adminClickCount++;
// 每次点击重启计时器
_resetTimer.Stop();
_resetTimer.Start();
if (_adminClickCount >= 5)
{
_resetTimer.Stop();
_adminClickCount = 0;
// 显示内嵌密码弹窗
AdminPasswordBox.Password = string.Empty;
AdminDialogGrid.Visibility = Visibility.Visible;
AdminPasswordBox.Focus();
}
}
// 密码弹窗:确定按钮
private void AdminOkButton_Click(object sender, RoutedEventArgs e)
{
var entered = AdminPasswordBox.Password ?? string.Empty;
if (entered == "8888")
{
AdminDialogGrid.Visibility = Visibility.Collapsed;
// 密码正确,打开管理员页面(已有 AdminWindow 或按需改为导航)
try
{
var mainWin = Application.Current.MainWindow as Main;
mainWin.SwitchPageWithMaskAnimation(new LongSttting(), true);
//var adminWin = new Views.AdminWindow();
//adminWin.Owner = Window.GetWindow(this);
//adminWin.Show();
}
catch (Exception ex)
{
MessageBox.Show("密码正确");
Debug.WriteLine($"打开管理员页面异常: {ex.Message}");
}
}
else
{
MessageBox.Show("密码错误", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
AdminPasswordBox.Password = string.Empty;
AdminPasswordBox.Focus();
}
}
// 密码弹窗:取消按钮
private void AdminCancelButton_Click(object sender, RoutedEventArgs e)
{
AdminDialogGrid.Visibility = Visibility.Collapsed;
}
// 在 PasswordBox 按 Enter 等同于确定,按 Esc 等同于取消
private void AdminPasswordBox_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
AdminOkButton_Click(sender, e);
e.Handled = true;
}
else if (e.Key == Key.Escape)
{
AdminCancelButton_Click(sender, e);
e.Handled = true;
}
}
} }
} }

View File

@ -0,0 +1,85 @@
<UserControl x:Class="Wpf_AiSportsMicrospace.Views.LongSttting"
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:Wpf_AiSportsMicrospace.MyUserControl"
xmlns:hc="https://handyorg.github.io/handycontrol"
Loaded="Window_Loaded"
mc:Ignorable="d" Width="1920" Height="1080">
<Grid>
<Image x:Name="videoImage" Stretch="Uniform" />
<!-- 背景网格,用于显示坐标参考 -->
<Canvas x:Name="MainCanvas" >
<!-- 网格线 -->
<Canvas.Resources>
<DrawingBrush x:Key="GridBackground" Viewport="0,0,50,50" ViewportUnits="Absolute" TileMode="Tile">
<DrawingBrush.Drawing>
<DrawingGroup>
<GeometryDrawing Brush="White">
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0,0,50,50"/>
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing>
<GeometryDrawing.Pen>
<Pen Brush="LightGray" Thickness="0.5"/>
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<GeometryGroup>
<LineGeometry StartPoint="0,0" EndPoint="0,50"/>
<LineGeometry StartPoint="0,0" EndPoint="50,0"/>
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Canvas.Resources>
<!--<Canvas.Background>
<StaticResource ResourceKey="GridBackground"/>
</Canvas.Background>-->
<!-- 可拖动的点 -->
<Ellipse x:Name="TopPoint1" Width="20" Height="20" Fill="Red" Cursor="Hand"
Canvas.Left="245" Canvas.Top="741" Tag="TopPoint1"/>
<Ellipse x:Name="TopPoint2" Width="20" Height="20" Fill="Red" Cursor="Hand"
Canvas.Left="1498" Canvas.Top="730" Tag="TopPoint2"/>
<Ellipse x:Name="TopPoint3" Width="20" Height="20" Fill="Red" Cursor="Hand"
Canvas.Left="1689" Canvas.Top="724" Tag="TopPoint3"/>
<Ellipse x:Name="BottomPoint1" Width="20" Height="20" Fill="Blue" Cursor="Hand"
Canvas.Left="191" Canvas.Top="918" Tag="BottomPoint1"/>
<Ellipse x:Name="BottomPoint2" Width="20" Height="20" Fill="Blue" Cursor="Hand"
Canvas.Left="1516" Canvas.Top="918" Tag="BottomPoint2"/>
<Ellipse x:Name="BottomPoint3" Width="20" Height="20" Fill="Blue" Cursor="Hand"
Canvas.Left="1722" Canvas.Top="909" Tag="BottomPoint3"/>
<!-- 坐标显示标签 -->
<hc:Tag ShowCloseButton="False" IsSelected="True" x:Name="CoordinateDisplay" Content="你是"
Padding="18,0" FontSize="14" Visibility="Visible"/>
</Canvas>
<!-- 控制面板 -->
<StackPanel HorizontalAlignment="Right" VerticalAlignment="Top" Margin="20" Width="200">
<Border Background="#F0F0F0" Padding="15" CornerRadius="8">
<StackPanel>
<TextBlock Text="跳远点编辑器" FontSize="16" FontWeight="Bold" Margin="0,0,0,10"/>
<TextBlock Text="红色点:上边界点" Foreground="Red" FontWeight="Bold"/>
<TextBlock Text="蓝色点:下边界点" Foreground="Blue" FontWeight="Bold" Margin="0,0,0,10"/>
<Button x:Name="LoadPointsButton" Content="加载点数据" Click="LoadPointsButton_Click"
Margin="0,5" Height="30" Background="#4CAF50" Foreground="White"/>
<Button x:Name="SavePointsButton" Content="保存点数据" Click="SavePointsButton_Click"
Margin="0,5" Height="30" Background="#2196F3" Foreground="White"/>
<Button x:Name="ResetPointsButton" Content="重置为默认" Click="ResetPointsButton_Click"
Margin="0,5" Height="30" Background="#FF9800" Foreground="White"/>
<TextBlock x:Name="StatusText" Text="就绪" Margin="0,10,0,0" TextWrapping="Wrap"/>
</StackPanel>
</Border>
</StackPanel>
</Grid>
</UserControl>

View File

@ -0,0 +1,415 @@
using AiSportsMicrospaceDB.DBContext;
using AiSportsMicrospaceDB.Entities;
using Emgu.CV.Reg;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using SharpDX.Direct3D9;
using SkiaSharp;
using System.Diagnostics;
using System.Drawing.Imaging;
using System.IO;
using System.Net.NetworkInformation;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Threading;
using Wpf_AiSportsMicrospace.Common;
using Wpf_AiSportsMicrospace.Dto;
using Yztob.AiSports.Inferences.Abstractions;
using Yztob.AiSports.Inferences.Things;
using Yztob.AiSports.Postures.Sports;
using Yztob.AiSports.Postures.Things;
using Yztob.AiSports.Sensors.Abstractions;
using Yztob.AiSports.Sensors.Things;
namespace Wpf_AiSportsMicrospace.Views
{
public partial class LongSttting : UserControl
{
private bool _isDragging = false;
private Ellipse _draggedEllipse;
private System.Windows.Point _dragStartPoint;
private IHumanPredictor _humanPredictor;
private IObjectDetector _objectDetector;
private HumanGraphicsRenderer _humanGraphicsRenderer;
private readonly List<SportDescriptor> _sports;
private SportBase _sport;
private readonly SportDetectionQueue _detectQueue;
private WriteableBitmap _videoBitmap;
private int _lastFrameNumber = -1;
public LongSttting()
{
InitializeComponent();
SetupDragEvents();
LoadPointsFromDatabase();
var _webcamClient = WebcamClient.CreateRTSP("172.17.30.64", "admin", "yd708090", 554u);
//处理抽帧回调
_webcamClient.OnExtractFrame += this.OnFrameExtracted;
_webcamClient.StartExtract();//开始抽帧
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
}
private async void OnFrameExtracted(VideoFrame frame)
{
if (frame == null) return;
// 跳帧:每秒只渲染 10~15 帧,降低 CPU 占用
if (_lastFrameNumber != -1 && frame.Number - _lastFrameNumber < 2) return;
_lastFrameNumber = (int)frame.Number;
//获得帧二进制流,保存图像、人体识别竺
var buffer = frame.GetImageBuffer(Yztob.AiSports.Sensors.Things.ImageFormat.Jpeg).ToArray();
//await File.WriteAllBytesAsync($"./temps/{frame.Number}.jpg", buffer);
// === 显示到 WPF ===
BitmapImage bitmap = null;
await Task.Run(() =>
{
using var ms = new MemoryStream(buffer);
bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.StreamSource = ms;
bitmap.EndInit();
bitmap.Freeze(); // 跨线程安全
});
// UI 线程显示
Application.Current.Dispatcher.Invoke(() =>
{
if (videoImage == null) return;
if (_videoBitmap == null ||
_videoBitmap.PixelWidth != bitmap.PixelWidth ||
_videoBitmap.PixelHeight != bitmap.PixelHeight)
{
_videoBitmap = new WriteableBitmap(bitmap.PixelWidth, bitmap.PixelHeight,
96, 96, PixelFormats.Bgra32, null);
videoImage.Source = _videoBitmap;
}
_videoBitmap.Lock();
bitmap.CopyPixels(new Int32Rect(0, 0, bitmap.PixelWidth, bitmap.PixelHeight),
_videoBitmap.BackBuffer,
_videoBitmap.BackBufferStride * bitmap.PixelHeight,
_videoBitmap.BackBufferStride);
_videoBitmap.AddDirtyRect(new Int32Rect(0, 0, bitmap.PixelWidth, bitmap.PixelHeight));
_videoBitmap.Unlock();
});
//var actualPositions = new List<(double X, double Y)>
//{
// (290, 510),
// (500, 700),
// (810, 710),
// (120, 880),
// (350, 880),
// (660, 880)
//};
////判断是否出圈
//if (configService.ConfigDic.TryGetValue("JumpRope", out var obj) && obj is ConfigSet cfg)
//{
// for (int i = 0; i < actualPositions.Count && i < cfg.Points.Count; i++)
// {
// var (ax, ay) = actualPositions[i];
// var pointCfg = cfg.Points[i];
// if (!IsInsideCircle(ax, ay, pointCfg))
// {
// Console.WriteLine($"⚠️ 学生{i + 1} 已经出圈!(坐标 {ax},{ay}");
// }
// else
// {
// Console.WriteLine($"✅ 学生{i + 1} 在圈内。");
// }
// }
//}
//可以进一步进行人体识别等
//var humanResult = await Task.Run(() => _humanPredictor.Predicting(buffer, frame.Number));
//var human = humanResult?.Humans?.FirstOrDefault();
//_detectQueue.Enqueue(frame.Number, human, null);
}
private void SetupDragEvents()
{
// 为所有点添加鼠标事件
var points = new[] { TopPoint1, TopPoint2, TopPoint3, BottomPoint1, BottomPoint2, BottomPoint3 };
foreach (var point in points)
{
point.MouseLeftButtonDown += Point_MouseLeftButtonDown;
point.MouseMove += Point_MouseMove;
point.MouseLeftButtonUp += Point_MouseLeftButtonUp;
point.MouseEnter += Point_MouseEnter;
point.MouseLeave += Point_MouseLeave;
}
}
private async void LoadPointsFromDatabase()
{
try
{
var app = (App)Application.Current;
using var scope = App.AppHost.Services.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
var pointsData = await db.JumpLongPoints.FirstOrDefaultAsync();
if (pointsData != null)
{
// 加载 TopPoint1
var topPoint1 = pointsData.TopPoint1;
Canvas.SetLeft(TopPoint1, topPoint1.X - 10); // 减去半径以居中
Canvas.SetTop(TopPoint1, topPoint1.Y - 10);
// 加载 TopPoint2
var topPoint2 = pointsData.TopPoint2;
Canvas.SetLeft(TopPoint2, topPoint2.X - 10);
Canvas.SetTop(TopPoint2, topPoint2.Y - 10);
// 加载 TopPoint3
var topPoint3 = pointsData.TopPoint3;
Canvas.SetLeft(TopPoint3, topPoint3.X - 10);
Canvas.SetTop(TopPoint3, topPoint3.Y - 10);
// 加载 BottomPoint1
var bottomPoint1 = pointsData.BottomPoint1;
Canvas.SetLeft(BottomPoint1, bottomPoint1.X - 10);
Canvas.SetTop(BottomPoint1, bottomPoint1.Y - 10);
// 加载 BottomPoint2
var bottomPoint2 = pointsData.BottomPoint2;
Canvas.SetLeft(BottomPoint2, bottomPoint2.X - 10);
Canvas.SetTop(BottomPoint2, bottomPoint2.Y - 10);
// 加载 BottomPoint3
var bottomPoint3 = pointsData.BottomPoint3;
Canvas.SetLeft(BottomPoint3, bottomPoint3.X - 10);
Canvas.SetTop(BottomPoint3, bottomPoint3.Y - 10);
UpdateStatus("点数据加载成功");
}
}
catch (Exception ex)
{
UpdateStatus($"加载点数据失败: {ex.Message}");
}
}
//保存点数据到数据库
private void SavePointsToDatabase()
{
try
{
var app = (App)Application.Current;
using var scope = App.AppHost.Services.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
var pointsData = db.JumpLongPoints.FirstOrDefault();
if (pointsData == null)
{
pointsData = new JumpLongPoints { Id = 1 };
db.JumpLongPoints.Add(pointsData);
}
// 保存所有点的位置
pointsData.TopPoint1 = new AiSportsMicrospaceDB.Entities.Point
{
X = Canvas.GetLeft(TopPoint1) + 10,
Y = Canvas.GetTop(TopPoint1) + 10
};
pointsData.TopPoint2 = new AiSportsMicrospaceDB.Entities.Point
{
X = Canvas.GetLeft(TopPoint2) + 10,
Y = Canvas.GetTop(TopPoint2) + 10
};
pointsData.TopPoint3 = new AiSportsMicrospaceDB.Entities.Point
{
X = Canvas.GetLeft(TopPoint3) + 10,
Y = Canvas.GetTop(TopPoint3) + 10
};
pointsData.BottomPoint1 = new AiSportsMicrospaceDB.Entities.Point
{
X = Canvas.GetLeft(BottomPoint1) + 10,
Y = Canvas.GetTop(BottomPoint1) + 10
};
pointsData.BottomPoint2 = new AiSportsMicrospaceDB.Entities.Point
{
X = Canvas.GetLeft(BottomPoint2) + 10,
Y = Canvas.GetTop(BottomPoint2) + 10
};
pointsData.BottomPoint3 = new AiSportsMicrospaceDB.Entities.Point
{
X = Canvas.GetLeft(BottomPoint3) + 10,
Y = Canvas.GetTop(BottomPoint3) + 10
};
db.SaveChanges();
UpdateStatus("点数据保存成功");
}
catch (Exception ex)
{
UpdateStatus($"保存点数据失败: {ex.Message}");
}
}
#region
private void Point_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
_isDragging = true;
_draggedEllipse = sender as Ellipse;
_dragStartPoint = e.GetPosition(MainCanvas);
_draggedEllipse.CaptureMouse();
// 提升点的Z索引使其在拖动时显示在最前面
Canvas.SetZIndex(_draggedEllipse, 100);
}
private void Point_MouseMove(object sender, MouseEventArgs e)
{
if (_isDragging && _draggedEllipse != null)
{
var currentPosition = e.GetPosition(MainCanvas);
// 计算新的位置
double newX = currentPosition.X - 10; // 减去半径
double newY = currentPosition.Y - 10;
// 限制在Canvas范围内
newX = Math.Max(0, Math.Min(newX, MainCanvas.ActualWidth - 20));
newY = Math.Max(0, Math.Min(newY, MainCanvas.ActualHeight - 20));
Canvas.SetLeft(_draggedEllipse, newX);
Canvas.SetTop(_draggedEllipse, newY);
// 更新坐标显示
UpdateCoordinateDisplay(currentPosition, _draggedEllipse.Tag.ToString());
}
}
private void Point_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (_isDragging)
{
_isDragging = false;
_draggedEllipse.ReleaseMouseCapture();
Canvas.SetZIndex(_draggedEllipse, 0); // 恢复Z索引
_draggedEllipse = null;
// 隐藏坐标显示
CoordinateDisplay.Visibility = Visibility.Collapsed;
}
}
private void Point_MouseEnter(object sender, MouseEventArgs e)
{
var ellipse = sender as Ellipse;
ellipse.Opacity = 0.8;
// 显示坐标提示
var position = e.GetPosition(MainCanvas);
UpdateCoordinateDisplay(position, ellipse.Tag.ToString());
}
private void Point_MouseLeave(object sender, MouseEventArgs e)
{
var ellipse = sender as Ellipse;
ellipse.Opacity = 1.0;
if (!_isDragging)
{
CoordinateDisplay.Visibility = Visibility.Collapsed;
}
}
private void UpdateCoordinateDisplay(System.Windows.Point position, string pointName)
{
CoordinateDisplay.Content = $"{pointName}: ({position.X:F0}, {position.Y:F0})";
Canvas.SetLeft(CoordinateDisplay, position.X + 10);
Canvas.SetTop(CoordinateDisplay, position.Y + 10);
CoordinateDisplay.Visibility = Visibility.Visible;
}
#endregion
#region
private void LoadPointsButton_Click(object sender, RoutedEventArgs e)
{
LoadPointsFromDatabase();
}
private void SavePointsButton_Click(object sender, RoutedEventArgs e)
{
SavePointsToDatabase();
}
private void ResetPointsButton_Click(object sender, RoutedEventArgs e)
{
var result = MessageBox.Show("确定要重置为默认点位置吗?", "确认重置",
MessageBoxButton.YesNo, MessageBoxImage.Question);
if (result == MessageBoxResult.Yes)
{
CreateDefaultPoints();
LoadPointsFromDatabase();
UpdateStatus("已重置为默认点位置");
}
}
#endregion
private void UpdateStatus(string message)
{
StatusText.Text = $"{DateTime.Now:HH:mm:ss} - {message}";
}
private async void CreateDefaultPoints()
{
var app = (App)Application.Current;
using var scope = App.AppHost.Services.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
var pointsData = db.JumpLongPoints.FirstOrDefault();
if (pointsData == null)
{
pointsData = new JumpLongPoints { Id = 1 };
db.JumpLongPoints.Add(pointsData);
}
var defaultPoints = new JumpLongPoints
{
Id = 1,
TopPoint1 = new AiSportsMicrospaceDB.Entities.Point { X = 245, Y = 741 },
TopPoint2 = new AiSportsMicrospaceDB.Entities.Point { X = 1498, Y = 730 },
TopPoint3 = new AiSportsMicrospaceDB.Entities.Point { X = 1689, Y = 724 },
BottomPoint1 = new AiSportsMicrospaceDB.Entities.Point { X = 191, Y = 918 },
BottomPoint2 = new AiSportsMicrospaceDB.Entities.Point { X = 1516, Y = 918 },
BottomPoint3 = new AiSportsMicrospaceDB.Entities.Point { X = 1722, Y = 909 },
};
pointsData = defaultPoints;
await db.SaveChangesAsync();
}
}
}