Delphi +透明表单与父级

时间:2009-12-04 19:13:02

标签: delphi transparency

我想创建一个表单,但只是使用它来保存图像。 (就像一个泼水形式)

要创建这样的表单,请使用以下行:

SetWindowLong(Handle, GWL_EXSTYLE, LexStyle or WS_EX_LAYERED);
UpdateLayeredWindow(Handle, 0, nil, @LBitmapSize, LBitmap.Canvas.Handle, 0,
  @LBlendFunction, ULW_ALPHA);

此图像是带透明层的PNG图像。

表单必须具有父表单,或者必须具有包含表单的表单的行为。

这就是问题,如果我在这个表单上添加一些组件,这只是不显示组件。 如果我将父表单设置为它,则会失去透明度。

但我需要在此添加组件,我需要为表单设置父级。

有人知道其他方法吗?

3 个答案:

答案 0 :(得分:2)

您不能在子窗口上使用WS_EX_LAYERED样式,例如分配了父窗体的窗体。您将不得不使用SetWindowRgn()。

答案 1 :(得分:2)

您可以尝试不直接设置Parent属性,但使用子类化...

假设TParentForm是父形式,TAlphaForm是带有图像的形式。

创建TAlphaForm实例时,将TParentForm的实例作为Owner参数传递,并在构造函数中更改所有者表单的WndProc。

接下来是TAlphaForm的示例代码:

type
  TAlphaForm = class(TForm)
  private
    FParentWndProc : TWndMethod;
    FParentForm    : TCustomForm;

    procedure HookWindowProc(var Message: TMessage);

  public
    constructor Create(AOwner : TComponent); override;
    destructor Destroy; override;
  end;

实现:

constructor TAlphaForm.Create(AOwner: TComponent);
begin
  inherited;

  if(Assigned(AOwner) and (Owner is TCustomForm)) then begin

    FParentForm := TCustomForm(Owner);
    // Subclass owner window 
    FParentWndProc := FParentForm.WindowProc;
    FParentForm.WindowProc := HookWindowProc;
    // Need to repaint to show initial picture
    if(FParentForm.HandleAllocated) then FParentForm.Invalidate;

  end else begin

    FParentForm := nil;
    FParentWndProc := nil;

  end;

end;

destructor TAlphaForm.Destroy;
begin
  if(Assigned(FParentForm)) then begin
    // Restore original WndProc and repaint to restore original look if available  
    FParentForm.WindowProc := FParentWndProc;
    if(FParentForm.HandleAllocated) then FParentForm.Invalidate;
    FParentForm := nil;
    FParentWndProc := nil;
  end;
  inherited;
end;

procedure TAlphaForm.HookWindowProc(var Message: TMessage);
begin

  if( not (Assigned(FParentForm) and Assigned(FParentWndProc)) )
    then exit;

  FParentWndProc(Message);

  if(Message.Msg = WM_PAINT) then begin
    // Paint alpha image here on Owner's form canvas
    // Here is sample painting
    FParentForm.Canvas.Pen.Width := 3;
    FParentForm.Canvas.Pen.Color := clRed;
    FParentForm.Canvas.Ellipse(FParentForm.ClientRect);
  end else if(Message.Msg = WM_SIZE) then begin 
    // Needed because the whole form must be repainted
    FParentForm.Invalidate;
  end;

end;

对我来说,解决方案适用于此父表单代码:

type
  TForm1 = class(TForm)
    Button2: TButton;
    Button3: TButton;
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { Private declarations }
    FAlpha : TForm;
  public
    { Public declarations }
    constructor Create(AOwner : TComponent); override;
  end;

实现:

procedure TForm1.Button2Click(Sender: TObject);
begin
  if(not Assigned(FAlpha)) then FAlpha := TAlphaForm.Create(Self);
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  FreeAndNil(FAlpha);
end;

constructor TForm1.Create(AOwner: TComponent);
begin
  inherited;
  FAlpha := nil;
end;

答案 2 :(得分:0)

假设同一个应用程序中的两个表单,您是否尝试过构建一个可以作为选项处理程序的公共方法?类似的东西:

function TForm1.UpdateForm(Action: Integer/[Enumerated Type]/[etc]; Parameters: TStringList): Boolean;

在里面有适当的处理代码可以得到你所需要的,而不必诉诸api回调或需要处理信息。