如何在画布上一起绘制2个渐变?

10 delphi

请查看我使用Paint程序执行的示例渐变图像:

在此输入图像描述

它包含2个垂直渐变.

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

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

关键是有2个渐变使用,有4种颜色,2种白色和2种橙色变化.

我想在Canvas上做这个,但不知道怎么做.颜色可以是任何颜色,上面只是一个例子.

我怎么能这样做?

NGL*_*GLN 16

Delphi 2005及以上版本:

使用GradientFillCanvasGraphUtil单位:

procedure TForm1.FormPaint(Sender: TObject);
var
  R: TRect;
begin
  SetRect(R, 0, 0, ClientWidth, ClientHeight div 2);
  GradientFillCanvas(Canvas, clWhite, $00056AFF, R, gdVertical);
  SetRect(R, 0, ClientHeight div 2, ClientWidth, ClientHeight); 
  GradientFillCanvas(Canvas, $000055FF, clWhite, R, gdVertical);
end;
Run Code Online (Sandbox Code Playgroud)

早期的Delphi版本:

使用GradientFillMSIMG32.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;
Run Code Online (Sandbox Code Playgroud)

现在,绘画代码变为:

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;
Run Code Online (Sandbox Code Playgroud)

GradientFill.png

  • @TLama:我同意你的看法,修改后的答案更好.如果他不想对渐变进行任何修改,他应该使用此答案. (3认同)
  • 这看起来非常顺利.我不想从你那里得到信任克里斯因为你也做得很好,但如果这种方法更好,我会重新接受.谢谢你们提供解决方案:) (2认同)

Chr*_*ris 7

我用普通的TCanvas编写了它.

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

procedure drawGradient(drawCanvas: TCanvas; canvasHeight, canvasWidth, canvasStartPos: Integer; startColor, endColor: TColor);
type
  RGBColor = (Blue, Green, Red);
var
  diff, startColorArray, endColorArray: array[RGBColor] of Integer;
  delta, currentColorFloat: array[RGBColor] of Double;
  gradientSize: Integer;
  currentColor: TColor;
  rgbC: RGBColor;
  i: Integer;
begin
  gradientSize := canvasHeight div 2;

  // Pre-calculate some required values for every RGB color
  for rgbC := Low(RGBColor) to High(RGBColor) do
    begin
    // Split the start end end colors into the RGB values
    // The right shift at the end shifts 16, 8 and 0 bits in the three loops
    // (I know that's a little hard to read)

    startColorArray[rgbC] := $FF and (startColor shr ((2 - Ord(rgbC)) * 8));
    endColorArray[rgbC] := $FF and (endColor shr ((2 - Ord(rgbC)) * 8));

    // Calculate the difference between the start and end color. This might be
    // a negative value, hence the declaration as Integer instead of Byte
    diff[rgbC] := startColorArray[rgbC] - endColorArray[rgbC];

    // And calculate a float value for each color. This is the increment on
    // every drawn line.
    delta[rgbC] := diff[rgbC] / gradientSize;
    end;

  // Initialize the drawn color with the start value
  currentColorFloat[Blue] := startColorArray[Blue];
  currentColorFloat[Green] := startColorArray[Green];
  currentColorFloat[Red] := startColorArray[Red];

  // Now draw the gradient line by line
  for i := 0 to gradientSize - 1 do
    begin
    // The target color as TColor
    currentColor := 0;

    for rgbC := Low(RGBColor) to High(RGBColor) do
      begin
      // Substract the decrement delta from the current color
      currentColorFloat[rgbC] := currentColorFloat[rgbC] - delta[rgbC];

      // Round the float value and left shift it to the correct position (16, 8 and 0 bits).
      // Then bitwise or it with the current color.
      currentColor := currentColor or (Round(currentColorFloat[rgbC]) shl ((2 - Ord(rgbC)) * 8));
      end;

    // Now draw a 1 pixel thin line from left to right
    drawCanvas.Pen.Color := currentColor;
    drawCanvas.MoveTo(0, i + canvasStartPos);
    drawCanvas.LineTo(canvasWidth, i + canvasStartPos);
    end;
end;
Run Code Online (Sandbox Code Playgroud)

像这样称呼它:

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;
Run Code Online (Sandbox Code Playgroud)

结果如下:

在此输入图像描述