我可以在面板上显示正在绘制的节点的工具提示吗?

Can I show ToolTip for the nodes I am painting on a panel?(我可以在面板上显示正在绘制的节点的工具提示吗?)
本文介绍了我可以在面板上显示正在绘制的节点的工具提示吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个用于MMO的网状系统,它使用A*来查找路径。偶尔它会失败,因为我有放置不当的节点。为了解决这个问题,我制作了一个网格可视化工具。它工作得很好-我可以看到一些节点放置得不好。但我看不到哪些节点。

以下是显示节点的代码:

    foreach (var node in FormMap.Nodes)
    {

        var x1 = (node.Point.X * sideX);
        var y1 = (node.Point.Y * sideY);

        var x = x1 - nodeWidth / 2;
        var y = y1 - nodeWidth / 2;

        var brs = Brushes.Black;
        //if (node.Visited)
        //    brs = Brushes.Red;
        if (node == FormMap.StartNode)
            brs = Brushes.DarkOrange;
        if (node == FormMap.EndNode)
            brs = Brushes.Green;
        g.FillEllipse(brs, (float)x, (float)y, nodeWidth, nodeWidth);

我知道我可以重做,制作数千个小按钮并为它们添加事件,但这似乎有点过头了。

是否可以将工具提示添加到我在面板上绘制的节点?

推荐答案

可以,您可以显示已在绘图图面上绘制的节点的工具提示。为此,您需要执行以下操作:

  • 对您的节点进行命中测试,这样就可以将节点放在鼠标位置下。
  • 创建一个定时器,在绘图图面的鼠标移动事件处理程序中,进行命中测试,找到热项。如果热节点与当前热节点不同,则停止计时器,否则,如果有新的热项目,则启动计时器。
  • 在Timer Tick事件处理程序中,检查是否有热项,显示工具提示并停止计时。
  • 在绘图图面的鼠标离开事件中,停止计时器。

以下是结果,其中显示了图形中某些点的工具提示:

上述算法,正在used in internal logic of ToolStrip control显示工具条项目(不受控制)的工具提示。因此,在不浪费大量窗口句柄和使用单个父控件和单个工具提示的情况下,您可以显示任意多个节点的工具提示。

代码示例-显示图形中某些点的工具提示

以下是绘图图面:

using System.ComponentModel;
using System.Drawing.Drawing2D;
public class DrawingSurface : Control
{
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    [Browsable(false)]
    public List<Node> Nodes { get; }
    public DrawingSurface()
    {
        Nodes = new List<Node>();
        ResizeRedraw = true;
        DoubleBuffered = true;
        toolTip = new ToolTip();
        mouseHoverTimer = new System.Windows.Forms.Timer();
        mouseHoverTimer.Enabled = false;
        mouseHoverTimer.Interval = SystemInformation.MouseHoverTime;
        mouseHoverTimer.Tick += mouseHoverTimer_Tick;
    }
    private void mouseHoverTimer_Tick(object sender, EventArgs e)
    {
        mouseHoverTimer.Enabled = false;
        if (hotNode != null)
        {
            var p = hotNode.Location;
            p.Offset(16, 16);
            toolTip.Show(hotNode.Name, this, p, 2000);
        }
    }

    private System.Windows.Forms.Timer mouseHoverTimer;
    private ToolTip toolTip;
    Node hotNode;
    protected override void OnMouseMove(MouseEventArgs e)
    {
        base.OnMouseMove(e);
        var node = Nodes.Where(x => x.HitTest(e.Location)).FirstOrDefault();
        if (node != hotNode)
        {
            mouseHoverTimer.Enabled = false;
            toolTip.Hide(this);
        }
        hotNode = node;
        if (node != null)
            mouseHoverTimer.Enabled = true;
        Invalidate();
    }
    protected override void OnMouseLeave(EventArgs e)
    {
        base.OnMouseLeave(e);
        hotNode = null;
        mouseHoverTimer.Enabled = false;
        Invalidate();
    }
    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
        if (Nodes.Count >= 2)
            e.Graphics.DrawLines(Pens.Black,
            Nodes.Select(x => x.Location).ToArray());
        foreach (var node in Nodes)
            node.Draw(e.Graphics, node == hotNode);
    }
    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (mouseHoverTimer != null)
            {
                mouseHoverTimer.Enabled = false;
                mouseHoverTimer.Dispose();
            }
            if (toolTip != null)
            {
                toolTip.Dispose();
            }
        }
        base.Dispose(disposing);
    }
}

以下是节点类:

using System.Drawing.Drawing2D;
public class Node
{
    int NodeWidth = 16;
    Color NodeColor = Color.Blue;
    Color HotColor = Color.Red;
    public string Name { get; set; }
    public Point Location { get; set; }
    private GraphicsPath GetShape()
    {
        GraphicsPath shape = new GraphicsPath();
        shape.AddEllipse(Location.X - NodeWidth / 2, Location.Y - NodeWidth / 2,
            NodeWidth, NodeWidth);
        return shape;
    }
    public void Draw(Graphics g, bool isHot = false)
    {
        using (var brush = new SolidBrush(isHot ? HotColor : NodeColor))
        using (var shape = GetShape())
        {
            g.FillPath(brush, shape);
        }
    }
    public bool HitTest(Point p)
    {
        using (var shape = GetShape())
            return shape.IsVisible(p);
    }
}

下面是示例窗体,上面有一个绘图图面控件:

protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);
    drawingSurface1.Nodes.Add(new Node() { 
        Name = "Node1", Location = new Point(100, 100) });
    drawingSurface1.Nodes.Add(new Node() { 
        Name = "Node2", Location = new Point(150, 70) });
    drawingSurface1.Nodes.Add(new Node() { 
        Name = "Node3", Location = new Point(170, 140) });
    drawingSurface1.Nodes.Add(new Node() { 
        Name = "Node4", Location = new Point(200, 50) });
    drawingSurface1.Nodes.Add(new Node() { 
        Name = "Node5", Location = new Point(90, 160) });
    drawingSurface1.Invalidate();
}

这篇关于我可以在面板上显示正在绘制的节点的工具提示吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

DispatcherQueue null when trying to update Ui property in ViewModel(尝试更新ViewModel中的Ui属性时DispatcherQueue为空)
Drawing over all windows on multiple monitors(在多个监视器上绘制所有窗口)
Programmatically show the desktop(以编程方式显示桌面)
c# Generic Setlt;Tgt; implementation to access objects by type(按类型访问对象的C#泛型集实现)
InvalidOperationException When using Context Injection in ASP.Net Core(在ASP.NET核心中使用上下文注入时发生InvalidOperationException)
LINQ many-to-many relationship, how to write a correct WHERE clause?(LINQ多对多关系,如何写一个正确的WHERE子句?)