我正在生成一堆具有不同大小和位置的RectangleF对象。用GDI +中的渐变画笔填充它们的最佳方法是什么?
在WPF中,我可以创建一个LinearGradientBrush,设置开始和结束relative
点,WPF将负责其余的。
然而,在GDI +中,渐变画笔构造函数需要绝对坐标中的位置,这意味着我必须为每个矩形创建一个画笔,这将是一个非常复杂的操作。
我错过了什么或者确实是唯一的方法吗?
答案 0 :(得分:1)
如果您只想声明画笔一次,则可以在应用渐变之前指定变换。请注意,使用转换将覆盖可以在LinearGradientBrush
上指定的许多构造函数参数。
LinearGradientBrush.Transform Property (System.Drawing.Drawing2D)
要修改转换,请调用与所需矩阵运算对应的画笔对象上的方法。请注意,矩阵运算不是可交换的,因此顺序很重要。为了您的目的,您可能希望按此顺序对矩形的每个再现执行:缩放,旋转,偏移/平移。
LinearGradientBrush.ResetTransform Method @ MSDN
LinearGradientBrush.ScaleTransform Method (Single, Single, MatrixOrder) @ MSDN
LinearGradientBrush.RotateTransform Method (Single, MatrixOrder) @ MSDN
LinearGradientBrush.TranslateTransform Method (Single, Single, MatrixOrder) @ MSDN
请注意,系统级绘图工具实际上并不包含渐变画笔的库存定义,因此如果您对制作多个画笔有性能问题,那么创建多个渐变画笔的成本不应超过GDI + / System.Drawing维护定义渐变和样式所需的数据。您可以根据需要为每个矩形创建一个画笔,而不必深入研究通过变换自定义画笔所需的数学。
Brush Functions (Windows) @ MSDN
以下是您可以在WinForms应用中测试的代码示例。此应用程序使用渐变画笔使用45度渐变绘制图块,缩放到图块的最大尺寸(天真计算)。如果您使用值和变换,您可能会发现,如果您有非平凡的渐变定义,则不值得使用为所有矩形设置变换的技术。否则,请记住您的转换是在世界级应用的,而在GDI世界中,y轴是颠倒的,而在笛卡尔数学世界中,它是从底部到顶部排序的。这也导致角度顺时针应用,而在三角学中,角度以递增的值逆时针前进,y轴向上。
using System.Drawing.Drawing2D;
namespace TestMapTransform
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Rectangle rBrush = new Rectangle(0,0,1,1);
Color startColor = Color.DarkRed;
Color endColor = Color.White;
LinearGradientBrush br = new LinearGradientBrush(rBrush, startColor, endColor, LinearGradientMode.Horizontal);
int wPartitions = 5;
int hPartitions = 5;
int w = this.ClientSize.Width;
w = w - (w % wPartitions) + wPartitions;
int h = this.ClientSize.Height;
h = h - (h % hPartitions) + hPartitions;
for (int hStep = 0; hStep < hPartitions; hStep++)
{
int hUnit = h / hPartitions;
for (int wStep = 0; wStep < wPartitions; wStep++)
{
int wUnit = w / wPartitions;
Rectangle rTile = new Rectangle(wUnit * wStep, hUnit * hStep, wUnit, hUnit);
if (e.ClipRectangle.IntersectsWith(rTile))
{
int maxUnit = wUnit > hUnit ? wUnit : hUnit;
br.ResetTransform();
br.ScaleTransform((float)maxUnit * (float)Math.Sqrt(2d), (float)maxUnit * (float)Math.Sqrt(2d), MatrixOrder.Append);
br.RotateTransform(45f, MatrixOrder.Append);
br.TranslateTransform(wUnit * wStep, hUnit * hStep, MatrixOrder.Append);
e.Graphics.FillRectangle(br, rTile);
br.ResetTransform();
}
}
}
}
private void Form1_Resize(object sender, EventArgs e)
{
this.Invalidate();
}
}
}
以下是输出的快照:
答案 1 :(得分:0)
我建议你创建一个像这样的通用方法:
public void Paint_rectangle(object sender, PaintEventArgs e)
{
RectangleF r = new RectangleF(0, 0, e.ClipRectangle.Width, e.ClipRectangle.Height);
if (r.Width > 0 && r.Height > 0)
{
Color c1 = Color.LightBlue;
Color c2 = Color.White;
Color c3 = Color.LightBlue;
LinearGradientBrush br = new LinearGradientBrush(r, c1, c3, 90, true);
ColorBlend cb = new ColorBlend();
cb.Positions = new[] { 0, (float)0.5, 1 };
cb.Colors = new[] { c1, c2, c3 };
br.InterpolationColors = cb;
// paint
e.Graphics.FillRectangle(br, r);
}
}
然后,对于每个矩形,只需调用:
yourrectangleF.Paint += new PaintEventHandler(Paint_rectangle);
如果渐变颜色全部相同,则可以缩短该方法。希望有所帮助..