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;
Related
I need that "x" button on any form would not close the form but instead open another 3 random forms on delphi, i have no idea how to do that, please help
Just use the form's OnCloseQuery event to detect the user's trying to close your form (by clicking the close button in the top-right corner, by double-clicking the form's title bar icon, by selecting the Close system menu item, by pressing Alt+F4, etc.).
Then set CanClose to False and instead open your three new forms:
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
CanClose := False;
Form2.Show;
Form3.Show;
Form4.Show;
end;
As suggested by #AndreasRejbrand's answer, you could use the Form's OnCloseQuery event. But, the problem with that approach is that the event is also triggered during system reboot/shutdown, and you don't want to block that. If OnCloseQuery returns CanClose=False during a system shutdown, the shutdown is canceled.
Another option is to use the Form's OnClose event instead, setting its Action parameter to caNone, eg:
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caNone;
Form2.Show;
Form3.Show;
Form4.Show;
end;
However, the best option would to be to handle only user-initiated closures (the X button, ALT-F4, etc) by having the Form handle the WM_SYSCOMMAND message looking for SC_CLOSE notifications, eg:
procedure TForm1.WndProc(var Message: TMessage);
begin
if (Message.Msg = WM_SYSCOMMAND) and (Message.WParam and $FFF0 = SC_CLOSE) then
begin
Message.Result := 0;
Form2.Show;
Form3.Show;
Form4.Show;
end
else
inherited;
end;
This way, system-initiated closures are unhindered.
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
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'm working with Delphi 7 code to ensure that comments are entered on a tab have been saved before users can switch tabs.
The tabs are located on a TPageControl, and this code is triggered OnExit
procedure TfCallerInfo.tsChaplainExit(Sender: TObject);
begin
{ Compare the saved DB value with the text in the comments field }
if (dmMain.qChaplainCOMMENTS.AsString <> dbmChapComments.Text) then
begin
ShowMessage ('Please save the comments before proceeding.');
pcDetail.ActivePage := tsChaplain; // Remain on the Current Page
tsChaplain.SetFocus;
end;
end;
When users click on another tab tsInfoRequest for instance, the validation does trigger, but the Active Page becomes tsInfoRequest instead of remaining tsChaplain.
Any idea what I'm doing wrong?
There's probably a better way to do what you're trying to do. Use the TPageControl.OnPageChanging event instead.
procedure TfCallerInfo.pcDetailPageChanging(Sender: TObject;
NewPage: TTabSheet; var AllowChange: Boolean);
begin
if pc.ActivePage = tsChaplain then
begin
AllowChange := (dmMain.qChaplainCOMMENTS.AsString = dbmChapComments.Text);
if not AllowChange then
ShowMessage(...);
end;
end;
By the way, a better test might be
AllowChange := not dmMain.gChaplainCOMMENTS.Modified;
TField.Modified is set to True when the content of the field is changed when it's DataSet is in dsEdit or dsInsert mode, and set to False when it's state changes back to dsBrowse.
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.