You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用内部Timer重绘GMapMarker实现500ms间隔闪烁效果

解决GMap.NET标记图片可控闪烁的问题

我明白你的痛点——用GMapControl.Invalidate()会重绘整个地图,导致闪烁不受控,而且地图闲置时OnRedraw()还不触发。其实关键是只重绘标记自身的区域,而不是整个地图,同时要处理Timer的线程问题。下面给你一步步解决:

核心思路

  1. 用WinForms的System.Windows.Forms.Timer替代System.Timers.Timer,避免跨线程UI操作的问题(WinForms Timer的Tick事件本身就在UI线程触发)。
  2. 给标记添加一个状态字段(比如控制显示/隐藏或透明度),用来实现闪烁效果。
  3. 在Timer事件中切换状态,然后只刷新标记所在的屏幕区域,而不是整个地图控件。

修改后的完整代码

namespace GMap.NET.WindowsForms.Markers
{
    public class GMarkerNode : GMapMarker
    {
        public Image Image { get; set; }
        private System.Windows.Forms.Timer _flashTimer;
        // 控制闪烁的状态字段,这里用显示/隐藏示例,也可以用透明度
        private bool _isMarkerVisible = true;

        public GMarkerNode(PointLatLng p) : base(p)
        {
            // 使用WinForms Timer,Tick事件在UI线程触发
            _flashTimer = new System.Windows.Forms.Timer()
            {
                Interval = 500,
                Enabled = true
            };
            _flashTimer.Tick += FlashTimer_Tick;
        }

        private void FlashTimer_Tick(object sender, EventArgs e)
        {
            // 切换闪烁状态
            _isMarkerVisible = !_isMarkerVisible;

            // 计算标记在屏幕上的矩形区域
            var markerScreenRect = new Rectangle(
                LocalPosition.X, 
                LocalPosition.Y, 
                Image?.Width ?? 0, 
                Image?.Height ?? 0);

            // 只刷新这个区域,而不是整个地图
            MapControl?.Invalidate(markerScreenRect);
        }

        public override void OnRender(Graphics g)
        {
            if (Image != null && _isMarkerVisible)
            {
                g.DrawImage(Image, LocalPosition);
            }
            // 如果要做透明度闪烁,可以用下面的代码替代上面的判断
            // if (Image != null)
            // {
            //     var alpha = _isMarkerVisible ? 255 : 100;
            //     using (var attr = new ImageAttributes())
            //     {
            //         var matrix = new ColorMatrix();
            //         matrix.Matrix33 = alpha / 255f;
            //         attr.SetColorMatrix(matrix);
            //         g.DrawImage(Image, new Rectangle(LocalPosition, Image.Size), 0, 0, Image.Width, Image.Height, GraphicsUnit.Pixel, attr);
            //     }
            // }
        }

        public override void Dispose()
        {
            _flashTimer?.Stop();
            _flashTimer?.Dispose();
            Image?.Dispose();
            base.Dispose();
        }
    }
}

关键细节解释

  • 为什么用WinForms Timer?:System.Timers.Timer的Elapsed事件是在后台线程触发的,直接操作UI控件会引发跨线程异常,而WinForms Timer的Tick事件天然在UI线程执行,省去了Invoke的麻烦。
  • 只刷新标记区域:通过MapControl.Invalidate(markerScreenRect),只告诉控件重绘标记所在的一小块矩形,不会触发整个地图的OnRedraw(),完美解决地图闲置时的问题,也避免了不必要的性能消耗。
  • 闪烁效果扩展:代码里提供了两种闪烁方式——显示/隐藏,或者透明度变化,你可以根据需求选择。

这样修改后,你的标记就会每500ms稳定闪烁,而且不会影响整个地图的重绘啦!

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:33:46