.NET WinForms中CSS3 repeating-linear-gradient()替代方案及填充问题
WinForms旋转重复条纹填充不全的解决办法
问题场景
在WinForms里想实现类似CSS repeating-linear-gradient()的效果,绘制45度角的红、黄、绿循环斑马条纹,但按现有代码实现后,旋转操作导致目标矩形的部分区域没被条纹填满,原代码如下:
private void DrawRepeatingStripes(int degree, int stripeWidth, Color[] colors, Rectangle rect, Graphics graphics) { using (var img = new Bitmap(colors.Length * stripeWidth, rect.Height)) { using (var g = Graphics.FromImage(img)) { for (int i = 0; i < colors.Length; i++) { // TODO: cache SolidBrush g.FillRectangle(new SolidBrush(colors[i]), stripeWidth * i, 0, stripeWidth, rect.Height); } } using (var tb = new TextureBrush(img, WrapMode.Tile)) { using (var myMatrix = new Matrix()) { myMatrix.Rotate(degree); graphics.Transform = myMatrix; graphics.FillRectangle(tb, rect); graphics.ResetTransform(); } } } }
使用示例:
protected override void OnPaintBackground(PaintEventArgs e) { base.OnPaintBackground(e); DrawRepeatingStripes(45, 10, new Color[] { Color.Red, Color.Yellow, Color.Green }, e.ClipRectangle, e.Graphics); }
问题根源
- 生成的纹理图高度仅等于目标矩形高度,旋转后纹理的覆盖范围不足以填满原矩形的所有区域——45度旋转后,需要更大的尺寸才能覆盖原矩形的对角线范围
- 直接对Graphics应用旋转变换再填充原矩形,会导致纹理坐标偏移,边缘区域无法被覆盖
修复后的代码
private void DrawRepeatingStripes(int degree, int stripeWidth, Color[] colors, Rectangle rect, Graphics graphics) { // 计算目标矩形的对角线长度,确保旋转后纹理能完全覆盖 float diagonal = (float)Math.Sqrt(rect.Width * rect.Width + rect.Height * rect.Height); int textureSize = (int)Math.Ceiling(diagonal); // 创建足够大的纹理图,宽度为条纹循环总宽度,高度为对角线长度 using (var img = new Bitmap(colors.Length * stripeWidth, textureSize)) { using (var g = Graphics.FromImage(img)) { // 绘制水平条纹(后续旋转成目标角度) for (int i = 0; i < colors.Length; i++) { // 缓存Brush,避免频繁创建销毁资源 using (var brush = new SolidBrush(colors[i])) { g.FillRectangle(brush, stripeWidth * i, 0, stripeWidth, textureSize); } } } using (var tb = new TextureBrush(img, WrapMode.Tile)) { using (var myMatrix = new Matrix()) { // 将变换中心设置为目标矩形的中心点,避免旋转偏移 myMatrix.Translate(rect.Left + rect.Width / 2f, rect.Top + rect.Height / 2f); myMatrix.Rotate(degree); // 平移回原位置,确保纹理对齐目标矩形 myMatrix.Translate(-(rect.Left + rect.Width / 2f), -(rect.Top + rect.Height / 2f)); tb.Transform = myMatrix; // 填充目标矩形,此时纹理已正确旋转并覆盖全部区域 graphics.FillRectangle(tb, rect); } } } }
关键修改点
- 纹理尺寸调整:用目标矩形的对角线长度作为纹理高度,确保旋转后能完全覆盖原矩形区域
- 变换中心修正:将纹理画笔的变换中心设置为目标矩形的中心,避免旋转后纹理偏移
- Brush资源优化:在循环内使用
using包裹SolidBrush,完成原代码TODO的缓存优化,减少资源消耗
内容的提问来源于stack exchange,提问作者Alexey Y.
相关产品推荐
相关产品推荐

