How can i create a \"drop-down\" window using Delphi?
Everything beyond this point is research effort; and is in no way related to the answer.
How can i create a "drop-down" window using Delphi?
You put together all the bits and pieces you have summarized, there is no one VCL class/function that would produce a drop down form.
There are a few points to mention in your research though.
First, you're confusing activation with focus. Focus is not preserved in the calling form when another window pops in front of it, activation is - or it seems that way. Focus is where keyboard input goes, it is obviously on either the popped/dropped window or on a control in it.
Your problem with controls not showing with AnimateWindow
is that, VCL does not create underlying native (OS) controls of TWinControl
s until it is necessary (non-wincontrols are not a problem). As far as VCL is concerned, creating them is not normally necessary until they will be visible, which is when you set Visible
of your form to true (or call Show
), which you cannot since then there will be no animation, unless of course you set visible
after the animation.
This is also the missing requirement when you try to refresh your form:
AnimateWindow(Self.Handle, 200, AW_VER_POSITIVE or AW_SLIDE or AW_ACTIVATE);
Self.Repaint;
Self.Update;
Self.Invalidate;
Notice that in the above quote from the question, none of the calls fail. But there's nothing to paint, the form is not even visible
yet.
Any means of forcing the controls to be created and making them visible will make your animation come alive.
...
if comboBoxAnimation then
begin
for i := 0 to ControlCount - 1 do
if Controls[i] is TWinControl and Controls[i].Visible and
not TWinControl(Controls[i]).HandleAllocated then begin
TWinControl(Controls[i]).HandleNeeded;
SetWindowPos(TWinControl(Controls[i]).Handle, 0, 0, 0, 0, 0,
SWP_NOSIZE or SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE or
SWP_SHOWWINDOW);
end;
AnimateWindow(Handle, 200, AW_VER_POSITIVE or AW_SLIDE or AW_ACTIVATE);
Visible := True; // synch VCL
end
else
...
This is just an example, showing the form off-screen or any other creative method could work equally well. Here, in this answer, I achieve the same by setting animated form's height to '0' before setting visible
to true (I like the approach in this answer better though..).
Regarding not dropping again when the form is already dropped down, you don't have to post a message to the calling form for that. In fact don't do that, it requires unnecessary cooperation from the calling form. There will ever be only one instance to be dropped down, so you can use a global:
TfrmPopup = class(TForm)
...
procedure FormDestroy(Sender: TObject);
private
FNotificationParentWnd: HWND;
class var
FDroppedDown: Boolean;
protected
...
procedure TfrmPopup.Show(Owner: TForm; NotificationParentWindow: HWND;
...
if not FDroppedDown then begin
if comboBoxAnimation then begin
// animate as above
Visible := True; // synch with VCL
FDroppedDown := True;
end
else
inherited Show;
end;
end;
procedure TfrmPopup.FormDestroy(Sender: TObject);
begin
FDroppedDown := False;
end;