【问题标题】:To create a zoom picturebox for mschart为 mschart 创建缩放图片框
【发布时间】:2018-11-26 06:02:39
【问题描述】:

我想在PictureBox Zoom 中为 mschart 创建一个缩放图片框。当我将鼠标悬停在图表上时,图片框应显示缩放视图,以便我可以选择合适的点。这可以在 winforms C#.net 中发生吗?

【问题讨论】:

  • 是的,mschart 很好地支持缩放和鼠标事件。展示你的尝试!就目前而言,这个问题太宽泛了,没有显示任何研究工作。请注意,我将使用两个图表控件,没有 pbox。
  • @TaW 这意味着我必须使用另一个图表控件而不是图片框。如果是这样,我将开始努力。
  • 是的,这似乎是最直接的方法。否则,您必须将 pbox 中的鼠标位置转换为图表像素,然后将这些位置转换为点。然后创建一个放大的图像来显示。或者从大图像开始并更改缩​​放。也可行,但涉及更多..
  • 重新思考这个问题后,我想知道:您的意思是要将鼠标移到图表上还是放大区域上?对于前者,也许一个 pbox 确实可以..
  • 如果您对此感到满意,您可能需要考虑发布您的解决方案;我肯定会投赞成票。我已经发布了原始想法的解决方案。请注意,imo 选择 DataPoints 的最佳帮助是用命中测试和放大标记指示点。可能可以与任一解决方案结合使用的位..

标签: c# .net picturebox mschart


【解决方案1】:

这是一个满足操作要求的解决方案:创建一个PictureBox,显示Chart放大部分,该部分将随着图表的移动而移动。

看起来不错,但仍然需要穿过那些微小的未缩放像素..

这是如何完成和设置的:

必要时必须重新设置PictureBox zoomPBox;设置它需要进行一些测量并创建Chart 的屏幕截图。为此,图表暂时放大,然后重置为原始大小。

注意:每当图表调整大小或以任何其他方式更改时,必须再次调用设置例程。

PictureBox zoomPBox 设置为 SizeMode Normal,并嵌套Panel 中。在设置中,我们放大zoomPBox 以容纳整个BitmapPanel zoomPanelAutoScroll = false 以避免滚动条。

一个复杂性是图表控件的自动调整大小。放大时,内容会放大,但例如没有任何字体。这会导致正常和缩放绘图区域之间的不同的纵横比。为了保持运动同步,我们不能这样做。因此,我们不仅要从放大的屏幕截图中切出没有LegendTitleAxes的实际内部绘图区域,还要将其拉伸到相同的位置纵横比作为未缩放的绘图区域..

结果如下:

MouseMove 的代码就没有这么复杂了..:

private void chart_MouseMove(object sender, MouseEventArgs e)
{
    if (zoomPBox.Image == null) return;

    Rectangle ri = Rectangle.Round(
                    InnerPlotPositionClientRectangle(chart, chart.ChartAreas[0]));

    Size szi = zoomPBox.Image.Size;
    Size szp = zoomPanel.ClientSize;
    Point cp = new Point( e.X - ri.X ,  e.Y - ri.Y );
    float zx = 1f * szi.Width / ri.Width;
    float zy = 1f * szi.Height / ri.Height;  // should be the same
    int x = round( szp.Width / 2 - cp.X * zx );
    int y = round( szp.Height / 2 - cp.Y * zy );
    zoomPBox.Location = new Point(x, y);     // now we move the pBox into position
    zoomPBox.Invalidate();
}

如你所见,我 Invalidate PictureBox;即允许它在自身上绘制十字线以便更好地控制;这是Paint 事件:

private void zoomPBox_Paint(object sender, PaintEventArgs e)
{
    Size sz = zoomPanel.ClientSize;
    int x = sz.Width / 2 - zoomPBox.Left;
    int y = sz.Height / 2 - zoomPBox.Top;
    e.Graphics.DrawLine(Pens.LightGray, 0, y, zoomPBox.Width, y);
    e.Graphics.DrawLine(Pens.LightGray, x, 0, x, zoomPBox.Height);
}

现在开始设置例程:

    void setupZoomBox(Chart chart, PictureBox pbox, float zoom)
    {
        ChartArea ca = chart.ChartAreas[0];
        Size sz = chart.ClientSize;
        Size szi = new Size(round(sz.Width * zoom), round(sz.Height * zoom));
        Bitmap bmp2 = null;
        chart.Refresh();

        // original plot area
        Rectangle pao = Rectangle.Round(InnerPlotPositionClientRectangle(chart, ca));
        float ro = 1f * (pao.Width+2) / (pao.Height+2);  // original aspect ratio

        chart.ClientSize = szi;
        chart.Refresh();  // enforce immediate layout
        // zoomed plot area
        Rectangle paz = Rectangle.Round(InnerPlotPositionClientRectangle(chart, ca));
        float rz = 1f * paz.Width / paz.Height;   // zoomed aspect ratio

        // target rectangle, same aspect ratio as unzoomed  area
        int th = paz.Height;
        int tw = round(paz.Height * ro );
        // if (ro > rz)
            //tw = round(th * ro); //else th = round(tw / ro);
        Rectangle tgtR = new Rectangle(0, 0, tw, th);

        // bitmap to hold only the zoomed inner plot area
        bmp2 = new Bitmap(tgtR.Width, tgtR.Height);

        // source area: Only the inner plot area plus 1 line of axis pixels:
        Rectangle srcR = Rectangle.Round(
                           new RectangleF(paz.X - 1, paz.Y - 1, paz.Width + 2, paz.Height + 2));

        // bitmap to hold the whole zoomed chart:
        using (Bitmap bmp = new Bitmap(szi.Width, szi.Height))
        {
            Rectangle drawR = new Rectangle(0, 0, szi.Width, szi.Height);
            chart.DrawToBitmap(bmp, drawR);  // screenshot
            using (Graphics g = Graphics.FromImage(bmp2))  // crop stretched
                 g.DrawImage(bmp, tgtR, srcR, GraphicsUnit.Pixel);
        }
        chart.ClientSize = sz;  // reset chart
        // you should dispose of the old Image if there is one before setting the new one!!
        pbox.Image = bmp2;    
        pbox.ClientSize = bmp2.Size;
    }

在某些地方,我需要获取所谓的InnerPlotPosition 的像素大小; (ElementPosition 中的 MSChart 包括 LocationSize 在相应容器区域的百分比中。)我使用我之前发布的功能,例如here.

【讨论】:

    【解决方案2】:

    另一种解决方案是使用图表控件作为缩放视图。当鼠标移到原始图表上时,您可以查看标记为红色的数据点。如下所示:

    代码如下:

    private void chart1_MouseMove(object sender, MouseEventArgs e)
        {
            Point mousePoint = new Point(e.X, e.Y);
            double mouse_Xvalue = chart1.ChartAreas[0].AxisX.PixelPositionToValue(e.X);
            double mouse_Yvalue = chart1.ChartAreas[0].AxisY.PixelPositionToValue(e.Y);
    
            DataPoint Prev_DataPoint = chart1.Series[0].Points.Select(x => x)
                                            .Where(x => x.XValue >= mouse_Xvalue)
                                            .DefaultIfEmpty(chart1.Series[0].Points.First()).First();
    
            DataPoint Next_DataPoint = chart1.Series[0].Points.Select(x => x)
                                  .Where(x => x.XValue <= mouse_Xvalue)
                                   .DefaultIfEmpty(chart1.Series[0].Points.Last()).Last();
    
            double diff_prev = Math.Abs(Prev_DataPoint.XValue - mouse_Xvalue);
            double diff_next = Math.Abs(Next_DataPoint.XValue - mouse_Xvalue);
    
            int zoffset = 15;
            int setindexX = diff_prev < diff_next ?
                              chart1.Series[0].Points.IndexOf(Prev_DataPoint)
                            : chart1.Series[0].Points.IndexOf(Next_DataPoint);
    
            int setXmin = (setindexX - zoffset) >= 0 ? (setindexX - zoffset)
                            : 0;
            int setXmax = (setindexX + zoffset) < chart1.Series[0].Points.Count
                          ? (setindexX + zoffset)
                            : chart1.Series[0].Points.Count - 1;
    
            if (zoomchart.Series.Count > 0)
                zoomchart.Series.Clear();
    
            Series series = new Series();
            Series series2 = new Series();
            series.Points.Clear();
            series2.Points.Clear();
    
            for (int i = setXmin; i <= setXmax; i++)
                series.Points.AddXY(chart1.Series[0].Points[i].XValue,
                                    chart1.Series[0].Points[i].YValues[0]);
            series.Color = chart1.Series[0].Color;
            series.ChartType = SeriesChartType.Line;
    
            series2.Points.AddXY(chart1.Series[0].Points[setindexX].XValue,
                                 chart1.Series[0].Points[setindexX].YValues[0]);
            series2.Color = Color.Red;
            series2.ChartType = SeriesChartType.Point;
            series2.Points[0].Label = series2.Points[0].XValue.ToString("F2") + ", "
                                    + series2.Points[0].YValues[0].ToString("F2");
    
    
            zoomchart.Series.Add(series);
            zoomchart.Series.Add(series2);
            zoomchart.Invalidate();
    
            zoomchart.ChartAreas[0].AxisX.Minimum = series.Points[0].XValue;
            zoomchart.ChartAreas[0].AxisX.Maximum = series.Points.FindMaxByValue("X").XValue;
            zoomchart.ChartAreas[0].AxisY.Minimum = series.Points.FindMinByValue().YValues[0];
            zoomchart.ChartAreas[0].AxisY.Maximum = series.Points.FindMaxByValue().YValues[0];
    
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-07-14
      • 1970-01-01
      • 2013-08-12
      • 1970-01-01
      • 2012-09-20
      • 1970-01-01
      • 1970-01-01
      • 2013-10-21
      相关资源
      最近更新 更多