如果不用 QLinearGradient,怎么实现上面的渐变效果呢?也既是线性渐变的原理是什么呢? 以求线段上任意点的坐标为例,如图,已知线段的两端点 A(x1, y1),B(x2, y2),求线段上任意一点 M 的坐标 (x, y),则
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
根据两点的距离公式可以求出线段的长度 |AB|(用 || 表示线段的长度) t = |AM| / |AB|; 因为 |AM| >= 0 且 |AM| <= |AB|,所以 t 的值为 [0.0, 1.0],用 length 表示 |AB|,则 x = x1 + t * length y = y1 + t * length
t 为 0.0 时 M 和 A 重合,t 为 1.0 时 M 和 B 重合。 因为 t 的值为 0 到 1 之间,所以可以用循环求出 AB 上任意点的坐标
for (float t = 0.0; rate <= 1.0; t += 0.1) { x = x1 + t * length; y = y1 + t * length; }
其实这就是线段的参数方程。
上面可以理解为坐标的渐变,变化的是坐标的 x, y 分量,颜色的渐变理论上也是一样的,只不过要变化的是颜色的 R, G, B 三个分量。如果同时已知点 A,B 的坐标和颜色 (r1, g1, b1), (r2, g2, b2),那么 M 点的坐标和颜色为:
1 2 3 4 5 6 7 8 9
for (float t = 0.0; rate <= 1.0; t += 0.1) { x = x1 + t * length; y = y1 + t * length;
r = r1 + t * (r2-r1); g = g1 + t * (g2-g1); b = b1 + t * (b2-b1); }
也既是说,如果知道某个点对应的 t,那么就能计算出此点的颜色。如下图,要在矩形内沿着 AB 进行渐变填充,已知点 A,B 的坐标和颜色,在矩形内任意一点 N 的坐标也是已知的(循环遍历矩形内所有的点),那么就可以求出点 N 在 AB 上的投影 M(MN 垂直于 AB),t=|AM|/|AB|,使用上面的方法求出点 M 的颜色,点 M 的颜色就是点 N 的颜色。
对于下图垂直方向的渐变来说,点 A(x1, y1) 为矩形的左上角,点 B(x2, y2) 为矩形的坐下角,矩形内任意一点 N(x, y) 在 AB 上的投影 M 的坐标为 (x1, y),所以 t = (y-y1)/(y2-y1),知道了 t,那么就能计算出对应的颜色了。
// 计算矩形中每一个点的颜色,然后用此颜色绘制这个点 for (int x = rect.x(); x <= rect.x() + rect.width(); ++x) { for (int y = rect.y(); y <= rect.y() + rect.height(); ++y) { qreal t = (y-y1) / (y2-y1); t = qMax(0.0, qMin(t, 1.0));
int r = r1 + t * (r2-r1); int g = g1 + t * (g2-g1); int b = b1 + t * (b2-b1);
// 计算矩形中每一个点的颜色,然后用此颜色绘制这个点 for (int x = rect.x(); x <= rect.x() + rect.width(); ++x) { for (int y = rect.y(); y <= rect.y() + rect.height(); ++y) { QPointF p = transform.map(QPointF(x ,y)); qreal t = p.x() / length; t = qMax(0.0, qMin(t, 1.0));
int r = r1 + t * (r2-r1); int g = g1 + t * (g2-g1); int b = b1 + t * (b2-b1);