I have setup my login procedure with an available form (Form4) and a MainForm.
On the available form (form4) I have:
var
Form4: TForm4;
procedure Login;
implementation
.....
The 'Login' procedure goes:
procedure Login;
begin
with TForm4.Create(nil) do
try
Application.MainForm.Hide;
if ShowModal = mrOK then
Application.MainForm.Show
else
Application.Terminate;
finally
Free;
end;
end;
Then on the same form I have a button to log in :
procedure TForm4.AdvGlowButton1Click(Sender: TObject); //the buton's property is ModalResult=mrOK
begin
DataModule2.LOGIN_QUERY.Active:=false;
DataModule2.LOGIN_QUERY.SQL.Clear;
DataModule2.LOGIN_QUERY.SQL.Add('select user,passsword from users where user='+QuotedStr(cxlookupcombobox1.text)+' and password='+QuotedStr(cxTextEdit1.Text));
DataModule2.LOGIN_QUERY.Open;
if DataModule2.LOGIN_QUERY.FieldByName('password').AsString<>''
then ModalResult := mrOK else
ModalResult := mrNone;
end;
The project source goes like this :
begin
Application.Initialize;
Application.MainFormOnTaskbar := False;
Application.CreateForm(TDataModule2, DataModule2);
Application.CreateForm(TMainForm, MainForm);
Application.CreateForm(TForm7, Form7);
Application.CreateForm(TARCHIVE, ARHCIVE);
Application.CreateForm(TForm10, Form10);
Application.CreateForm(TForm1, Form1);
Application.CreateForm(TForm6, Form6);
Application.CreateForm(TForm5, Form5);
Application.CreateForm(TForm9, Form9);
Application.CreateForm(TForm12, Form12);
Application.CreateForm(TForm12, Form12);
Application.CreateForm(TAboutBox, AboutBox);
Login;
Application.Run;
end.
Yet, every now and then when clicking the Login button on Form4 the application
terminates without no reason. Why is this happening ?
Should
Application.MainFormOnTaskbar := False;
be set to true perhaps?
Edit:
I edited the project file and the form4 on create event :
procedure TForm4.FormCreate(Sender: TObject);
begin
AdvGlowButton1.ModalResult := mrOK;
end;
and changed the project source :
{$R *.res}
var
MainForm: TMainForm;
begin
Application.Initialize;
Application.CreateForm(TMainForm, MainForm);
Application.MainFormOnTaskbar := False;
Application.CreateForm(TDataModule2, DataModule2);
Application.CreateForm(TForm7, Form7);
Application.CreateForm(TARCHIVE, ARCHIVE);
Application.CreateForm(TForm10, Form10);
Application.CreateForm(TForm1, Form1);
Application.CreateForm(TForm6, Form6);
Application.CreateForm(TForm5, Form5);
Application.CreateForm(TForm9, Form9);
Application.CreateForm(TForm12, Form12);
Application.CreateForm(TForm12, Form12);
Application.CreateForm(TAboutBox, AboutBox);
Login;
Application.Run;
end.
and I dont seem to be getting application closing....(it still does,ughh...)
edit2:
Tried this way. I set my AdvGlowButton1 to ModalResult=mrNone and the Form style to fsdialog:
procedure TForm4.AdvGlowButton1Click(Sender: TObject); //the buton's property is ModalResult=mrOK
begin
DataModule2.LOGIN_QUERY.Active:=false;
DataModule2.LOGIN_QUERY.SQL.Clear;
DataModule2.LOGIN_QUERY.SQL.Add('select user,passsword from users where user='+QuotedStr(cxlookupcombobox1.text)+' and password='+QuotedStr(cxTextEdit1.Text));
DataModule2.LOGIN_QUERY.Open;
if DataModule2.LOGIN_QUERY.FieldByName('password').AsString<>''
then ModalResult := mrOK else
dxStatusBar1.Panels[1].Text :='Wrong password !';
end;
this works most of the times and yet it sometimes closes when I start the application and hit the AdvGlowButton1 button (login button) . Another thing I figured out is missing, how do you prompt for the closure of the application on this login form as it expects only modal results?
Like #SertacAkyuz is hinting, one option would be that ShowModal does not return mrOK. Check the ModalResult value for this button and/or the event handler for the OnClick of this button to see if mrOK is the ModalResult that is returned in these cases...
If you click a button, then the OnClick event is fired and if the ModalResult of that button is set to anything, the Form's ModalResult will be set to that value. When an event (like an OnClick event) ends, the form checks its ModalResult value, and if it is set to anything other that 0 (zero), then the form closes and the value is returned as the result of the ShowModal function.
So from what information you have given, this seems like a likely scenario - the Form's ModalResult is set to some value that isn't mrOK. The form then closes, and your IF ShowModal test then terminates the application (since it didn't return mrOK).
Based on your code entering wrong password would also result in termination of your application becouse in that case the modal result returned would be mrNone and you only expecting mrOK to continue with your application.
So I recomend next changes:
First remove the modal result propery of your button. button modal result propery is mostly used only as a way to forward the information as of clicking on which specific button lead to closure of modal form.
Then change your buttons event code so that it only sets form modal result if the code is correct else it should show a message that the entered passowrd is incorect. Something like so:
procedure TForm4.AdvGlowButton1Click(Sender: TObject); //the buton's property is ModalResult=mrOK
begin
DataModule2.LOGIN_QUERY.Active:=false;
DataModule2.LOGIN_QUERY.SQL.Clear;
DataModule2.LOGIN_QUERY.SQL.Add('select user,passsword from users where user='+QuotedStr(cxlookupcombobox1.text)+' and password='+QuotedStr(cxTextEdit1.Text));
DataModule2.LOGIN_QUERY.Open;
if DataModule2.LOGIN_QUERY.FieldByName('password').AsString<>'' then
//Close the modal form with returning of mrOK as modal result
ModalResult := mrOK
else
begin
//No modal result should be set here or it would lead to closure of login form
MessageDlg('Entered password is incorect!',mtError, mbOKCancel, 0);
end;
end;
This is direct solution for your specific problem. But I would recomend you seriously reconsider your design of the whole login system. Why?
In you current design you create all the forms at the start of your application. Now while you do start with your main form hidden this still doesen't mean that your user can't access it.
Using a special software user could find a handle to your main form window and show it without going through your login process at all.
So the correct approach to avoid this would be to create the login form first and then only on sucsessfull login create the rest of your forms. But that would mean that your login form would actually become the main form of your application so you should take great care of not closing it as it would lead to the closure of your whole application.
You can check the example of how to implement such approach in my answer to another question here:
Delphi Change main form while application is running
Related
I would like to transfer data from the statusbar of Form2 (which is on the list of available forms and used for login purposes), to the statusbar on the MainForm (which is autocreated one).
If I use :
procedure TMainForm.FormShow(Sender: TObject);
begin
AdvOfficeStatusBar1.Panels[0].Text := Form2.AdvOfficeStatusBar1.Panels[0].Text;
end;
I get an access violation error. . Why is this happening? How can I get over this?
Based on your comment I would say that the following is occurring:
The code you would be using for your login form is this:
procedure Login;
begin
with TForm2.Create(nil) do
try
Application.MainForm.Hide;
if ShowModal = mrOK then
Application.MainForm.Show
else
Application.Terminate;
finally
Free;
end;
end;
What is happening here is that there is an implicit variable for TLoginForm. This is not the same as the auto created variable which would be Form2: TForm2; which sits in the TForm2 unit. This variable is freed directly after the form closes.
To see what I mean. If you delete the variable called Form2 from your application, the only part of the code that won't compile is your line in your original post.
What you would have to do if you wanted to do this sort of thing is something like this (I have changed the name of TLoginForm to your Form2).
procedure Login;
begin
Form2 := TForm2.Create(nil);
Application.MainForm.Hide;
if Form2.ShowModal = mrOK then
Application.MainForm.Show
else
begin
Form2.Free;
Application.Terminate;
end;
end;
The you would have to free your Form2 when you close your main form. I would really not recommend doing this sort of thing though. As a quick fix, you would be far better off saving the text AdvOfficeStatusBar1.Panels[0].Text in a global variable in the OnClose event of the Form2 with something like this:
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
g_MySavedVariable := AdvOfficeStatusBar1.Panels[0].Text;
end;
And then loading it in the main form with:
procedure TMainForm.FormShow(Sender: TObject);
begin
AdvOfficeStatusBar1.Panels[0].Text := g_MySavedVariable;
end;
Even this is not ideal but should get you up and running.
If you are looking for some code for a login form where you pass data between the login form and the main form then you are probably better off looking at this question in StackOverflow (delphi Login Form) along with the answers by David and Cosmin. My personal preference is for the solution by Cosmin as you don't need to mess with the DPR and there is no global variables involved.
My form1 is the mainform. I use it for login purposes and after I dont need it
I hide it. If the login is successful, on button click,form3 is called.
procedure TForm1.AdvGlowButton1Click(Sender: TObject);
begin
ABSQuery4.Active:=false;
ABSQuery4.SQL.Clear;
ABSQuery4.SQL.Add('select .....bla,bla,bla....');
ABSQuery4.Open;
if ABSQuery4.FieldByName('passsword').AsString<>''
then begin
Form3.Show;
Form1.Hide;
end else begin
cxTextedit1.Text := '';
showmessage('wrong password');
end;
end;
Now I am noticing that sometimes the event produces strange results.
Form3 is shown but Form1 remains visible also. For showing the main form
from form3 I use :
procedure TForm3.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Form1.Show;
end
Since I need the application icon for Form3, I have there :
procedure TForm3.CreateParams(var Params: TCreateParams) ;
begin
inherited;
Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
Params.WndParent := 0;
end;
Can you tell me am I messing anything up or is there a better way to
make the forms behave properly?
There is a better way to do this. For a start, you should give your forms meaningful names!
Your real problem is that your main form is being hidden because you are using it as your login form. You make life needlessly difficult and complicated by doing that.
So the main piece of advice is that you should make you real main form be the Delphi main form. The Delphi main form is the first form created using Application.CreateForm. I suggest that you call Application.CreateForm exactly once, to create the main form.
This may leave you wondering how to create other forms. Well, you just create them using the standard constructor, just like any other object.
So your .dpr file code might look like this:
Application.Initialize;
LoginForm := TLoginForm.Create(nil);
try
if LoginForm.ShowModal <> mrOK then
exit;
finally
LoginForm.Free;
end;
Application.CreateForm(TMainForm, MainForm);
Application.Run;
Once you make this change you will find that you don't need to take steps to force the main form onto the taskbar.
I have an application with a TTrayIcon Component that I use to "Hide" and "Restore" my MainForm. Here is what I use to "Hide" (OnTrayClick)
procedure TMainWindow.TrayIcon1Click(Sender: TObject);
var
I : Integer;
begin
if Application.MainForm.Visible then begin
{ Hide }
Application.MainForm.Visible := FALSE;
end else begin
{ Restore }
Application.MainForm.Visible := TRUE;
WindowState := wsNormal;
Application.BringToFront();
{ Workaround for ModalForms }
for I := 0 to Screen.FormCount-1 do begin
if (fsModal in Screen.Forms[I].FormState) then begin
Screen.Forms[I].BringToFront;
Screen.Forms[I].SetFocus;
break; // Stop looking for more ModalForms
end;
end;
end;
end;
This example works just fine if there are no other (Modal) Forms open.
But if there is a ModalForm open and restore my MainForm, the ModalForm seems to be behind the MainForm and I can't reach it. How can I activate/focus the ModalForm and put it in front of my MainForm after my MainForm has been restored? My Application.MainFormOnTaskbar is set to False
EDIT:
If a ModalForm is open and I restore my MainForm, both of the forms won't focus at all.
The setting of MainFormOnTaskbar seems to be causing the problem. You really need to keep that set to true.
You could choose to not hide any forms if there is a modal windows. In that case check for Application.ModalLevel > 0 in your hide code. You could even show a balloon hint stating that the application cannot be minimized until messages are closed.
Otherwise if you really want to minimize all windows the code below works well for me. Hide all of the open windows including the modal window. This will cause the main taskbar icon to go away and everything is off the screen. The one thing you need to do is keep track of which windows were just open. I did that below by setting the Tag value on the forms that were just hidden. Then in the restore code you can set the visible of those windows back to true.
The only case this does not deal with is hiding the main window but leaving the modal window visible. I'm not sure why you would want to do that and personally I would find that confusing as a user.
procedure TForm1.TrayIcon1Click(Sender: TObject);
var
I : Integer;
begin
if Application.MainForm.Visible then
begin
// Hide
for I := 0 to Screen.FormCount-1 do
begin
if Screen.Forms[i].Visible = true then
begin
Screen.Forms[i].Visible := false;
Screen.Forms[i].Tag := 1;
end;
end;
end
else
begin
// Restore
for I := 0 to Screen.FormCount-1 do
begin
if Screen.Forms[i].Tag = 1 then
begin
Screen.Forms[i].Visible := true;
Screen.Forms[i].Tag := 0;
end;
end;
Application.BringToFront();
end;
end;
You may need need to set the PopupParent property on the Modal Form to be your main form. This is set to pmAuto for new forms but if this is an old project it could be pmNone.
Here is a link to a blog post by Allen on PopupMode and PopupParent and here is another Stackoverflow questions that address the topic Newly created modal window loses focus and become inacessible in Windows Vista
I normally use something like this:
MyPopupForm := TMyForm.Create(Owner);
MyPopupForm.PopupMode := pmAuto;
MyPopupForm.PopupParent := Owner;
MyPopupForm.ShowModal;
I am creating one subForm from Main form on button click event of Main Form.Now On subForm I have added one button named 'OK'.ModalResult property of Button set to mrOK. On Ok button click i want to peform some validations. If there is some error i want to show it on subform and should focus on the error filed of SubForm. But I am able to show error message and after error msg displayed Subform closes and main form will be displayed. Below is part of code. Plz help me.
result:= frmAddField.showModal= mrOK; // subForm
procedure TfrmAddField.btnOKClick(Sender:TObject);
begin
if edit1.text = '' then
begin
MessageDlg('Error',mtWarning,[mbOK],0);
edit1.setfocus;
break;
end;
// to be continued
end;
Set the ModalResult property on the Button back to mrNone. Alter your event handler:
procedure TfrmAddField.btnOKClick(Sender:TObject);
begin
if edit1.text = '' then
begin
MessageDlg('Error',mtWarning,[mbOK],0);
edit1.setfocus;
end else
ModalResult := mrOK;
end;
Break is not what you want here. Use Exit if you want to leave the current function or procedure. Also make sure that you only set the modal result if you want the form to close, in your example:
procedure TfrmAddField.btnOKClick(Sender:TObject);
begin
if edit1.text = '' then
begin
MessageDlg('Error',mtWarning,[mbOK],0);
edit1.setfocus;
Exit;
end;
// to be continued
ModalResult := mrOK; // validation worked, close the form!
end;
I have a form one which I want to show a file open dialog box before the full form opens.
I already found that I can't do UI related stuff in FormShow, but it seems that I can in FormActivate (which I protect from being called a second time...)
However, if the user cancels out of the file open dialog, I want to close the form without proceeding.
But, a form close in the activate event handler generates an error that I can't change the visibility of the form.
So how does one do some UI related operation during form start up and then perhaps abort the form (or am I trying to stuff a function into the form that should be in another form?)
TIA
It would be best (i think) to show the file open dialog BEFORE you create and show the form. If you want to keep all code together you might add a public class procedure OpenForm() or something:
class procedure TForm1.OpenForm( ... );
var
O: TOpenDialog;
F: TForm1;
begin
O := TOpenDialog.Create();
try
// set O properties.
if not O.Execute then Exit
F := TForm1.Create( nil );
try
F.Filename := O.FIlename;
F.ShowModal();
finally
F.Free();
end;
finally
O.Free();
end;
end;
Set a variable as a condition of the opendialog and close the form on the formshow event if the flag is not set correctly.
procedure TForm1.FormCreate(Sender: TObject);
begin
ToClose := not OpenDialog1.Execute;
end;
procedure TForm1.FormShow(Sender: TObject);
begin
if ToClose then Close();
end;
or even more simply
procedure TForm1.FormShow(Sender: TObject);
begin
if not OpenDialog1.Execute then Close();
end;
If you want to keep the logic conditioning the opening self-contained in the Form, you can put a TOpenDialog in your Form and use a code like this in your OnShow event:
procedure TForm2.FormShow(Sender: TObject);
begin
if OpenDialog1.Execute(Handle) then
Color := clBlue
else
PostMessage(Handle, WM_CLOSE, 0, 0); // NB: to avoid any visual glitch use AlpaBlend
end;
If you don't need this encapsulation, a better alternative can be to check the condition before trying to show the form, for instance by embedding the Form2.Show call in a function that tests all the required conditions first.
Two Ways....
1. using oncreate and onactivate
create a global flag or even 2
var
aInitialized:boolean;
Set the flag to false in the oncreate handler.
aInitialized := false; //we have not performed our special code yet.
Inside onActivate have something like this
if not aInitialized then
begin
//our one time init code. special stuff or whatever
If successful
then set aInitialized := true
else aInitialized := false
end;
And how to close it without showing anything just add your terminate to the formshow. of course you need to test for some reason to close.. :)
Procedure Tmaindlg.FormShow(Sender: TObject);
Begin
If (shareware1.Sharestatus = ssExpired) or (shareware1.Sharestatus = ssTampered) Then
application.Terminate;
End;
In your DPR you will need to add a splash screen type effect. In my case I am showing progress as the application starts. You could also just show the form and get some data.
Code from the splash.pas
Procedure tsplashform.bumpit(str: string);
Begin
label2.Caption := str;
gauge1.progress := gauge1.progress + trunc(100 / items);
update;
If gauge1.progress >= items * (trunc(100 / items)) Then Close;
End;
Program Billing;
uses
Forms,
main in 'main.pas' {maindlg},
Splash in 'splash.pas' {splashform};
{$R *.RES}
Begin
Application.Initialize;
Application.Title := 'Billing Manager';
SplashForm := TSplashForm.Create(Application);
SplashForm.Show;
SplashForm.Update;
splash.items := 5;
SplashForm.bumpit('Loading Main...');
Application.CreateForm(Tmaindlg, maindlg);
SplashForm.bumpit('Loading Datamodule...');
Application.CreateForm(TfrmSingleWorkorder, frmSingleWorkorder);
SplashForm.bumpit('Loading SQL Builder...');
Application.CreateForm(TDm, Dm);
SplashForm.bumpit('Loading Security...');
Application.CreateForm(TSQLForm, SQLForm);
SplashForm.bumpit('Loading Reports...');
Application.CreateForm(Tpickrptdlg, pickrptdlg);
Application.Run;
End.