C# WinForm中如何为Panel内GDI+绘制的多边形设置独立颜色
问题:给Panel上绘制的自定义多边形设置填充色
参考图示:图中多边形需要设置为其他颜色
我是编程新手,过去数周学习进展顺利,目前编写了一款用于计算 second moment of area(面积二次矩) 的应用程序,支持用户选择顶点定义n边多边形,顶点及多边形会绘制在Panel控件上。出于美观性考虑,我希望将多边形设置为与面板背景不同的颜色,咨询可行实现方案。
代码上下文说明:
vecPolygons存储了一个或多个Polygon对象及其关联的顶点坐标
原有代码片段如下:
public void AppendNewPolygon() { double[][,] vecTemp; vecTemp = vecPolygons; int i; vecPolygons = new double[vecTemp.Length + 1][,]; for( i=0; i< vecTemp.Length; i++) { vecPolygons[i] = vecTemp[i]; } vecPolygons[vecTemp.Length] = new double[0, 2]; }
public void AppendNewPointBefore() { double[,] arrTemp; int i; if (vecPolygons.GetLength(0) > 0) { arrTemp = vecPolygons[activePolygon]; vecPolygons[activePolygon] = new double[arrTemp.GetLength(0) + 1, 2]; for (i = 0; i < activePoint; i++) { vecPolygons[activePolygon][i, 0] = arrTemp[i, 0]; vecPolygons[activePolygon][i, 1] = arrTemp[i, 1]; } vecPolygons[activePolygon][activePoint, 0] = 0; vecPolygons[activePolygon][activePoint, 1] = 0; for (i = activePoint; i < arrTemp.GetLength(0); i++) { vecPolygons[activePolygon][i + 1, 0] = arrTemp[i, 0]; vecPolygons[activePolygon][i + 1, 1] = arrTemp[i, 1]; } } }
名为pGraphic的Panel控件的Paint事件处理代码如下:
private void pGraphic_Paint(object sender, PaintEventArgs e) { pgr.DrawPolygons( flm.vecPolygons, pGraphic); }
点击按钮bViewA时会触发面板更新,对应逻辑如下:
private void bViewA_Click(object sender, EventArgs e) { double yMin, yMax, zMin, zMax; flm.GetModelExtens(out yMin, out yMax, out zMin, out zMax); pgr.SetParametersForViewAll(pGraphic, yMin, yMax, zMin, zMax); pGraphic.Invalidate(); }
上述点击事件会调用两个方法,第一个是GetModelExtens:
public void GetModelExtens(out double ymin,out double ymax,out double zmin,out double zmax) { ymin = double.MaxValue; ymax = -double.MaxValue; zmax = -double.MaxValue; zmin = double.MaxValue; for (int i = 0; i < vecPolygons.Length; i++) { for (int j = 0; j < vecPolygons[i].GetLength(0); j++) { if (vecPolygons[i][j, 0] < ymin) ymin = vecPolygons[i][j, 0]; if (vecPolygons[i][j, 1] < zmin) zmin = vecPolygons[i][j, 1]; if (vecPolygons[i][j, 0] >ymax) ymax = vecPolygons[i][j, 0]; if (vecPolygons[i][j, 1] > zmax) zmax = vecPolygons[i][j, 1]; } } }
第二个是SetParametersForViewAll,其所属的PolygonGraphics类定义如下:
public class PolygonGraphics { double centerX, centerY, scale; public PolygonGraphics() { centerX = 0.0; centerY = 0.0; scale = 1.0; } public void SetParametersForViewAll ( Panel pGraphic ,double yMin, double yMax, double zMin, double zMax) { double scaleVert, scaleHorz; scaleVert = pGraphic.Width/ (yMax-yMin); scaleHorz = pGraphic.Height/ (zMax-zMin); scale = scaleHorz; if (scale > scaleVert) { scale = scaleVert; } scale = scale * 0.9; centerX = -yMin * scale + (pGraphic.Width-(yMax-yMin)*scale)* 0.5; centerY = zMax * scale + (pGraphic.Height - (zMax - zMin) * scale) * 0.5; } }
调用Invalidate方法触发面板重绘后,pGraphic_Paint事件会调用DrawPolygons方法执行实际绘制,该方法代码如下:
public void DrawPolygons(double[][,] vecPolygons, Panel panel) { Graphics gr; Pen pn = new Pen(Color.Black, 1); gr = panel.CreateGraphics(); gr.Clear(panel.BackColor); double xpx1, ypx1, xpx2, ypx2, ymm1, ymm2, zmm1, zmm2; int iLine, iPolygon, index2; for (iPolygon = 0; iPolygon < vecPolygons.GetLength(0); iPolygon++) { for (iLine = 0; iLine < vecPolygons[iPolygon].GetLength(0); iLine++) { index2 = (iLine + 1) % vecPolygons[iPolygon].GetLength(0); ymm1 = vecPolygons[iPolygon][iLine, 0]; zmm1 = vecPolygons[iPolygon][iLine, 1]; ymm2 = vecPolygons[iPolygon][index2, 0]; zmm2 = vecPolygons[iPolygon][index2, 1]; xpx1 = scale * ymm1 + centerX; ypx1 = -scale * zmm1 + centerY; xpx2 = scale * ymm2 + centerX; ypx2 = -scale * zmm2 + centerY; gr.DrawLine( pn, (float)xpx1, (float)ypx1, (float)xpx2, (float)ypx2); } } }
解决方案
你当前的代码只逐段绘制了多边形的黑色边框,没有调用填充API,同时使用CreateGraphics获取画布的写法存在绘制内容不持久的问题,按以下步骤修改即可实现自定义多边形颜色:
- 修改Paint事件调用逻辑:不要自行创建Graphics对象,直接使用Paint事件传入的画布对象,避免重绘时内容丢失:
private void pGraphic_Paint(object sender, PaintEventArgs e) { pgr.DrawPolygons(flm.vecPolygons, e.Graphics); } - 重写DrawPolygons方法:先将每个多边形的所有顶点转换为屏幕坐标点数组,调用
FillPolygon填充内部颜色,再绘制边框,代码如下:public void DrawPolygons(double[][,] vecPolygons, Graphics gr) { gr.Clear(pGraphic.BackColor); // 自定义边框颜色、填充色,替换成和面板背景不同的颜色即可 using Pen borderPen = new Pen(Color.Black, 1); using Brush fillBrush = new SolidBrush(Color.LightSteelBlue); for (int iPolygon = 0; iPolygon < vecPolygons.GetLength(0); iPolygon++) { int pointCount = vecPolygons[iPolygon].GetLength(0); if (pointCount < 3) continue; // 少于3个点无法构成封闭多边形,跳过 PointF[] polygonPoints = new PointF[pointCount]; for (int i = 0; i < pointCount; i++) { double ymm = vecPolygons[iPolygon][i, 0]; double zmm = vecPolygons[iPolygon][i, 1]; float x = (float)(scale * ymm + centerX); float y = (float)(-scale * zmm + centerY); polygonPoints[i] = new PointF(x, y); } // 先填充再描边,避免边框被填充层覆盖 gr.FillPolygon(fillBrush, polygonPoints); gr.DrawPolygon(borderPen, polygonPoints); } }
原有视口计算、顶点增删、全览按钮的逻辑不需要改动,重绘时会自动应用填充效果。如果需要给不同多边形设置不同颜色,只要在循环绘制每个多边形时传入对应颜色的画刷即可。
内容的提问来源于stack exchange,提问作者Tobias Trauner
相关产品推荐
相关产品推荐

