2
votes
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  end;

  TForm2 = class(TForm)
  private
    FAppWindow: Boolean;
  protected
    procedure CreateParams(var Params: TCreateParams); override;
  public
    property AppWindow: Boolean read FAppWindow write FAppWindow;
  end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Form2 := TForm2.Create(Self);
  Form2.AppWindow := True;
  Form2.Show;
end;

procedure TForm2.CreateParams(var Params: TCreateParams);
begin
  inherited;
  if FAppWindow then begin
    Params.Style := Params.Style or WS_EX_APPWINDOW;
    Params.WndParent := 0;
  end;
end;

This doesn't work, because the window handle is created during the constructor of TForm, so CreateParams is run too early and FAppWindow is always False.

Writing a custom constructor also doesn't work since you have to eventually call the inherited constructor which creates the handle before you can save any data to the instance:

constructor TForm2.CreateAppWindow(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FAppWindow := True;
end;

Is there a way to:

  • Delay the creation of the window handle?
  • Alter the window style after creation of the window handle?
  • Recreate the window handle after the constructor has run?
  • Some other option I haven't thought of, yet?

How can I change the style of a form from the "outside" of the class?

3
Write a setter for that property that will RecreateWnd. - TLama
Or, if you don't want to re-create the window, you could do what the ChangeAppWindow internal procedure does. It sets the style by SetWindowLong inside a pair of ShowWindow calls (SW_HIDE and SW_SHOW or SW_MINIMIZE pair). I would prefer re-creation here. - TLama

3 Answers

4
votes

The simplest solution is to pass the parameter to the form in its constructor, rather than wait until it has finished being created.

That means you need to introduce a constructor for TForm2 that accepts as parameters whatever information you need to pass on in CreateParams.

Make a note of any state before you call the inherited constructor. Also, there's no need to set WS_EX_APPWINDOW when you are setting the owner to be zero.

3
votes

The nice thing about Delphi is that a derived constructor DOES NOT have to call the inherited constructor as its first statement. So you can set your FAppWindow member first, THEN call the inherited constructor to stream the DFM and create the window, eg:

procedure TForm1.FormCreate(Sender: TObject);
begin
  Form2 := TForm2.CreateAppWindow(Self);
  Form2.Show;
end;

constructor TForm2.CreateAppWindow(AOwner: TComponent);
begin
  FAppWindow := True;
  inherited Create(AOwner);
end;
1
votes

This seems to work to recreate the handle, I got the idea from the RecreateAsPopup VCL method:

procedure TForm2.SetAppWindow(const Value: Boolean);
begin
  FAppWindow := Value;
  if HandleAllocated then
    RecreateWnd
  else
    UpdateControlState;
end;