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

WinForms多折线图跨图垂直线与数值显示实现方法问询

我之前做过类似的WinForms图表需求,用自带的Chart控件就能完美实现这个贯穿所有折线图的垂直线+数值显示功能,下面是一步步的实操方案,亲测好用:

实现步骤

1. 基础准备(窗体与Chart控件)

  • 先在窗体上拖放4个Chart控件(可以命名为chart1chart2chart3chart4),务必确保它们的X轴刻度范围完全一致——比如都设置固定的MinimumMaximum,或者后续动态同步,这样垂直线才能精准对齐所有图表。
  • 给每个Chart添加至少一个折线类型的Series,并绑定好你的业务数据。

2. 定义全局状态变量

在窗体类里声明几个变量,用来跟踪鼠标交互状态和当前的X轴位置:

// 标记是否需要显示垂直线
private bool _showVerticalLine = false;
// 当前鼠标对应的X轴数值
private double _currentXValue = 0;
// 用来显示数值提示的ToolTip
private ToolTip _chartToolTip = new ToolTip();

3. 批量绑定控件事件

为了避免重复代码,我们可以在窗体的Load事件里批量给所有Chart绑定鼠标和绘制事件:

private void Form1_Load(object sender, EventArgs e)
{
    // 把所有Chart放到一个集合里统一处理
    var allCharts = new List<Chart> { chart1, chart2, chart3, chart4 };
    
    foreach (var chart in allCharts)
    {
        chart.MouseMove += Chart_MouseMove;
        chart.MouseLeave += Chart_MouseLeave;
        chart.Paint += Chart_Paint;
    }
}

4. 处理鼠标交互逻辑

当鼠标在任意Chart上移动时,我们要把屏幕坐标转换为Chart的X轴数值,然后标记需要显示垂直线;鼠标离开时则关闭显示:

private void Chart_MouseMove(object sender, MouseEventArgs e)
{
    var currentChart = sender as Chart;
    if (currentChart == null || currentChart.Series.Count == 0) return;

    var chartArea = currentChart.ChartAreas[0];
    // 将鼠标的X像素坐标转换为Chart的X轴数值
    _currentXValue = chartArea.AxisX.PixelPositionToValue(e.X);
    _showVerticalLine = true;

    // 清空之前的提示,显示当前Chart的数值
    _chartToolTip.RemoveAll();
    ShowCurrentChartValues(currentChart, e.Location);

    // 强制所有Chart重绘,更新垂直线位置
    foreach (var chart in new List<Chart> { chart1, chart2, chart3, chart4 })
    {
        chart.Invalidate();
    }
}

private void Chart_MouseLeave(object sender, EventArgs e)
{
    _showVerticalLine = false;
    _chartToolTip.RemoveAll();
    // 重绘所有Chart以隐藏垂直线
    foreach (var chart in new List<Chart> { chart1, chart2, chart3, chart4 })
    {
        chart.Invalidate();
    }
}

5. 绘制贯穿所有Chart的垂直线

在每个Chart的Paint事件里,根据全局的_currentXValue绘制一条贯穿整个图表区域的垂直线:

private void Chart_Paint(object sender, PaintEventArgs e)
{
    var chart = sender as Chart;
    if (!_showVerticalLine || chart == null || chart.ChartAreas.Count == 0) return;

    var chartArea = chart.ChartAreas[0];
    // 将X轴数值转换为当前Chart的像素位置
    int xPixelPosition = (int)chartArea.AxisX.ValueToPixelPosition(_currentXValue);

    // 绘制红色垂直线(可以自定义颜色、粗细)
    using (var linePen = new Pen(Color.Red, 1))
    {
        // 获取ChartArea的实际显示区域(相对于Chart控件)
        var areaRect = chartArea.Position.ToRectangleF(chart.ClientRectangle);
        e.Graphics.DrawLine(linePen, xPixelPosition, areaRect.Top, xPixelPosition, areaRect.Bottom);
    }
}

6. 获取并显示当前数值

写一个辅助方法,找到当前X值对应的最接近数据点,并用ToolTip显示数值:

private void ShowCurrentChartValues(Chart chart, Point mousePos)
{
    var chartArea = chart.ChartAreas[0];
    double targetX = _currentXValue;

    foreach (var series in chart.Series)
    {
        // 找到距离当前X值最近的数据点
        DataPoint closestPoint = null;
        double minDistance = double.MaxValue;
        foreach (var point in series.Points)
        {
            double distance = Math.Abs(point.XValue - targetX);
            if (distance < minDistance)
            {
                minDistance = distance;
                closestPoint = point;
            }
        }

        if (closestPoint != null)
        {
            // 格式化提示文本,也可以用Label集中显示所有图表的数值
            string tipContent = $"系列: {series.Name}\nX: {targetX:F2}\nY: {closestPoint.YValues[0]:F2}";
            _chartToolTip.Show(tipContent, chart, mousePos.X + 10, mousePos.Y + 10);
        }
    }
}

额外优化建议

  • X轴同步:如果你的数据是动态更新的,记得在数据更新后同步所有Chart的X轴MinimumMaximum,确保垂直线始终对齐。
  • 数值精度:如果需要更精准的Y值,可以用线性插值计算当前X值对应的Y值,而不是直接取最近的点。
  • 自定义样式:可以把垂直线的颜色、粗细做成可配置的,甚至支持用户切换显示状态。
  • 集中显示:如果觉得每个Chart单独显示ToolTip太乱,可以在窗体上放一个Label,把所有4个Chart的当前数值汇总显示在里面。

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

火山引擎 最新活动