views:

660

answers:

3

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 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?

A: 

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.

Tom
I have no idea what this is talking about. What question did you answer?
Rob Kennedy
The way I understand the original question is that the developer wishes to have a "control" form and a "display" form that will show the image after it is manipulated by the control. Something like a multiple form image editor or a karaoke display maybe?
Tom
+1  A: 

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.

Remy Lebeau - TeamB
I tried it, but it's not exactly what I need.The form must resize when necessary based on other form resize.Like it was it's parent.
SaCi
You can still use SetWindowRgn() with a resizable form. Simply call SetWindowRgn() to assign a new region each time the Form is resized.
Remy Lebeau - TeamB
hun... alright I'm gonna test it
SaCi
I set the SetWindowRgn, but it didn't limit the constraints of the form, maybe some thing I'm doing wrong ?
SaCi
A: 

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;
ThinkJet