使用 C# 进行 Windows 应用程序图表制作。






4.69/5 (16投票s)
使用 Windows 应用程序和 C# 中的 .NET Framework 内置函数创建图表
引言
绘制图表或图形是许多项目的常见需求。如果您是一名软件专业人士,您一定遇到过绘制图表的情况。大多数时候,我们倾向于依赖昂贵的第三方控件。
背景
我将演示 .NET 的内置函数来绘制一些基本图表。到文章结尾,您应该可以在您的 Windows 应用程序中绘制基本图表。我这里使用 C#。
Using the Code
我创建了一个 Windows 应用程序,并编写了以下四个函数来处理四种不同类型的图表。
绘制切片图
绘制饼图
绘制柱状图
绘制折线图
在我们的示例中,我们将输入权重为 (13, 23, 33, 15, 20, 10, 4, 11)。我们将此数组传递给上述所有函数。让我们一一讨论所有函数。
绘制切片图
可以将此看作是根据权重将蛋糕切成片。在此图表中,切片的角度与权重呈线性比例。为了理解这一点,我们将讨论 .NET 支持的 `FillPie` 函数。
`FillPie` 函数的签名如下:
Void FillPie(Brush brush, int x,int y, int width,int height,
int startAngle, int sweepAngle)
如果扫描角度为 360 度,则此函数用于填充椭圆。为了使其成为一个圆形,我们将高度和宽度都设置为圆的直径。
height = width = 2*radius;
让我们来看一下参数的细节。
Brush brush
:这是一个用于填充饼图的 `brush` 对象。Int x
:定义饼图扇形所在的椭圆的边界矩形的左上角的 `x` 坐标。因此,如果我们的圆心 `x` 坐标为 `x0`,半径为 `r`x = x0 – r;
Int y
:与 `x` 类似。y = y0 – r;
Int width
:定义椭圆的边界矩形的 `width`,从该椭圆中获取饼图扇形。width = 2*radius;
Int startAngle
:从 `x` 轴到饼图扇形第一边的角度(顺时针测量)。因此,我们从 0 度开始,并将其与 `sweepAngle` 递增,以便下一个切片紧接着前一个切片结束。Int sweepAngle
:从 `startAngle` 参数到饼图扇形第二边的角度(顺时针测量)。因此,这是基于权重的角度跨度。所以 360 度根据权重按比例分为 8 部分。对于我们示例中的权重 `23`:
Int totalWeight = 13+23+33+15+20+10+4+11; sweepAngle = (23 * 360)/totalWeight;
然后我使用另一个函数来绘制形状周围的边框:`DrawPie`。它与 `FillPie` 唯一的区别是它接受 `Pen` 对象而不是 `Brush`。
private void DrawSliceChart(PaintEventArgs e, int[] alWeight)
{
int numberOfSections = alWeight.Length
int x0 = 100;
int y0 = 100;
int radius = 100;
int startAngle = 0;
int sweepAngle = 0;
int[] height = new int[numberOfSections];
int total = SumOfArray(alWeight);
Random rnd = new Random();
SolidBrush brush = new SolidBrush(Color.Aquamarine);
Pen pen = new Pen(Color.Black);
for (int i = 0; i < numberOfSections; i++)
{
brush.Color = Color.FromArgb(rnd.Next(200, 255),
rnd.Next(255), rnd.Next(255), rnd.Next(255));
// Since we have taken integer so last slice needs to
// be rounded off to fit into the remaining part.
if (i == numberOfSections - 1)
sweepAngle = 360 - startAngle;
else
sweepAngle = (360 * alWeight[i]) / total;
e.Graphics.FillPie(brush, x0 - height[i], y0 - height[i],
2*radius, 2*radius, startAngle , sweepAngle);
e.Graphics.DrawPie(pen, x0 - height[i], y0 - height[i],
2*radius, 2*radius, startAngle, sweepAngle);
startAngle += sweepAngle;
brush.Color = Color.FromKnownColor(KnownColor.Black);
}
}
绘制饼图
这是另一个图表,它也使用相同的内置函数,只需对之前的代码稍作修改。在此图表中,所有切片的角度相同,但半径根据权重而变化。
因此,我们首先找出最大权重 `MaxWeight`。然后 `MaxWeight` 将等于半径,而其他切片的半径将小于 `MaxWeight` 的比例。
例如,对于权重 `23`:
MaxWeight = 33;
width = (23*radius)/MaxWeight;
sweepAngle = 360/TotalNumberOfWeights;
`startAngle` 将从 0 开始,并由 `sweepAngle` 递增。
startAngle += sweepAngle;
private void DrawPieChart(PaintEventArgs e, int[] alWeight)
{
int numberOfSections = alWeight.Length;
int x0 = 600;
int y0 = 500;
int radius = 200;
int startAngle = 0;
int sweepAngle = 360/numberOfSections;
int[] height = new int[numberOfSections];
int maxWeight = MaxValue(alWeight);
Random rnd = new Random(10);
SolidBrush brush = new SolidBrush(Color.Aquamarine);
Pen pen = new Pen(Color.Black);
for(int i =0;i<numberofsections;i++){
height[i] = ((Convert.ToInt32(alWeight[i])) * radius) / maxWeight;
brush.Color = Color.FromArgb(rnd.Next(200, 255), rnd.Next(255),
rnd.Next(255), rnd.Next(255));
e.Graphics.FillPie
(brush, x0 - height[i], y0 - height[i], 2 * height[i],
2 * height[i],(startAngle+i*45), sweepAngle);
e.Graphics.DrawPie(pen, x0 - height[i], y0 - height[i], 2 * height[i],
2 * height[i], (startAngle + i * 45), sweepAngle);
//e.Graphics.FillPie(Brushes.Blue, x0 - height[i], y0 - height[i],
//2 * height[i], 2 * height[i], (startAngle + i * 45 -2), 2);
}
}
绘制柱状图
在此,我们使用了内置函数 '`DrawRectangle`'。这里的想法是首先创建一个定义柱状图边界的大矩形。`DrawRectangle` 函数接受以下参数:
- `Pen` – 定义边框的颜色和样式
- `Rectangle` – 要创建的 `Rectangle` 对象
我们将仔细研究 `rectangle` 对象。
Rectangle(int x, int y, int width,int height)
`X` 和 `y` 是矩形左上角的坐标。
`Width` 和 `height` 是矩形的 `width` 和 `height`。
所以,要绘制一个条形,我们将使用相同的函数。唯一需要确定的是 `Rectangle` 的这四个参数。`Width` 是恒定的,等于外部矩形总长度除以条形总数。`Height` 计算如下:
Height = (weight of current array element *
height of outer rectangle )/ maximum weight.
每次创建新条形时,`X` 坐标都会按条形宽度递增。
`Y` 坐标通过以下公式计算:
y = y coordinate of outer rectangle + height of outer rectangle –
height of bar calculated using above formula
像 `DrawPie` 和 `DrawSlice` 一样,我们使用相应的填充函数填充形状。
private void DrawBarChart(PaintEventArgs e, int[] alWeight)
{
int numberOfSections = alWeight.Length;
int lengthArea = 400;
int heightArea = 250;
int topX = 400;
int topY = 20;
int maxWeight = MaxValue(alWeight);
int[] height = new int[numberOfSections];
int total = SumOfArray(alWeight);
Random rnd = new Random();
SolidBrush brush = new SolidBrush(Color.Aquamarine);
Pen pen = new Pen(Color.Gray);
Rectangle rec = new Rectangle(topX,topY,lengthArea,heightArea);
e.Graphics.DrawRectangle(pen,rec);
pen.Color = Color.Black;
int smallX = topX;
int smallY = 0;
int smallLength = (lengthArea/alWeight.Length);
int smallHeight = 0;
for (int i = 0; i < numberOfSections; i++)
{
brush.Color = Color.FromArgb(rnd.Next(200, 255),
rnd.Next(255), rnd.Next(255), rnd.Next(255));
smallHeight = ((alWeight[i] * heightArea )/ maxWeight);
smallY = topY + heightArea - smallHeight;
Rectangle rectangle = new Rectangle
(smallX, smallY, smallLength, smallHeight);
e.Graphics.DrawRectangle(pen,rectangle);
e.Graphics.FillRectangle(brush, rectangle);
brush.Color = Color.FromKnownColor(KnownColor.Black);
e.Graphics.DrawRectangle(pen, rectangle);
smallX = smallX + smallLength;
}
}
绘制折线图
要绘制折线图,我们首先使用内置函数 '`DrawRectangle`' 创建边界。然后我们确定绘制直线的点。
`X` 坐标按相等距离递增,`y` 坐标基于权重设置。
在这里,为了突出显示每个点,我使用了 `DrawDots` 函数,通过创建一个半径为 5 的圆来突出显示该点。
private void DrawLineChart(PaintEventArgs e,int[] alWeight)
{
int numberOfSections = alWeight.Length;
int lengthArea = 400;
int heightArea = 250;
int topX = 20;
int topY = 400;
int maxWeight = MaxValue(alWeight);
int[] height = new int[numberOfSections];
int total = SumOfArray(alWeight);
Random rnd = new Random();
SolidBrush brush = new SolidBrush(Color.Aquamarine);
Pen pen = new Pen(Color.Gray);
Rectangle rec = new Rectangle(topX, topY, lengthArea, heightArea);
e.Graphics.DrawRectangle(pen, rec);
pen.Color = Color.Black;
int smallX = topX;
int smallY = 0;
int smallLength = (lengthArea / (alWeight.Length + 1));
int smallHeight = 0;
Point p1 = new Point();
Point p2 = new Point();
for (int i = 0; i < numberOfSections; i++)
{
brush.Color = Color.FromArgb(rnd.Next(200, 255),
rnd.Next(255), rnd.Next(255), rnd.Next(255));
p1 = p2;
p2.X = p2.X + smallLength;
smallHeight = ((alWeight[i] * heightArea) / maxWeight);
p2.Y = topY + heightArea - smallHeight;
if (p1.X != 0 && p1.Y != 0)
{
e.Graphics.DrawLine(pen, p1, p2);
}
DrawDots(e,p2);
smallX = smallX + smallLength;
}
}
这是突出显示点的函数:
private void DrawDots(PaintEventArgs e, Point p1)
{
Pen pen = new Pen(Color.SeaGreen);
e.Graphics.DrawPie(pen, p1.X-5 , p1.Y-5, 10, 10, 0, 360);
e.Graphics.FillPie(new SolidBrush(Color.Purple),
p1.X - 5, p1.Y - 5, 10, 10, 0, 360);
}
关注点
因此,这些是我们能创建的一些图表。我们还可以根据自己的需求进行自定义。如果您的需求只是绘制类似于这三个图表中的任何一个,只需复制粘贴该函数,然后根据您的要求更改坐标和颜色即可。此外,我还使用了另外两个简单的函数来获取数组的最大值和总和。您可以在附件中找到完整的源代码。
需要注意的重要一点是,所有这四个函数都从 `Paint` 事件处理函数调用,并接受 `PaintEventArgs` 和权重数组作为参数。
历史
- 2009年4月7日:初稿