Delphi 如何在画布上同时绘制两个渐变?

Delphi 如何在画布上同时绘制两个渐变?,delphi,Delphi,请看我使用绘画程序制作的渐变图像示例: 它包含2个垂直渐变 从顶部到中间的第一个渐变是白色到浅色橙色的混合 从底部到中间的第二个渐变也是白色的混合色,但略暗的橙色 重点是使用了2种渐变,4种颜色,2种白色和2种橙色 我想在画布上做这个,但不知道怎么做。颜色可以是任何东西,以上只是一个例子 我该怎么做呢?我用普通的TCanvas编码 代码通过稳定增加颜色在画布上绘制渐变。例如,您可以通过向起始颜色或结束颜色添加权重(例如,增加白色部分)来调整 可以这样称呼: procedure TForm18.

请看我使用绘画程序制作的渐变图像示例:

它包含2个垂直渐变

从顶部到中间的第一个渐变是白色到浅色橙色的混合

从底部到中间的第二个渐变也是白色的混合色,但略暗的橙色

重点是使用了2种渐变,4种颜色,2种白色和2种橙色

我想在画布上做这个,但不知道怎么做。颜色可以是任何东西,以上只是一个例子


我该怎么做呢?

我用普通的TCanvas编码

代码通过稳定增加颜色在画布上绘制渐变。例如,您可以通过向起始颜色或结束颜色添加权重(例如,增加白色部分)来调整

可以这样称呼:

procedure TForm18.Button1Click(Sender: TObject);
const
  white1: TColor = clWhite;
  white2: TColor = $00CFCFCF;
  color1: TColor = $000080FF;
  color2: TColor = $00007AF4;
begin
  // pb is a TPaintbox, but this works with any canvas

  drawGradient(pb.Canvas, pb.Height, pb.Width, 0, white1, color1);
  drawGradient(pb.Canvas, pb.Height, pb.Width, pb.Height div 2, color2, white2);
end;
结果如下所示:

procedure TForm18.Button1Click(Sender: TObject);
const
  white1: TColor = clWhite;
  white2: TColor = $00CFCFCF;
  color1: TColor = $000080FF;
  color2: TColor = $00007AF4;
begin
  // pb is a TPaintbox, but this works with any canvas

  drawGradient(pb.Canvas, pb.Height, pb.Width, 0, white1, color1);
  drawGradient(pb.Canvas, pb.Height, pb.Width, pb.Height div 2, color2, white2);
end;

Delphi 2005及以上: 从抓斗装置中使用:


早期的Delphi版本: 从Msimg32.dll使用。将以下代码添加到全局实用程序单元:

type
  PTriVertex = ^TTriVertex;
  TTriVertex = record
    X, Y: DWORD;
    Red, Green, Blue, Alpha: WORD;
  end;

function GradientFill(DC: HDC; Vertex: PTriVertex; NumVertex: ULONG;
  Mesh: Pointer; NumMesh, Mode: ULONG): BOOL; stdcall; overload;
  external msimg32 name 'GradientFill';

function GradientFill(DC: HDC; const ARect: TRect; StartColor,
  EndColor: TColor; Vertical: Boolean): Boolean; overload;
const
  Modes: array[Boolean] of ULONG = (GRADIENT_FILL_RECT_H, GRADIENT_FILL_RECT_V);
var
  Vertices: array[0..1] of TTriVertex;
  GRect: TGradientRect;
begin
  Vertices[0].X := ARect.Left;
  Vertices[0].Y := ARect.Top;
  Vertices[0].Red := GetRValue(ColorToRGB(StartColor)) shl 8;
  Vertices[0].Green := GetGValue(ColorToRGB(StartColor)) shl 8;
  Vertices[0].Blue := GetBValue(ColorToRGB(StartColor)) shl 8;
  Vertices[0].Alpha := 0;
  Vertices[1].X := ARect.Right;
  Vertices[1].Y := ARect.Bottom;
  Vertices[1].Red := GetRValue(ColorToRGB(EndColor)) shl 8;
  Vertices[1].Green := GetGValue(ColorToRGB(EndColor)) shl 8;
  Vertices[1].Blue := GetBValue(ColorToRGB(EndColor)) shl 8;
  Vertices[1].Alpha := 0;
  GRect.UpperLeft := 0;
  GRect.LowerRight := 1;
  Result := GradientFill(DC, @Vertices, 2, @GRect, 1, Modes[Vertical]);
end;
现在,绘制代码变为:

procedure TForm1.FormPaint(Sender: TObject);
var
  R: TRect;
begin
  SetRect(R, 0, 0, ClientWidth, ClientHeight div 2);
  GradientFill(Canvas.Handle, R, clWhite, $00056AFF, True);
  SetRect(R, 0, ClientHeight div 2, ClientWidth, ClientHeight); 
  GradientFill(Canvas.Handle, R, $000055FF, clWhite, True);
end;

procedure TForm1.FormResize(Sender: TObject);
begin
  Invalidate;
end;

我喜欢在TCanvas上使用类助手,因此我修改了另一个答案中的代码

type
  TTriVertex = record
  public
    type
      P = ^TTriVertex;
  public
    X, Y: DWORD;
    Red, Green, Blue, Alpha: WORD;
    constructor Create(APoint: TPoint; AColor: TColor; AAlpha: Word = 0);
  end;

  TTriVertexRect = record
  public
    TopLeft: TTriVertex;
    LowerRight: TTriVertex;
    constructor Create(ARect: TRect; Color1,Color2; AAlpha1: Word = 0; AAlpha2: Word = 0);
  end;
 {Enumerate the constants so they will show up on alt space in the IDE}
 TGradientFillType = (
     gftRectH = GRADIENT_FILL_RECT_H
    ,gftRectV = GRADIENT_FILL_RECT_V
    ,gftTriangle = GRADIENT_FILL_TRIANGLE);

 TCavas_Helper = class helper for TCanvas
  public
    function GradientFill(const Vertexes: array of TTriVertexRect; FillType: TGradientFillType): Boolean; overload;
  end;

{ TTriVertex }

constructor TTriVertex.Create(APoint: TPoint; AColor: TColor; AAlpha: Word = 0);
begin
  X := APoint.X;
  Y := APoint.Y;
  Red := GetRValue(ColorToRGB(AColor)) SHL 8;
  Green := GetGValue(ColorToRGB(AColor)) SHL 8;
  Blue := GetBValue(ColorToRGB(AColor)) SHL 8;
  Alpha := 0;
end;

{ TTriVertexRect }

constructor TTriVertexRect.Create(ARect: TRect; Color1, Color2: TColor; AAlpha1,
  AAlpha2: Word);
begin
  TopLeft.Create(ARect.TopLeft,Color1,AAlpha1);
  LowerRight.Create(ARect.BottomRight,Color2,AAlpha2);
end;

{ TCavas_Helper }

function TCavas_Helper.GradientFill(const Vertexes: array of TTriVertexRect; FillType: TGradientFillType): Boolean;
var
  GRect: array of TGradientRect;
  Index: Integer;
begin
  SetLength(GRect,Length(Vertexes));
  for Index := 0 to Length(GRect) do begin
    GRect[Index].UpperLeft := Index*2;
    GRect[Index].LowerRight := Index*2 + 1;
  end;
  Result := WIndows.GradientFill(Handle,@Vertexes[0],Length(Vertexes)*2,@GRect[0],Length(GRect),Ord(FillType))
end;
所以实际的通话是这样的

procedure TForm56.FormPaint(Sender: TObject);
begin
  Canvas.GradientFill([
      TTriVertexRect.Create(Rect(0,0,ClientWidth,ClientHeight DIV 2),clWhite,$00056AFF)
     ,TTriVertexRect.Create(Rect(0,ClientHeight DIV 2,ClientWidth,ClientHeight),$00056AFF,clWhite)
    ],gftRectV);
end;
样本:


找到一个代码来制作双色渐变,并从顶部到橙色绘制一个,从橙色到白色绘制第二个?您使用哪种类型的画布?GDI+或Direct2D?@TLama这就是这种渐变双色的名称?@teran只是普通的TCanvas,如窗体或画框等,+1看起来非常好,谢谢Chris。我将尝试一下,可能还有一些关于代码等的问题要问。为了更好地理解,我添加了一些注释(并修复了一个错误,我在末尾使用了
pb.Width
,并用一个额外的参数替换)你能给我推荐一些关于图形的好文章吗。上面你贴的我仍然觉得很难理解,即使有评论。我需要先了解基本知识,然后才能理解您的解决方案是如何工作的:)老实说,我真的不知道有哪篇文章可以推荐。上面的代码基本上是一些相当简单的数学运算(它在每行的颜色值上添加一个固定的数字)。我相信你会发现一些使用谷歌的好文章(例如,看起来不错)已经有了
GradientFill
的包装器。在
GraphUtil.pas中
:。你可以用类似的方法,一个电话也只是一条线。但是,如果你可以自己编写代码,那么乐趣何在;-)@Chris这并不是因为我喜欢编写已经完成的代码,但是旧的Delphi版本没有这样的例程。如果WinAPI代码比手工编写的Delphi代码快一个数量级,我也不会感到惊讶。@TLama:我同意你的观点,修改后的答案会更好。如果他不想对梯度做任何修改,他应该使用这个答案。这看起来真的很平滑。我不想从你身上夺走荣誉,克里斯,因为你也做得很好,但如果这个方法更好,我会重新接受。谢谢你们两位提供的解决方案:)谢谢你们发布这个问题的答案!代码只回答堆栈溢出问题,因为没有上下文的代码转储无法解释解决方案的工作方式或原因,使原始海报(或任何未来读者)无法理解其背后的逻辑。请编辑您的问题,并对您的代码进行解释,以便其他人可以从您的答案中受益。此信息已在3年前的一篇帖子中发布(附有完整解释)。在完全没有解释和补充细节的情况下,简单地复制这些信息的目的是什么?
type
  TTriVertex = record
  public
    type
      P = ^TTriVertex;
  public
    X, Y: DWORD;
    Red, Green, Blue, Alpha: WORD;
    constructor Create(APoint: TPoint; AColor: TColor; AAlpha: Word = 0);
  end;

  TTriVertexRect = record
  public
    TopLeft: TTriVertex;
    LowerRight: TTriVertex;
    constructor Create(ARect: TRect; Color1,Color2; AAlpha1: Word = 0; AAlpha2: Word = 0);
  end;
 {Enumerate the constants so they will show up on alt space in the IDE}
 TGradientFillType = (
     gftRectH = GRADIENT_FILL_RECT_H
    ,gftRectV = GRADIENT_FILL_RECT_V
    ,gftTriangle = GRADIENT_FILL_TRIANGLE);

 TCavas_Helper = class helper for TCanvas
  public
    function GradientFill(const Vertexes: array of TTriVertexRect; FillType: TGradientFillType): Boolean; overload;
  end;

{ TTriVertex }

constructor TTriVertex.Create(APoint: TPoint; AColor: TColor; AAlpha: Word = 0);
begin
  X := APoint.X;
  Y := APoint.Y;
  Red := GetRValue(ColorToRGB(AColor)) SHL 8;
  Green := GetGValue(ColorToRGB(AColor)) SHL 8;
  Blue := GetBValue(ColorToRGB(AColor)) SHL 8;
  Alpha := 0;
end;

{ TTriVertexRect }

constructor TTriVertexRect.Create(ARect: TRect; Color1, Color2: TColor; AAlpha1,
  AAlpha2: Word);
begin
  TopLeft.Create(ARect.TopLeft,Color1,AAlpha1);
  LowerRight.Create(ARect.BottomRight,Color2,AAlpha2);
end;

{ TCavas_Helper }

function TCavas_Helper.GradientFill(const Vertexes: array of TTriVertexRect; FillType: TGradientFillType): Boolean;
var
  GRect: array of TGradientRect;
  Index: Integer;
begin
  SetLength(GRect,Length(Vertexes));
  for Index := 0 to Length(GRect) do begin
    GRect[Index].UpperLeft := Index*2;
    GRect[Index].LowerRight := Index*2 + 1;
  end;
  Result := WIndows.GradientFill(Handle,@Vertexes[0],Length(Vertexes)*2,@GRect[0],Length(GRect),Ord(FillType))
end;
procedure TForm56.FormPaint(Sender: TObject);
begin
  Canvas.GradientFill([
      TTriVertexRect.Create(Rect(0,0,ClientWidth,ClientHeight DIV 2),clWhite,$00056AFF)
     ,TTriVertexRect.Create(Rect(0,ClientHeight DIV 2,ClientWidth,ClientHeight),$00056AFF,clWhite)
    ],gftRectV);
end;