给你个单元,绝对可以用,我目前编的程序就是用这个unit drawGradient;interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs,Math;
function SSDrawGradient(ACanvas: TCanvas; AClipRect: TRect;
FromPoint, ToPoint: TPoint; FromColor, ToColor: TColor): Boolean;
implementationfunction SSDrawGradient(ACanvas: TCanvas; AClipRect: TRect;
FromPoint, ToPoint: TPoint; FromColor, ToColor: TColor): Boolean;
type
TSSGradientDirection=(gdEast, gdWest, gdNorth, gdSouth, gdOther);
var
buf:TBitmap;
w,h,y,x,XOffset,ir,ig,ib,pw,ph:Integer;
c1, c2: TColor;
r1,g1,b1,r2,g2,b2,br,bg,bb,rmax,rmin,gmax,gmin,bmax,bmin: Byte;
kx,ky,kx0,ky0,rx0,gx0,bx0,r0,g0,b0,drx,dry,dgx,dgy,dbx,dby,dr,dg,db: Double;
P : PByteArray; function GetStep(V1, V2, V3:Integer): Double;
begin
if V2=V1 then Result:=0
else Result:=V3/(V2-V1);
end;begin
Result:=False;
if (FromPoint.Y=ToPoint.Y)and(FromPoint.X=ToPoint.X) then Exit;
buf:=TBitmap.Create;
try
//初始化缓冲区
buf.PixelFormat:=pf24bit;
w:=AClipRect.Right -AClipRect.Left;
buf.Width:=w;
h:=AClipRect.Bottom -AClipRect.Top ;
buf.Height:=h;
//为了防止运算溢出而设的检查
if (w>Screen.Width)or(h>Screen.Height) then Exit; //读取渐变起点和终点的RGB值
c1:=ColorToRGB(FromColor);
c2:=ColorToRGB(ToColor);
r1:=GetRValue(c1);
g1:=GetGValue(c1);
b1:=GetBValue(c1);
r2:=GetRValue(c2);
g2:=GetGValue(c2);
b2:=GetBValue(c2);
if r1>r2 then begin rmin:=r2; rmax:=r1 end
else begin rmin:=r1; rmax:=r2 end;
if g1>g2 then begin gmin:=g2; gmax:=g1 end
else begin gmin:=g1; gmax:=g2 end;
if b1>b2 then begin bmin:=b2; bmax:=b1 end
else begin bmin:=b1; bmax:=b2 end;
pw:=Abs(ToPoint.X-FromPoint.X);
ph:=Abs(ToPoint.Y-FromPoint.Y);
kx:=pw/Sqrt(ph*ph+pw*pw);
ky:=ph/Sqrt(ph*ph+pw*pw);
//计算出RGB值相对于XY轴的线性变化系数
drx:=GetStep(AClipRect.Left, AClipRect.Right, Round((r2-r1)*kx));
dry:=GetStep(AClipRect.Top, AClipRect.Bottom, Round((r2-r1)*ky));
dgx:=GetStep(AClipRect.Left, AClipRect.Right, Round((g2-g1)*kx));
dgy:=GetStep(AClipRect.Top, AClipRect.Bottom, Round((g2-g1)*ky));
dbx:=GetStep(AClipRect.Left, AClipRect.Right, Round((b2-b1)*kx));
dby:=GetStep(AClipRect.Top, AClipRect.Bottom, Round((b2-b1)*ky)); //计算出矩形左上角的RGB值,备用
kx0:=GetStep(FromPoint.X, ToPoint.X, FromPoint.X);
ky0:=GetStep(FromPoint.Y, ToPoint.Y, FromPoint.Y);
r0:=r1+(kx0+ky0)*r2;
g0:=g1+(kx0+ky0)*g2;
b0:=b1+(kx0+ky0)*b2; //这三个变量是每个扫描线的第一个点的RGB值
rx0:=r0;
gx0:=g0;
bx0:=b0;
for y:=0 to h-1 do
begin
XOffset:=0;
//dr意思是Double类型的红色值,其他类推
dr:=rx0;
dg:=gx0;
db:=bx0;
P := buf.ScanLine[y];
for x:=0 to w-1 do
begin
//ir的意思是整型的红色值,其他类推
//之所以要先转成整型,是因为我觉得整型的比较也许会比浮点快一点
//反正都要三次Round的,不如早做……
ir:=Round(dr);
ig:=Round(dg);
ib:=Round(db);
//br的意思是字节型的红色值
br:=Max(Min(rmax,ir),rmin);
bg:=Max(Min(gmax,ig),gmin);
bb:=Max(Min(bmax,ib),bmin);
//按照偏移量设置RGB值
P[XOffset]:=bb;
P[XOffset+1]:=bg;
P[XOffset+2]:=br; if FromPoint.X<>ToPoint.X then
begin
//下一个像素的RGB值分别按照一定的系数递增
dr:=dr+drx;
dg:=dg+dgx;
db:=db+dbx;
end;
//因为我定义的P是字节型的数组,所以这里递增“3”,避免使用乘法
Inc(XOffset, 3);
end;
if FromPoint.Y<>ToPoint.Y then
begin
//按照RGB在Y轴方向上的变化规律计算下一行的第一个像素RGB值
rx0:=rx0+dry;
gx0:=gx0+dgy;
bx0:=bx0+dby;
end;
end;
//将缓冲区复制到目标上
BitBlt(ACanvas.Handle, AClipRect.Left, AClipRect.Top, w, h,
buf.Canvas.Handle, 0, 0, SRCCOPY);
Result:=True;
finally
buf.Free;
end;
end;
end.
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs,Math;
function SSDrawGradient(ACanvas: TCanvas; AClipRect: TRect;
FromPoint, ToPoint: TPoint; FromColor, ToColor: TColor): Boolean;
implementationfunction SSDrawGradient(ACanvas: TCanvas; AClipRect: TRect;
FromPoint, ToPoint: TPoint; FromColor, ToColor: TColor): Boolean;
type
TSSGradientDirection=(gdEast, gdWest, gdNorth, gdSouth, gdOther);
var
buf:TBitmap;
w,h,y,x,XOffset,ir,ig,ib,pw,ph:Integer;
c1, c2: TColor;
r1,g1,b1,r2,g2,b2,br,bg,bb,rmax,rmin,gmax,gmin,bmax,bmin: Byte;
kx,ky,kx0,ky0,rx0,gx0,bx0,r0,g0,b0,drx,dry,dgx,dgy,dbx,dby,dr,dg,db: Double;
P : PByteArray; function GetStep(V1, V2, V3:Integer): Double;
begin
if V2=V1 then Result:=0
else Result:=V3/(V2-V1);
end;begin
Result:=False;
if (FromPoint.Y=ToPoint.Y)and(FromPoint.X=ToPoint.X) then Exit;
buf:=TBitmap.Create;
try
//初始化缓冲区
buf.PixelFormat:=pf24bit;
w:=AClipRect.Right -AClipRect.Left;
buf.Width:=w;
h:=AClipRect.Bottom -AClipRect.Top ;
buf.Height:=h;
//为了防止运算溢出而设的检查
if (w>Screen.Width)or(h>Screen.Height) then Exit; //读取渐变起点和终点的RGB值
c1:=ColorToRGB(FromColor);
c2:=ColorToRGB(ToColor);
r1:=GetRValue(c1);
g1:=GetGValue(c1);
b1:=GetBValue(c1);
r2:=GetRValue(c2);
g2:=GetGValue(c2);
b2:=GetBValue(c2);
if r1>r2 then begin rmin:=r2; rmax:=r1 end
else begin rmin:=r1; rmax:=r2 end;
if g1>g2 then begin gmin:=g2; gmax:=g1 end
else begin gmin:=g1; gmax:=g2 end;
if b1>b2 then begin bmin:=b2; bmax:=b1 end
else begin bmin:=b1; bmax:=b2 end;
pw:=Abs(ToPoint.X-FromPoint.X);
ph:=Abs(ToPoint.Y-FromPoint.Y);
kx:=pw/Sqrt(ph*ph+pw*pw);
ky:=ph/Sqrt(ph*ph+pw*pw);
//计算出RGB值相对于XY轴的线性变化系数
drx:=GetStep(AClipRect.Left, AClipRect.Right, Round((r2-r1)*kx));
dry:=GetStep(AClipRect.Top, AClipRect.Bottom, Round((r2-r1)*ky));
dgx:=GetStep(AClipRect.Left, AClipRect.Right, Round((g2-g1)*kx));
dgy:=GetStep(AClipRect.Top, AClipRect.Bottom, Round((g2-g1)*ky));
dbx:=GetStep(AClipRect.Left, AClipRect.Right, Round((b2-b1)*kx));
dby:=GetStep(AClipRect.Top, AClipRect.Bottom, Round((b2-b1)*ky)); //计算出矩形左上角的RGB值,备用
kx0:=GetStep(FromPoint.X, ToPoint.X, FromPoint.X);
ky0:=GetStep(FromPoint.Y, ToPoint.Y, FromPoint.Y);
r0:=r1+(kx0+ky0)*r2;
g0:=g1+(kx0+ky0)*g2;
b0:=b1+(kx0+ky0)*b2; //这三个变量是每个扫描线的第一个点的RGB值
rx0:=r0;
gx0:=g0;
bx0:=b0;
for y:=0 to h-1 do
begin
XOffset:=0;
//dr意思是Double类型的红色值,其他类推
dr:=rx0;
dg:=gx0;
db:=bx0;
P := buf.ScanLine[y];
for x:=0 to w-1 do
begin
//ir的意思是整型的红色值,其他类推
//之所以要先转成整型,是因为我觉得整型的比较也许会比浮点快一点
//反正都要三次Round的,不如早做……
ir:=Round(dr);
ig:=Round(dg);
ib:=Round(db);
//br的意思是字节型的红色值
br:=Max(Min(rmax,ir),rmin);
bg:=Max(Min(gmax,ig),gmin);
bb:=Max(Min(bmax,ib),bmin);
//按照偏移量设置RGB值
P[XOffset]:=bb;
P[XOffset+1]:=bg;
P[XOffset+2]:=br; if FromPoint.X<>ToPoint.X then
begin
//下一个像素的RGB值分别按照一定的系数递增
dr:=dr+drx;
dg:=dg+dgx;
db:=db+dbx;
end;
//因为我定义的P是字节型的数组,所以这里递增“3”,避免使用乘法
Inc(XOffset, 3);
end;
if FromPoint.Y<>ToPoint.Y then
begin
//按照RGB在Y轴方向上的变化规律计算下一行的第一个像素RGB值
rx0:=rx0+dry;
gx0:=gx0+dgy;
bx0:=bx0+dby;
end;
end;
//将缓冲区复制到目标上
BitBlt(ACanvas.Handle, AClipRect.Left, AClipRect.Top, w, h,
buf.Canvas.Handle, 0, 0, SRCCOPY);
Result:=True;
finally
buf.Free;
end;
end;
end.
解决方案 »
- 关于用delphi实现批量登录远程mstsc的问题
- UrlDownloadToFile这个函数存在代理的问题吗?
- 加分 关于数据字段计数、排名次的问题
- 求助高手:用indy的tcp控件发送和接收数组该用什么函数?
- Delphi控件读取数据库问题
- 有关在delphi里用ADO连接到db2数据库出现的问题!
- 一下这段代码,有个问题不明白,望解惑!!
- 高分求Install Sheild for Dephi
- 汇编+DELPHI高手请进(赏分)
- visibroker问题:为何启动\delphi6\vbroker\bin\osagent(SMART AGENT)老是启动后马上退出?corba高手47分请教!!!
- TO: taidy() ,我用你的办法动态生成了几个按钮,但是我怎样写代码响应这个按钮的Onclick事件呢
- 关于SQL语句的问题?
1 取得起点颜色RGB1(就是TColor),和终点颜色RGB2;
2 将起点颜色分解成R,G,B:
GetRValue(RGB1),GetGValue(RGB1),GetBValue(RGB1); RGB2也一样
3 计算每像素三种单色增加的幅度: deltaR:=(R2-R1)/Width
4 讲递进后的单色合成RGB(R,G,B)然后画图
for i:=0 to Width
Line(0,0,i,Height,RGB(R,G,B)) //伪码
其中 R=R1+i*deltaR
简单吧?
我想各位应该见过Windows2000安装程序,瞧安装背景色,多平滑啊!
我自己也曾做了画渐变色,但效果不理想,颜色有些突变..我的简要代码如下:=========================
说明:
在指定画布上指定区域内以startColor为开始色,endColor为结束色
画过渡色。bFlag标志为横向或者纵向(尚未处理)
procedure tform1.DrawRange(ACanvas: TCanvas; r:TRect;startColor, endColor: TColor;
bFlag: boolean);
var i,sR,sG,sB,eR,eG,eB:integer;
const WIDTH=100;
begin
sR:=GetRValue(startColor);
sG:=GetGValue(startColor);
sB:=GetBValue(startColor);
eR:=GetRValue(endColor);
eG:=GetGValue(endColor);
eB:=GetBValue(endColor); for i:=0 to WIDTH do
begin
ACanvas.pen.color:=rgb(sR+(i*(eR-sR) div WIDTH),
sG+(i*(eG-sG) div WIDTH),
sB+(i*(eB-sB) div WIDTH));
ACanvas.MoveTo(i,0);
ACanvas.LineTo(i,30);
end;
end;
比如start=1;
end=2;
width=100;
那就只有两种颜色所以肯定在中间的地方会出现突变,改变的方法是在你的30长的线上面加一些不同的颜色,比如在i=25的地方增加15个点2的颜色。你可以这样理解,你的方法每个颜色只在属于他的地方起作用,一旦超出了他起作用的范围她就突然不起作用了,这样造成了 突变。而好的方法是每个颜色在他应该起作用的点傍边一定范围内也渐变形的起一些作用,比如说颜色100应该在10到20的地方起作用,那么改进后在10到20的范围内100占的比重是100在9和21的地方占的比重是80在8和22的地方占比重60以此类推。
最后可以得到在9的地方颜色100占比重80,颜色99占比重100,那么在9这个位置你应该每180个点中由100个99颜色的80个100颜色的,当然最好事均匀的随机分布的。这样一来你会发现他变成渐变得了。
不知道我说明白了没有!