You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Delphi VCL中实现半透明面板(支持在半透明表面添加不透明组件)

在VCL中实现半透明面板(支持不透明子控件)

在VCL框架里确实没有FireMonkey那种直接给TPanel设置Opacity属性的便捷方式,但完全可以通过原生Windows API和VCL的自定义绘制机制来实现,而且能保证面板上的子控件保持不透明状态。下面是两个不需要第三方组件的可行方案:


方案一:基于GDI+的自定义半透明面板

这个方案通过继承TPanel,重写绘制方法,使用GDI+来渲染半透明背景,子控件会正常独立渲染,不受面板透明度影响。

实现步骤

  1. 新建一个Delphi单元,创建继承自TPanel的自定义组件TSemiTransparentPanel
  2. 添加Opacity属性(取值范围0-255,0为完全透明,255为完全不透明)
  3. Paint方法中用GDI+绘制半透明背景,同时保留面板原有的边框/标题绘制

完整代码示例

unit SemiTransparentPanel;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Winapi.GDIPAPI, Winapi.GDIPOBJ;

type
  TSemiTransparentPanel = class(TPanel)
  private
    FOpacity: Byte;
    procedure SetOpacity(Value: Byte);
  protected
    procedure Paint; override;
  public
    constructor Create(AOwner: TComponent); override;
  published
    property Opacity: Byte read FOpacity write SetOpacity default 128;
  end;

implementation

constructor TSemiTransparentPanel.Create(AOwner: TComponent);
begin
  inherited;
  FOpacity := 128; // 默认半透明值
  DoubleBuffered := True; // 启用双缓冲减少闪烁
end;

procedure TSemiTransparentPanel.SetOpacity(Value: Byte);
begin
  if FOpacity <> Value then
  begin
    FOpacity := Value;
    Invalidate; // 触发重绘
  end;
end;

procedure TSemiTransparentPanel.Paint;
var
  Graphics: TGPGraphics;
  SolidBrush: TGPSolidBrush;
  TransparentColor: TGPColor;
  ClientArea: TRect;
begin
  // 先绘制面板原生的边框和标题(如果启用了相关样式)
  inherited Paint;

  // 计算客户区(留出边框的位置)
  ClientArea := ClientRect;
  InflateRect(ClientArea, -1, -1);

  // 初始化GDI+绘图对象
  Graphics := TGPGraphics.Create(Canvas.Handle);
  try
    // 创建带透明度的纯色画刷,基于面板的Color属性
    TransparentColor := MakeColor(FOpacity, Color.R, Color.G, Color.B);
    SolidBrush := TGPSolidBrush.Create(TransparentColor);
    try
      // 填充半透明背景
      Graphics.FillRectangle(SolidBrush, ClientArea.Left, ClientArea.Top, ClientArea.Width, ClientArea.Height);
    finally
      SolidBrush.Free;
    end;
  finally
    Graphics.Free;
  end;
end;

end.

优缺点

  • ✅ 子控件完全不透明,独立渲染
  • ✅ 支持自定义面板颜色的半透明效果
  • ❌ 需要依赖GDI+(Windows XP及以上系统默认自带,无需额外部署)

方案二:基于Win32 AlphaBlend API的实现

这个方案纯用Win32 API实现,不依赖GDI+,兼容性更好,原理是先将面板内容绘制到内存DC,再通过AlphaBlend函数半透明渲染到面板上。

实现步骤

  1. 同样继承TPanel创建自定义组件
  2. 添加Opacity属性,重写PaintWM_ERASEBKGND消息处理(避免背景擦除导致闪烁)
  3. 使用内存DC和AlphaBlend API实现半透明绘制

完整代码示例

unit SemiTransparentPanel2;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls;

type
  TSemiTransparentPanel = class(TPanel)
  private
    FOpacity: Byte;
    procedure SetOpacity(Value: Byte);
  protected
    procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
    procedure Paint; override;
  public
    constructor Create(AOwner: TComponent); override;
  published
    property Opacity: Byte read FOpacity write SetOpacity default 128;
  end;

implementation

constructor TSemiTransparentPanel.Create(AOwner: TComponent);
begin
  inherited;
  FOpacity := 128;
  DoubleBuffered := True;
end;

procedure TSemiTransparentPanel.SetOpacity(Value: Byte);
begin
  if FOpacity <> Value then
  begin
    FOpacity := Value;
    Invalidate;
  end;
end;

procedure TSemiTransparentPanel.WMEraseBkgnd(var Message: TWMEraseBkgnd);
begin
  // 禁止系统擦除背景,避免闪烁和半透明绘制冲突
  Message.Result := 1;
end;

procedure TSemiTransparentPanel.Paint;
var
  MemDC: HDC;
  MemBitmap: HBITMAP;
  OldBitmap: HBITMAP;
  BlendParams: TBlendFunction;
  ClientRect: TRect;
begin
  ClientRect := Self.ClientRect;

  // 创建兼容内存DC和位图
  MemDC := CreateCompatibleDC(Canvas.Handle);
  MemBitmap := CreateCompatibleBitmap(Canvas.Handle, ClientRect.Width, ClientRect.Height);
  OldBitmap := SelectObject(MemDC, MemBitmap);
  try
    // 将面板原生内容绘制到内存DC
    inherited PaintTo(MemDC, 0, 0);

    // 设置Alpha混合参数
    BlendParams.BlendOp := AC_SRC_OVER;
    BlendParams.BlendFlags := 0;
    BlendParams.SourceConstantAlpha := FOpacity;
    BlendParams.AlphaFormat := AC_SRC_ALPHA;

    // 将内存DC的内容半透明渲染到面板
    AlphaBlend(Canvas.Handle, ClientRect.Left, ClientRect.Top, ClientRect.Width, ClientRect.Height,
      MemDC, 0, 0, ClientRect.Width, ClientRect.Height, BlendParams);
  finally
    // 清理资源
    SelectObject(MemDC, OldBitmap);
    DeleteObject(MemBitmap);
    DeleteDC(MemDC);
  end;
end;

end.

优缺点

  • ✅ 纯Win32 API实现,兼容性极佳
  • ✅ 子控件不受半透明影响,正常显示
  • ✅ 无需额外依赖库

注意事项

  1. 一定要开启DoubleBuffered := True,否则会出现严重的绘制闪烁
  2. Opacity属性取值0-255,如果你习惯FireMonkey的0-1浮点范围,可以自己修改属性类型为Single,然后转换为0-255的字节值
  3. 如果面板上有大量子控件,建议开启VCL全局双缓冲(在项目选项中启用)
  4. 两个方案都支持在面板上放置任何VCL控件(如TButtonTEditTLabel等),这些控件会保持完全不透明

内容的提问来源于stack exchange,提问作者Xel Naga

火山引擎 最新活动