Delphi FMX FormStyle StayOnTop only while app is active - delphi

Delphi 10.4 FMX desktop project
I create a form and set its FormStyle to StayOnTop. The window works as expected, staying on top of other windows in the project.
But when the app goes into the background, this form stays on top of all other apps. How do get this window to go into the background like all the other windows in the project?

did you try to make OnActivate and OnDeactivate on **MainForm** ? :
procedure TForm1.FormActivate(Sender: TObject);
begin
if Assigned(Form2) then
Form2.FormStyle := TFormStyle.StayOnTop;
end;
procedure TForm1.FormDeactivate(Sender: TObject);
begin
if Assigned(Form2) then
Form2.FormStyle := TFormStyle.Normal;
end;

Related

Delphi 7 opendialog has garbage in filename when used in Windows 10

This is my first post here so please forgive me if I am not doing it right.
I am using Delphi 7 on my Windows 10 machine. When I use the TOpenDialog I get garbage in the filename property on close. This is what I get back þƒ‡uÔÁ™ßðæRw. I created a simple form with a button and a edit box to show the problem here. Could someone please assist me.
The code is below.
procedure TForm1.Button1Click(Sender: TObject);
begin
opendialog1.Execute();
end;
procedure TForm1.OpenDialog1Close(Sender: TObject);
begin
edit1.Text := opendialog1.FileName;
end;
Don't use the OnClose event of the dialog. That is invoked after the underlying dialog object, which owns the file name data, has been destroyed.
Instead respond to the dialog when Execute returns.
procedure TForm1.Button1Click(Sender: TObject);
begin
if opendialog1.Execute() then
edit1.Text := opendialog1.FileName;
end;
Note that you must also test the return value of Execute to handle the user cancelling the dialog.

Clear TEdit control rad studio delphi

When use TEdit control on the right side stay small icon 'x'. How after click on icon clear TEdit box.
Tnx all!
Delphi provide TClearEditButton to clear the TEdit content. It can be added by right clicking and selecting AddItem - TClearEditButton from the popup menu. It also has a Click procedure overriden in FMX.Edit unit like:
procedure TClearEditButton.Click;
var
EditTmp: TCustomEdit;
begin
inherited Click;
EditTmp := GetEdit;
if EditTmp <> nil then
begin
if EditTmp.Observers.IsObserving(TObserverMapping.EditLinkID) then
if not TLinkObservers.EditLinkEdit(EditTmp.Observers) then
Exit; // Can't change
EditTmp.Text := string.Empty;
if EditTmp.Observers.IsObserving(TObserverMapping.EditLinkID) then
TLinkObservers.EditLinkModified(EditTmp.Observers);
if EditTmp.Observers.IsObserving(TObserverMapping.ControlValueID) then
TLinkObservers.ControlValueModified(EditTmp.Observers);
end;
end;
Which make you don't need to write OnClick event handler for the TClearEditButton unless you want to do some other job along side with clearing the edit.
If you are using a TEditButton then you should write the OnClick event handler like:
procedure TForm1.EditButton1Click(Sender: TObject);
begin
Edit1.Text:= EmptyStr;
end;

Delphi Vcl Metro application issue when minimizing then maximizing application

I've written a Vcl Metro application with several forms that I have to open sequentially.
I'm using Rad Studio 10.1 Berlin
I've added a button on every form to miminize application if user need it.
The issue happens when:
1) Open main form
2) Open second form
3) Open third form
4) Minimize application
5) Restore application.
At point 5 (when click on desktop bar to maximize application) the application will show Form2 instead of form3
The code
//On Main form (Form1)
procedure TForm1.Button2Click(Sender: TObject);
begin
if not Assigned(form2) then
form2:=tform2.Create(self);
form2.show;
form2.BringToFront;
end;
//On Second form (Form2)
procedure TForm2.Button2Click(Sender: TObject);
begin
if not Assigned(form3) then
form3:=tform3.Create(self);
form3.show;
form3.BringToFront;
end;
//On third Form
procedure TForm3.Button1Click(Sender: TObject);
begin
APPLICATION.Minimize;
end;

SDI application with multiple instances shown on taskbar

I've created an SDI application using the Delphi Berlin VCL template. I can create additional instances by programming File|New as follows:
procedure TSDIAppForm.FileNew1Execute(Sender: TObject);
var
LNewDoc: TSDIAppForm;
begin
LNewDoc := TSDIAppForm.Create(Application);
LNewDoc.Show;
end;
Only the owner form shows on the taskbar. Also, closing the owner form closes all the instances. How do I unlink the additional instances so that they operate independently and show individually on the taskbar?
Closing the TForm that is assigned as the Application.MainForm exits the app, that is by design.
If you want the MainForm to act like any other SDI window and be closed independently without exiting the app if other SDI windows are still open, you will have to create a separate TForm to act as the real MainForm and then hide it from the user (set Application.ShowMainForm to false at startup before Application.Run() is called), and then you can create TSDIAppForm objects as needed. When the last TSDIAppForm object is closed, you can then close the MainForm, or call Application.Terminate() directly, to exit the app.
To give each TSDIAppForm its own Taskbar button, you need to override the virtual CreateParams() method:
How can I get taskbar buttons for forms that aren't the main form?
Try this:
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TMyRealMainForm, MyRealMainForm);
Application.CreateForm(TSDIAppForm, SDIAppForm);
SDIAppForm.Visible := True;
Application.ShowMainForm := False;
Application.Run;
end.
procedure TSDIAppForm.CreateParams(var Params: TCreateParams);
begin
inherited;
Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
Params.WndParent := 0;
end;
procedure TSDIAppForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
end;
procedure TSDIAppForm.FormDestroy(Sender: TObject);
begin
if Screen.FormCount = 2 then // only this Form and the MainForm
Application.Terminate;
end;
procedure TSDIAppForm.FileNew1Execute(Sender: TObject);
var
LNewDoc: TSDIAppForm;
begin
LNewDoc := TSDIAppForm.Create(Application);
LNewDoc.Show;
end;

How to not have a MainForm in Delphi?

i've been trying to get some modeless forms in my application to appear on the taskbar - taking advantage of the new useful taskbar in Windows 7.
There's are many issues with the VCL that need to be undone before a form can exist on the taskbar.
But the final issue is that minimizing the form that the VCL has designated the main form causes all windows in the application to vanish.
Ten years ago, Peter Below (TeamB) documented these problems, and attempts to work around them. But there are some issues that cannot be solved. The issues run so deep within the VCL itself, that it's effectively impossible to make Delphi applications behave properly.
It all stems from the fact that the button you see on the toolbar does not represent the application's window; it represents the TApplications window, which is hidden and never seen. And then there is the application's MainForm, which is then imbued with special abilities where if it is minimized then it instructs the application to hide itself.
It seems to me that if i can do
Application.MainForm := nil;
then all these bugs would go away. The application can have its hidden window, and in the meantime i'll override every other form in the application, including my main form, with:
procedure TForm2.CreateParams(var params: TCreateParams );
begin
inherited CreateParams(params);
params.ExStyle := params.ExStyle or WS_EX_APPWINDOW;
end;
But in Delphi the Application.MainForm property is read-only.
How can i not have a MainForm in Delphi?
See also
(stackoverflow) Delphi: What is Application.Handle?
(newsgroup) Hiding Main Window but not child
You cannot run a GUI project without a MainForm assigned. The main message loop will exit immediately without one. However, that does not mean that the MainForm has to run your UI. You can use a blank hidden TForm as the assigned MainForm, and then have it instantiate your real MainForm as a secondary TForm. For example:
HiddenMainFormApp.dpr:
project HiddenMainFormApp;
uses
..., Forms, HiddenMainForm;
begin
Application.Initialize;
Application.CreateForm(THiddenMainForm, MainForm);
Application.ShowMainForm := False;
Application.Run;
end.
HiddenMainForm.cpp:
uses
..., RealMainForm;
procedure THiddenMainForm.FormCreate(Sender: TObject);
begin
RealMainForm := TRealMainForm.Create(Self);
RealMainForm.Show;
end;
RealMainForm.cpp:
procedure TRealMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
Application.Terminate;
end;
Alternatively:
HiddenMainFormApp.dpr:
project HiddenMainFormApp;
uses
..., Forms, HiddenMainForm, RealMainForm;
begin
Application.Initialize;
Application.CreateForm(THiddenMainForm, MainForm);
Application.ShowMainForm := False;
RealMainForm := TRealMainForm.Create(Application);
RealMainForm.Show;
RealMainForm.Update;
Application.Run;
end.
RealMainForm.cpp:
procedure TRealMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
Application.Terminate;
end;
You can't, especially in Delphi 5.
Your quote concerning the TApplication window being the one seen on the task bar hasn't been true for several Delphi versions now (I believe D2007 changed it).
Because you're using Delphi 5, you're using an outdated copy of Delphi; current versions have almost none of the things you're writing about any longer. I'd suggest you upgrade to a later version of Delphi (D5 is extremely old); Delphi 2007 if you need to avoid Unicode, Delphi XE if you can use (or don't mind having) Unicode support in the VCL and RTL.
The things you're describing are not bugs, BTW. They were intentional design decisions made at the time Delphi 1 was being designed, and through Delphi 7 worked fine with the versions of Windows that were available. Changes in later versions of Windows (XP/Vista/Win7 and the equivalent Server versions) made changes in that architecture necessary, and they were made as Delphi progressed along with Windows. Because you've chosen not to progress with your version of Delphi to keep it more recent doesn't make the things you write about magically become bugs. :-)
Having Application.MainForm assigned seems not to be a problem here for showing another modeless form on the taskbar while minimizing the MainForm.
Project1.dpr:
program Project1;
uses
Forms,
Windows,
Unit1 in 'Unit1.pas' {MainForm},
Unit2 in 'Unit2.pas' {Form2};
{$R *.res}
var
MainForm: TMainForm;
begin
Application.Initialize;
Application.CreateForm(TMainForm, MainForm);
ShowWindow(Application.Handle, SW_HIDE);
Application.Run;
end.
Unit1.pas:
unit Unit1;
interface
uses
Windows, Messages, Classes, Controls, Forms, StdCtrls, Unit2;
type
TMainForm = class(TForm)
ShowForm2Button: TButton;
ShowForm2ModalButton: TButton;
procedure ShowForm2ButtonClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure ShowForm2ModalButtonClick(Sender: TObject);
private
FForm2: TForm2;
procedure ApplicationActivate(Sender: TObject);
procedure Form2Close(Sender: TObject; var Action: TCloseAction);
procedure WMSysCommand(var Msg: TWMSysCommand); message WM_SYSCOMMAND;
protected
procedure CreateParams(var Params: TCreateParams); override;
end;
implementation
{$R *.dfm}
procedure TMainForm.FormCreate(Sender: TObject);
begin
Visible := True; //Required only for MainForm, can be set designtime
Application.OnActivate := ApplicationActivate;
end;
procedure TMainForm.ApplicationActivate(Sender: TObject);
{ Necessary in case of any modal windows dialog or modal Form active }
var
TopWindow: HWND;
I: Integer;
begin
TopWindow := 0;
for I := 0 to Screen.FormCount - 1 do
begin
Screen.Forms[I].BringToFront;
if fsModal in Screen.Forms[I].FormState then
TopWindow := Screen.Forms[I].Handle;
end;
Application.RestoreTopMosts;
if TopWindow = 0 then
Application.BringToFront
else
SetForegroundWindow(TopWindow);
end;
procedure TMainForm.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
with Params do
begin
ExStyle := ExStyle or WS_EX_APPWINDOW;
WndParent := GetDesktopWindow;
end;
end;
procedure TMainForm.WMSysCommand(var Msg: TWMSysCommand);
begin
if Msg.CmdType = SC_MINIMIZE then
ShowWindow(Handle, SW_MINIMIZE)
else
inherited;
end;
{ Testing code from here }
procedure TMainForm.ShowForm2ButtonClick(Sender: TObject);
begin
if FForm2 = nil then
begin
FForm2 := TForm2.Create(Application); //Or: AOwner = nil, or Self
FForm2.OnClose := Form2Close;
end;
ShowWindow(FForm2.Handle, SW_RESTORE);
FForm2.BringToFront;
end;
procedure TMainForm.Form2Close(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
FForm2 := nil;
end;
procedure TMainForm.ShowForm2ModalButtonClick(Sender: TObject);
begin
with TForm2.Create(nil) do
try
ShowModal;
finally
Free;
end;
end;
end.
Unit2.pas:
unit Unit2;
interface
uses
Windows, Messages, Classes, Controls, Forms;
type
TForm2 = class(TForm)
private
procedure WMSysCommand(var Msg: TWMSysCommand); message WM_SYSCOMMAND;
protected
procedure CreateParams(var Params: TCreateParams); override;
end;
implementation
{$R *.dfm}
procedure TForm2.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
with Params do
begin
ExStyle := ExStyle or WS_EX_APPWINDOW;
WndParent := GetDesktopWindow;
end;
end;
procedure TForm2.WMSysCommand(var Msg: TWMSysCommand);
begin
if Msg.CmdType = SC_MINIMIZE then
ShowWindow(Handle, SW_MINIMIZE)
else
inherited;
end;
end.
(Tested with D5 and D7 on XP and Win7.)
(And yes, you may flag this as being not an answer, because it isn't: There still is a MainForm. But I dó like to think this answers the question behind the question...)
I can't speak for Delphi 5, but in Delphi 7 you can definitely run without a mainform if you're willing to get your hands dirty. I covered a lot of the details in another answer here.
Since Delphi 5 doesn't have the MainFormOnTaskbar property, you need to do the following in your dpr:
// Hide application's taskbar entry
WasVisible := IsWindowVisible(Application.Handle);
if WasVisible then
ShowWindow(Application.Handle, SW_HIDE);
SetWindowLong(Application.Handle, GWL_EXSTYLE,
GetWindowLong(Application.Handle, GWL_EXSTYLE) or WS_EX_TOOLWINDOW);
if WasVisible then
ShowWindow(Application.Handle, SW_SHOW);
// Hide the hidden app window window from the Task Manager's
// "Applications" tab. Don't change Application.Title since
// it might get read elsewhere.
SetWindowText(Application.Handle, '');
That will hide the application window, and as long as you override your form's CreateParams to set Params.WndParent := 0 each of them will have a taskbar entry of their own. Application.MainForm isn't assigned, so things like the minimize override aren't an issue, but you do have to be careful about any code that assumes MainForm is valid.
You can put your modeless forms in a dll, then they act pretty much on their own. (If you do not use the Application instance of the dll while creating them (Application.CreateForm) then Application.Mainform is nil in the dll).
Of course this might not be feasible depending on what the forms might need to do.
Actually most of what you are complaining about is in fact the design of Windows rather than the VCL. See Windows Features for all the details.
The crux of the matter is the owner property, and I mean the windows owner rather than the VCL owner.
An owned window is hidden when
its owner is minimized.
If you wish to be able to minimise the main form without other windows being hidden then you need to get on top of how owned windows work.

Resources