65.9K
CodeProject 正在变化。 阅读更多。
Home

在 GDI+ 中绘制折线图

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.86/5 (10投票s)

2011年4月9日

CPOL

4分钟阅读

viewsIcon

78890

downloadIcon

4135

在笛卡尔坐标系中绘制折线图(VB.NET 和 GDI+)

引言

几年前,我使用了 Felix Haas 的 VB 6.0 项目的示例代码,名为《无需 ActiveX / OCX 控件的快速图表》。他在其中提出了一种相对简单但有效的方法,使用 GDI 构建带有网格线的笛卡尔坐标系。

当我在 VB 6.0 中需要绘制基于手动输入值、从数据库查询的数据或实时数据的折线图时,我将此代码用作模板。在 VB.NET 和 GDI+ 引入后,与图形相关的代码发生了巨大变化。

此示例代码是初始 VB 6.0 代码对 GDI+ 类的改编,并升级到 VB 2010。

背景

Windows GDI/GDI+ 使用镜像的笛卡尔坐标系第一象限,原点 (0,0) 位于左上角,而不是笛卡尔模型中的左下角原点。Windows 坐标以这种方式绘制的原因来自初始的 GDI 映射模式(控制逻辑坐标如何转换为设备坐标的设备上下文的属性)。
摘自 Jeff Prosise 著的《使用 MFC 编程 Windows》,O Reilly, 1999 年,章节《Windows GDI》:

在 GDI 中,当您使用 MM_TEXT 映射模式绘图时,您使用的是坐标系统,其中原点位于窗口的左上角,正 x 轴指向右侧,正 y 轴指向下方,并且 1 个单位等于 1 个像素。您切换到其中一种“公制”映射模式 - MM_LOENGLISH, MM_HIENGLISH, MM_LOMETRIC, MM_HIMETRIC 或 MM_TWIPS - y 轴翻转,使得正 y 指向上方,并且逻辑单位被缩放以表示真实距离,而不是原始像素计数

 

我们绘制在屏幕上的文本从左上角开始,行数递增。
而默认的 GDI 映射模式是 MM_TEXT,这对于图像绘制来说有点令人困惑。
在 Visual Studio、C++ 和 GDI 中,您可以应用公制映射模式或用户定义的映射模式来获得图表功能。

在 VB 6.0 和 GDI 中,您可以使用方法 ScaleLine 以及属性 AutoRedrawCurrentXCurrentY 来构建坐标并绘制图表。
在 VB.NET 和 GDI+ 中,您必须使用转换(TranslateScale 等)才能获得类似的结果。

Using the Code

该项目由两个模块组成:frmChart.vb(带有绘图过程的主窗体)和 modSettings.vb(图表的初始设置、转换函数和 public 变量)。在 Visual Basic 6 中,默认的图形单位是 twips(因此初始项目是基于它们的)。

在 VB.NET 中,它们被像素取代,为了升级,我们使用 VB.NET 中可用的 points 单位,因为它更容易重新计算。为了在窗体重绘时重绘图形对象(在 VB 6.0 中使用 AutoRedraw 完成),使用了 Form.Paint 事件。

在 VB 6.0 中,我们可以使用 Scale 方法来镜像第二象限,并将原点设置为左下角。在 VB.NET 中,此图形方法被删除,我们必须使用转换来获得类似的图表功能。

来自 MSDN 转换概述

转换定义了如何将点从一个坐标空间映射或转换为另一个坐标空间。
此映射由一个转换矩阵描述,该矩阵是一个包含三行三列 Double 值的集合
.

这是相应的代码

Dim graphicsObj As Graphics = eventArg.Graphics

'For this simple chart we actually don't need a Matrix object, 
'but I left here as it can be needed for more complex tasks:
Dim chartMatrix As New Drawing2D.Matrix()
graphicsObj.Transform = chartMatrix

请注意,我们只是在此代码中定义了图形对象,而没有对标签(在本例中为数字)进行转换,以便它们能够正确绘制。

'Draw labels and markers at X-axis:
For I = Xmin To Xmax 
    graphicsObj.DrawString(Trim(Str(I)), drawFont, drawBrush, _
    XinPoints(I) - 2 * Len(Trim(Str(I))), YinPoints(0) + 100)
Next

'Draw labels and markers at Y-axis:
For I = Ymin To Ymax ' Y-Axis
    graphicsObj.DrawString(Trim(Str(-scaleFactorY * I + Ymax + Ymin)), _
    drawFont, drawBrush, XinPoints(scaleFactorX) - 10 - _
    2 * Len(Trim(Str(scaleFactorY * I))), YinPoints(scaleFactorY * I) - 12)
Next

现在,我们可以将转换应用于图形对象

'Move the origin to the bottom left corner 
'(position it inside Picture Box = Picture Height + border from the top).
graphicsObj.TranslateTransform(0.0F, PictureHeight + 20)

graphicsObj.ScaleTransform(1, -1) 	' Scales an element by the specified 
				' ScaleX and ScaleY amounts
             			' multiplying the transformation matrix 
				' by a diagonal matrix whose elements are (1,-1)

现在,我们使用 graphicsObj.DrawLine 方法构建带有网格线的坐标(这里仅用于 X 轴)。

'Construct X-axis and Y-axis:
'X axis:
' use DrawLine(Pen, Single, Single, Single, Single) 
' Draws a line connecting the two points specified by the coordinate pairs. 
graphicsObj.DrawLine(blackPen, XinPoints(Xmin) - 100, _
YinPoints(0), XinPoints(Xmax) + 5, YinPoints(0))

'Add arrow to X+ axis:
graphicsObj.DrawLine(blackPen, XinPoints(Xmax) + 5, _
YinPoints(0), XinPoints(Xmax), YinPoints(0) - 5)
graphicsObj.DrawLine(blackPen, XinPoints(Xmax) + 5, _
YinPoints(0), XinPoints(Xmax), YinPoints(0) + 5)

'Gridlines at X-axis:
For I = Xmin To Xmax ' X-axis
                
'Create a dashed line:
blackPen.DashStyle = Drawing2D.DashStyle.Dash
    If I <> 0 Then
        ' Gridlines vertical:
        graphicsObj.DrawLine(blackPen, XinPoints(I), _
        YinPoints(Ymin), XinPoints(I), YinPoints(Ymax))
    End If
Next 

最后 - 在坐标上绘制测试线。

'Draw test line from 0,0
x = 0
y = 0
graphicsObj.DrawLine(bluePen, XinPoints(1), YinPoints(6), _
XinPoints((Xmax - Xmin) / 20 * x + Xmin), YinPoints(y))
x = 1
y = 6
graphicsObj.DrawLine(bluePen, XinPoints(2), YinPoints(4), _
XinPoints((Xmax - Xmin) / 20 * x + Xmin), YinPoints(y))

这只是一个在笛卡尔坐标系中绘制的简单图表。如果您想绘制实时数据或从数据库查询的数据的图表,您将不得不解决更困难的任务。

参考文献

历史

  • 08.2007 - 在 Visual Basic 6.0 中构建
  • 04.2011 - 升级到 Visual Basic 2010
© . All rights reserved.