You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

C# WinForms实现随视频同步移动的动态红点(坐标点控制)

嘿,我来帮你搞定这个同步红点的问题!你的思路完全正确——用时间节点绑定地图坐标,跟着视频进度移动红点,下面是一步步的实现方法,都是WinForms里的基础操作,你跟着来就行:

第一步:定义路径点的数据结构

先创建一个简单的类,用来存储每个视频时间点对应的地图坐标:

public class PathPoint
{
    // 视频播放到该点的时间(单位:秒)
    public double TimeInSeconds { get; set; }
    // 该时间点红点在PictureBox上的坐标
    public Point Position { get; set; }
}

然后把你路径的关键节点列出来,比如从主入口到各个目的地的必经点:

// 全局变量,存整个路径的所有节点
private List<PathPoint> _pathPoints = new List<PathPoint>
{
    new PathPoint { TimeInSeconds = 0, Position = new Point(174, 123) }, // 起点(主入口)
    new PathPoint { TimeInSeconds = 5, Position = new Point(200, 123) }, // 走廊第一个拐角
    new PathPoint { TimeInSeconds = 10, Position = new Point(200, 180) }, // 楼梯口
    // 继续添加你的所有关键节点...
};
第二步:准备视频控件和全局变量

假设你用的是WinForms常用的AxWindowsMediaPlayer控件(直接在工具箱里拖就行),命名为videoPlayer。然后添加几个全局变量:

// 当前红点的位置
private Point _currentRedDotPosition;
// 定时更新红点的计时器
private Timer _positionUpdateTimer;
// 全局画笔(避免重复创建浪费资源)
private Pen _redPen = new Pen(Color.Red, 3);

在窗体的Load事件里初始化计时器:

private void Form1_Load(object sender, EventArgs e)
{
    // 每隔50毫秒更新一次红点(间隔可以根据流畅度调整)
    _positionUpdateTimer = new Timer();
    _positionUpdateTimer.Interval = 50;
    _positionUpdateTimer.Tick += PositionUpdateTimer_Tick;
    // 初始位置设为路径起点
    _currentRedDotPosition = _pathPoints.First().Position;
}
第三步:实现红点的位置计算

在计时器的Tick事件里,根据视频当前播放时间计算红点应该在的位置,还做了平滑插值处理,避免红点跳着走:

private void PositionUpdateTimer_Tick(object sender, EventArgs e)
{
    // 获取视频当前播放的时间(单位:秒)
    double currentVideoTime = videoPlayer.Ctlcontrols.currentPosition;

    // 找到当前时间对应的前后两个路径节点
    var previousPoint = _pathPoints.LastOrDefault(p => p.TimeInSeconds <= currentVideoTime);
    var nextPoint = _pathPoints.FirstOrDefault(p => p.TimeInSeconds >= currentVideoTime);

    if (previousPoint == null || nextPoint == null)
    {
        // 超出路径范围时停在最后一个节点
        _currentRedDotPosition = _pathPoints.Last().Position;
    }
    else if (previousPoint == nextPoint)
    {
        // 刚好卡在某个节点上,直接用该节点坐标
        _currentRedDotPosition = previousPoint.Position;
    }
    else
    {
        // 线性插值计算中间位置,让红点平滑移动
        double timeRatio = (currentVideoTime - previousPoint.TimeInSeconds) / (nextPoint.TimeInSeconds - previousPoint.TimeInSeconds);
        int x = (int)(previousPoint.Position.X + (nextPoint.Position.X - previousPoint.Position.X) * timeRatio);
        int y = (int)(previousPoint.Position.Y + (nextPoint.Position.Y - previousPoint.Position.Y) * timeRatio);
        _currentRedDotPosition = new Point(x, y);
    }

    // 触发PictureBox重绘,更新红点位置
    Planos.Invalidate();
}
第四步:修改Paint事件绘制红点

把你原来硬编码的Paint事件改成使用全局变量的位置:

private void Planos_Paint_1(object sender, PaintEventArgs e)
{
    // 直接绘制当前计算好的红点位置
    e.Graphics.DrawEllipse(_redPen, _currentRedDotPosition.X, _currentRedDotPosition.Y, 3, 3);
}
第五步:同步视频的播放状态

要处理暂停、快进、快退这些操作,得监听视频的播放状态变化:

private void videoPlayer_PlayStateChange(object sender, AxWMPLib._WMPOCXEvents_PlayStateChangeEvent e)
{
    switch (e.newState)
    {
        case 3: // 视频播放中
            _positionUpdateTimer.Start();
            break;
        case 2: // 视频暂停
        case 1: // 视频停止
            _positionUpdateTimer.Stop();
            // 暂停时强制更新一次红点,确保位置准确
            Planos.Invalidate();
            break;
        // 快进快退时,视频当前时间会直接变化,计时器运行中会自动计算新位置,不用额外处理
    }
}

记得在窗体设计器里给videoPlayerPlayStateChange事件绑定这个方法哦!

额外小技巧
  • 坐标点获取:你可以给PictureBox加个MouseClick事件,点击地图上的点时输出e.Location的X和Y,这样就能精准记录每个关键节点的坐标,比硬编码靠谱多了。
  • 资源释放:在窗体的FormClosing事件里释放画笔和计时器,避免内存泄漏:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
    _redPen.Dispose();
    _positionUpdateTimer.Dispose();
}

内容的提问来源于stack exchange,提问作者laumrz

火山引擎 最新活动