开发者

Delphi + Transparent forms with parent

I want to create a form, but just use it to keep an image. (Like a splash form)

To create a form like these I use these lines:

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

This image is a PNG image with transparent layer.

The form must have a parent form or must have the behavior of a form that have it.

That is the 开发者_C百科problem, if I add some component on this form, this just doesn't show the component. And if I set a parent form to it, this lose its transparency.

But I need to add components in this and I need to set a parent to the form.

Some one knows other way to do this?


You can try not set Parent property directly but use subclassing ...

Suppose TParentForm is parent form and TAlphaForm is form with image.

When creating TAlphaForm instance, pass instance of TParentForm as Owner parameter and change WndProc of owner form in constructor.

Next is example code for 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;

Implementation:

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;

For me solution works with this parent form code:

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;

Implementation:

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;


You can't use the WS_EX_LAYERED style on child windows, such as a Form with a Parent assigned. You will have to use SetWindowRgn() instead.


Assuming both forms inside the same application, have you tried building a public method that can act as a handler for your options? Something like:

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

with appropriate handling code inside should get you what you need without having to resort to api callbacks or requiring handle information.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜