C# 2.0 图形控件






4.88/5 (9投票s)
2006年12月16日
5分钟阅读

74506

1529
通用多曲线图控件。
引言
本项目创建了一个图形控件,它是标准.Net WinForms 2.0 PictureBox
控件的子类。它易于集成到VS2005工具箱中,并支持多条曲线、多种样式、图例、网格和其他功能。它可以绘制函数和关系。图形可以自动缩放,也可以完全控制缩放。
我没有提供单独的DLL,但您可以轻松地将GraphHelp.cs和GraphBox.cs(包含在演示项目中)一起构建,以便在多个项目中使用。
所有的颜色、字体和显示特性都可以通过代码直接设置,也可以在Visual Studio设计器中设置。
这个控件的主要区别在于支持模块GraphHelp.cs。GraphHelp
声明了一组非泛型和泛型类,它们为控件提供数据流。通过这些,控件可以使用任何可转换为数值的值作为轴。演示代码显示了DateTime
水平轴和float垂直轴。
通过使用委托和泛型,GraphHelp
允许您通过最少的代码绘制几乎任何数据类型与其他数据类型。如果您不想使用泛型,可以直接使用非泛型基类。
此外,GraphBox
的默认行为允许您将图像保存到磁盘。它还支持通过弹出“工具提示”窗口将图形位置翻译成人类可读的值,该窗口在鼠标按钮按住图形时出现。
背景
在当今的环境中,创建图形的很大一部分工作来自于在您的数据“原生”域及其类型与GDI+等GUI的严格要求之间进行双向转换。要创建支持从图形上的点到数据空间中的点的双向(可逆)转换的代码,可能会很繁琐。
GraphBox和GraphHelp协同工作,不仅显示信息,还允许您创建安全、可靠管理多种数据类型的数据容器。
以下是GraphHelp
中类的基本层次结构。请记住,您可以充分利用GraphBox而不实例化任何泛型类型;如果您觉得使用它们方便,它们只会让事情变得更容易。
这是基本概念。创建一个GraphDataset
并将其与GraphBox
关联;图形绘制是自动的。每个GraphDataset
至少有一个GraphDatastream
用于绘制;GraphDatastreams
可能为空。
要了解所有内容如何组合在一起,请在Debug模式下运行程序,并在FormGraphDemo.cs中的RecreateDataset()
处设置断点。观察GraphBox如何调用CreateDesignTimeDataset()
来构建其测试数据集。
GraphItem
这是一个抽象类,代表一个有序对(X(水平)和Y(垂直)值)。
GraphItemXY<TH,TV>
这是GraphItem
的泛型版本。由于它包含“原始”数据(例如DateTime),每个都依赖于其关联的GraphDimension
将其值转换回“float”。
GraphDimension
GraphDimension
是一个抽象类,包含一个浮点范围([minimum..maximum]);它可以将其他浮点值缩放到其范围内以及从其范围缩出。它还知道如何格式化打印值和图形图例。
GraphDim<T>
这是GraphDimension
的泛型版本。它允许轻松声明新数据类型的维度。在GraphHelp中,此类用作GraphDimInt
、GraphDimFloat
、 GraphDimLong
和GraphDimDateTime
类的基础。如果您想声明自己的维度,请查看这些类。
GraphDatastream
GraphDatastream
是GraphItems
的集合,代表一条曲线或一个图形。GraphDatastreams
也知道如何“分桶”或合并和排序密集数据集以进行快速显示。
GraphDataset
GraphDataset
是(至少一个)GraphDatastreams
的集合。这是GraphBox用来创建图形的类。换句话说,创建一个数据集并将其告知GraphBox
—— 就会生成一个图形。
GraphDatastreamGenerator<TH,TV,TI>
这是一个泛型接口,如果实现,则创建类型安全的GraphDataStreams
。有关详细信息,请参阅下面的示例。
GraphDatasetXY<TH,TV>
这是GraphDataset
的泛型或类型安全版本。它具有自动创建适合您正在使用的数据类型的缩放GraphDimensions
的逻辑。如果您创建新的GraphDimension类,您可以告知GraphDatasetXY,它将在适当的时候使用它们。
GraphHelper
GraphHelper
是一个隐式助手类,它是GraphDataset
类和GraphBox
控件之间的“桥梁”。您永远不会创建它——它会在需要时出现。
使用代码
要使用该代码,只需从ZIP文件中解压项目并进行构建。您必须拥有Microsoft Visual Studio 2005或.Net Framework工具集的最新版本。
演示代码是一个WinForms应用程序,它使用GraphBox创建的内置数据集,其中一个在“设计时”(当您构建应用程序窗口时)使用。
核心要求是为GraphBox
提供一个包含要绘制数据的GraphDataset
。这可以通过一次添加一个GraphItems来完成。或者,您可以调用GraphDataset或GraphDatasetXY类中的某个函数求值器来为您构建数据集。
在第一个示例中,创建了一个“ping”数据的的数据集,其中每个点代表一个ICMP“ping”消息,发生在一个特定的日期和时间;每个事件完成需要测量毫秒数。
//
// Create a GraphDataset with DateTime as the x-axis and a float
// (millisecond round-trip time) for "ping" data. Give display names
// to the dimensions
//
GraphDatasetXY<DateTime, float> gdb =
new GraphDatasetXY<DateTime, float>( "ping time", "ms round trip" );
//
// Populate the default GraphDatastream in the GraphDataset
//
foreach (PingNote pn in pt.Notes)
{
gdset.Add( 0, pn.dtEvent, pn.cmsRoundTrip );
}
//
// Tell the GraphBox to graph it.
//
gboxTest.Dataset = gdset;
另一个更复杂的例子是GraphBox.cs中的一个函数。它的作用是创建一个由一组点表示的正弦曲线。它通过使用“委托”或C#函数指针来实现;在这种情况下,它被称为
SineFunction
。//
// Use GraphDatastream's "FromFunction" capability to run the SineFunction
// delegate the correct number of times.
//
private GraphDataset DesignTimeDatasetTestSine ( int cPoints )
{
float fxMin = 0;
float fxMax = (float) (Math.PI * 2);
float fxInc = (fxMax - fxMin) / (float)(cPoints + 1);
GraphDatastream gstrm = GraphDatastream.FromFunction( SineFunction,
fxMin, fxMax, fxInc );
GraphDatasetXY<float,float> gds
= new GraphDatasetXY < float,float >("Angle", "Sine",gstrm);
return gds;
}
private void SineFunction ( float fx, out float fxOut, out float fyOut )
{
fxOut = fx;
fyOut = (float) Math.Sin( (double) fx );
}
关键点是GraphBox需要一个GraphDataset
,它是一个包含一个或多个GraphDatastreams
的容器。该代码允许您为流使用几乎任何类型的数据。
关于缩放的说明
当一个简单的数据集被提供给GraphBox
时,会遍历这些项来确定数据的下限和上限。这些限制默认使用(请参阅GraphHelp.cs中的AutoScaleDimensions()
)。但是,您可以调用MeasureDimensions()
和RescaleDimensions()
来直接设置您期望的值。这允许“缩放”。关注点
这是我第二次深入体验将标准的C#(抽象类、委托等)与C# 2.0的泛型功能相结合。我发现一切基本上都按预期工作。我能够解决.Net泛型的一些更具挑战性的方面,例如缺少标准的“数值接口”;在这种情况下,我依赖了IComparer
接口。
历史
2006年12月15日。代码和演示程序的第一个版本。