简体   繁体   English

WPF 与 WinForms Oxyplot 自定义工具提示/跟踪器

[英]WPF vs WinForms Oxyplot Customize Tooltip/Tracker

I am building a WPF application and rendering a chart using OxyPlot.我正在构建一个 WPF 应用程序并使用 OxyPlot 渲染图表。

In order to maximize the performance of the chart, I switched to OxyPlot.WindowsForms and embedded the chart using WindowsFormsHost .为了最大限度地提高图表的性能,我切换到OxyPlot.WindowsForms并使用WindowsFormsHost嵌入图表。 Source: https://oxyplot.userecho.com/de/communities/1/topics/35-wpf-performance资料来源: https://oxyplot.userecho.com/de/communities/1/topics/35-wpf-performance

Zooming is a very important part of the chart I'm rendering, but OxyPlot.WindowsForms seems to not have a great-looking tooltip.缩放是我正在渲染的图表的一个非常重要的部分,但OxyPlot.WindowsForms似乎没有漂亮的工具提示。

WindowsForms:窗体: 在此处输入图像描述

WPF: WPF: 在此处输入图像描述

Is there any way to customize the WindowsForms tooltip to look anything like the WPF one?有什么方法可以自定义 WindowsForms 工具提示,使其看起来像 WPF 那样? The most important things are the vertical and horizontal line of the point.最重要的是点的垂直和水平线。

Looking into the source code of the component, it's not really a tooltip, it's a Label .查看组件的源代码,它并不是真正的工具提示, 而是 Label An option could be getting the private trackingLabel and apply changes on the region of the control (or ideally replace it with a custom label which supports that shape).一个选项可能是获取私有 trackingLabel并在控件区域应用更改(或者理想情况下用支持该形状的自定义 label 替换它)。

Also to draw the crosshair tracker, you can handle Paint event of the plot, and draw the horizontal and vertical line based on the center of label.同样绘制十字线跟踪器,可以处理plot的Paint事件,以label为中心绘制横竖线。

well, what I mentioned above is just a quick workaround which results in the following:好吧,我上面提到的只是一个快速解决方法,结果如下:

在此处输入图像描述

Using the following code:使用以下代码:

private Label trackerLabel;
private void Form1_Load(object sender, EventArgs e)
{
    var trackerLabelField = plotView1.GetType().GetField("trackerLabel",
        System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
    trackerLabel = new BalloonLabel()
    {
        Visible = false,
        Parent = plotView1
    };
    trackerLabelField.SetValue(plotView1, trackerLabel);

    var myModel = new PlotModel { Title = "Example 1" };
    myModel.Series.Add(new FunctionSeries(Math.Cos, 0, 10, 0.1, "cos(x)"));
    this.plotView1.Model = myModel;
    this.plotView1.Paint += PlotView1_Paint;
    trackerLabel.VisibleChanged += TrackerLabel_VisibleChanged;
}
private void TrackerLabel_VisibleChanged(object sender, EventArgs e)
{
    plotView1.Invalidate();
}
private void PlotView1_Paint(object sender, PaintEventArgs e)
{
    if (trackerLabel.Visible)
    {
        var r = plotView1.Model.PlotArea;
        e.Graphics.DrawLine(Pens.Blue, trackerLabel.Left + trackerLabel.Width / 2, (int)r.Top,
            trackerLabel.Left + trackerLabel.Width / 2, (int)r.Bottom);
        e.Graphics.DrawLine(Pens.Blue, (int)r.Left, trackerLabel.Bottom, (int)r.Right, trackerLabel.Bottom);
    }
}

And this balloon label, which I assume is a good-enough start point:这个气球 label,我认为这是一个足够好的起点:

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
public class BalloonLabel : Label
{
    public BalloonLabel()
    {
        BackColor = SystemColors.Info;
        Padding = new Padding(5, 5, 5, 20);
        ArrowSize = new Size(10, 20);
        AutoSize = true;
    }
    private Size arrowSize;
    public Size ArrowSize
    {
        get { return arrowSize; }
        set
        {
            arrowSize = value;
            this.RecreateRegion();
        }
    }

    private GraphicsPath GetBalloon(Rectangle bounds)
    {
        GraphicsPath path = new GraphicsPath();
        path.StartFigure();

        if (arrowSize.Width > 0 && arrowSize.Height > 0)
        {
            path.AddLine(bounds.Left, bounds.Bottom - arrowSize.Height / 2, bounds.Left, bounds.Top);
            path.AddLine(bounds.Left, bounds.Top, bounds.Right, bounds.Top);
            path.AddLine(bounds.Right, bounds.Top, bounds.Right, bounds.Bottom - arrowSize.Height / 2);
            path.AddLine(bounds.Right, bounds.Bottom - arrowSize.Height / 2, bounds.Left + bounds.Width / 2 + arrowSize.Width / 2, bounds.Bottom - arrowSize.Height / 2);
            path.AddLine(bounds.Left + bounds.Width / 2 + arrowSize.Width / 2, bounds.Bottom - arrowSize.Height / 2,
                bounds.Left + bounds.Width / 2, bounds.Bottom);
            path.AddLine(bounds.Left + bounds.Width / 2, bounds.Bottom,
                bounds.Left + bounds.Width / 2 - arrowSize.Width / 2, bounds.Bottom - arrowSize.Height / 2);
            path.AddLine(bounds.Left + bounds.Width / 2 - arrowSize.Width / 2, bounds.Bottom - arrowSize.Height / 2,
                bounds.Left, bounds.Bottom - arrowSize.Height / 2);
        }
        else
        {
            path.AddLine(bounds.Left, bounds.Bottom, bounds.Left, bounds.Top);
            path.AddLine(bounds.Left, bounds.Top, bounds.Right, bounds.Top);
            path.AddLine(bounds.Right, bounds.Top, bounds.Right, bounds.Bottom);
            path.AddLine(bounds.Right, bounds.Bottom, bounds.Left, bounds.Bottom);
        }
        path.CloseFigure();
        return path;
    }

    private void RecreateRegion()
    {
        var r = ClientRectangle;
        using (var path = GetBalloon(r))
            this.Region = new Region(path);
        this.Invalidate();
    }
    protected override void OnSizeChanged(EventArgs e)
    {
        base.OnSizeChanged(e);
        this.RecreateRegion();
    }
    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        var r = ClientRectangle;
        r.Inflate(-1, -1);
        using (var path = GetBalloon(r))
        {
            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
            using (var pen = new Pen(Color.Gray, 1) { Alignment = PenAlignment.Inset })
                e.Graphics.DrawPath(pen, path);
            if (Parent != null)
                Parent.Invalidate();
        }
    }
}

And here is the animated result:这是动画结果:

在此处输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM