SOLVED Impossible to close a modal window... lazarus / 10-Designer ---------------------------------------------------------------------- pjtuloup · 2024-07-03 07:43 Hello everyone... New beginner problem: I can't close a modal window. Here's how things look: My Main form (Master) calls in its FormActivate procedure a modal window used for identification. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.FormActivate(Sender: TObject);begin  FormIdentif.ShowModal;end;   In this FormIdentif form there is a "Continue" button which should close the window so that the Master file is accessible with its general menu Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TFormIdentif.Btn_ContinuerClick(Sender: TObject);begin  //Close;  //FormIdentif.Close;  //FormIdentif.ModalResult:= 1;  //FormIdentif.ModalResult:= mrOK;end;  I tried several things which don't work: either nothing happens (using ModalResult) or the application closes (with Close) I don't see what I'm missing... Can anyone point me in the right direction? Thanks in advance! ---------------------------------------------------------------------- Thaddy · 2024-07-03 07:48 You can't easily close a modal window from somewhere else. You close a modal Window from the modal window itself. That is by design. That does not mean it can not be done, but it should not be done. It is a bit useless to show you how to do it since you are a beginner. I will not show you bad practice, but someone else on this forum with less understanding of the matter will show you how to do it anyway... and he or she can count on my anger... The proverbial The easy way out for a beginner is to make the window NOT modal. ---------------------------------------------------------------------- pjtuloup · 2024-07-03 07:55 Thanks but A clarification: the procedure TFormIdentif.Btn_ContinuerClick is in the form of the modal window I want to close. ---------------------------------------------------------------------- MarkMLl · 2024-07-03 07:58 Quote from: pjtuloup on July 03, 2024, 09:43:50 amIn this FormIdentif form there is a "Continue" button which should close the window so that the Master file is accessible with its general menu Make sure that the button you've labelled "Continue" is in the context of the modal form, and is marked as having e.g. a cancel effect. Can't give a more detailed example at the moment, but would echo (perhaps more gently) Thaddy's warning that this is something that shouldn't be done from outside the form. MarkMLl ---------------------------------------------------------------------- Zvoni · 2024-07-03 08:07 I'm probably going to invoke Thaddy's Anger, but hey...no risk no fun The way i do it (No code, just "steps") 1) In your Main Form you have a var for your ModalForm 2) In your MainForm you create the ModalForm, then you ShowModal that Form --> Code-Execution in your MainForm is "stopped" as long as your ModalForm is visible (here Line 3) Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i //In TMainF ormModalForm:=TModalForm.Create;ModalForm.ShowModal;ModalForm.Close;Mo dalForm.Free; 3) In your ModalForm you have a Button (or whatever else) to close that ModalForm. I do Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TModalForm.cmdCloseClick(Sender: TObject);Begin   Self.Close;End;procedure TModalForm.FormClose(Sender: TObject;  var CloseAction: TCloseAction);begin  CloseAction:=caHide;  //THIS ONEend;     After executing above statement, code-execution returns to your MainForm to Line 4 above ...and now i have to run and hide, so Thaddy doesn't kill me... ---------------------------------------------------------------------- n7800 · 2024-07-03 08:18 I just checked and Close or ModalResult should work. But the code in the OnActivate event always bothers me. It can cause problems. For example, if you write Show instead of ShowModal in your program, the window will close, focus will switch to the first form, which will activate the OnActivate code, and it will open the second form again. This will happen very quickly and will look like it never closed. That's the first thing I thought of when I saw the event. However, for modal forms this does not cause a loop and the form closes... ---------------------------------------------------------------------- pjtuloup · 2024-07-03 08:21 Thank you very much for the advice... and taking risks. I will study this. I have to say that I am grateful for the warnings since you are experienced, but I don't understand why you say that I am trying to close a modal window from outside the form, since my "continue" button that wants to close the form is indeed in this form? ---------------------------------------------------------------------- rvk · 2024-07-03 08:22 Quote from: Thaddy on July 03, 2024, 09:48:57 amYou can't easily close a modal window from somewhere else. You close a modal Window from the modal window itself. Have I read the question wrong... or did you??? TS says (s)he want's to close the modal form IN THE MODAL FORM itself via a button TFormIdentif.Btn_ContinuerClick. The only problem I see with the code is that it calls the instance variable itself "FormIdentif" and not using "Self." or just using ModalResult directly (without FormIdentif in front). ModalResult:= mrOK; should have been sufficient in that button-event on the modal form. Edit: Quote from: pjtuloup on July 03, 2024, 10:21:45 amI have to say that I am grateful for the warnings since you are experienced, but I don't understand why you say that I am trying to close a modal window from outside the form, since my "continue" button that wants to close the form is indeed in this form? Yes. Exactly. Ignore grumpy Thaddy. He doesn't always read the questions carefully. ---------------------------------------------------------------------- MarkMLl · 2024-07-03 08:30 Quote from: pjtuloup on July 03, 2024, 10:21:45 amThank you very much for the advice... and taking risks. I will study this. I have to say that I am grateful for the warnings since you are experienced, but I don't understand why you say that I am trying to close a modal window from outside the form, since my "continue" button that wants to close the form is indeed in this form? I was being cautious after Thaddy's interpretation :-/ Apart from that: you don't really need to close the form as such, just exit it using the appropriate button. MarkMLl ---------------------------------------------------------------------- Thaddy · 2024-07-03 08:33 Rik, my mother taught me speed reading when I was 5 but never mentioned the disadvantages..So I ignore them by habit ---------------------------------------------------------------------- MarkMLl · 2024-07-03 08:42 Quote from: Thaddy on July 03, 2024, 10:33:33 amRik, my mother taught me speed reading when I was 5 but never mentioned the disadvantages..So I ignore them by habit  Thaddy, I'm very sorry to have to say this but we've noticed. You really should be a bit more careful particularly when- as you've noted yourself- the person asking the question is a newcomer to the language, IDE or forum. MarkMLl ---------------------------------------------------------------------- dseligo · 2024-07-03 09:43 Quote from: pjtuloup on July 03, 2024, 09:43:50 amIn this FormIdentif form there is a "Continue" button which should close the window so that the Master file is accessible with its general menu It should work just with Close;. Check if your method is actually called when you press 'Continue' button: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TFormIdentif.Btn_ContinuerClick(Sender: TObject);begin  ShowMessage('works!');  Close;  //FormIdentif.Close;  //FormIdentif.ModalResult:= 1;  //FormIdentif.ModalResult:= mrOK;end;  Other thing you could check is if you use 'OnClose' event, and in there set 'CloseAction' parameter to caNone. If nothing works, I suggest you make test project that shows problem and post it here. ---------------------------------------------------------------------- rvk · 2024-07-03 10:02 Close; and ModalResult := mrOk; should both work fine. (Note the absense of the "FormIdentif." in front of the ModalResult !! ) But be careful, you have the FormIdentif.ShowModal in your Form1.OnActivate. Why did you put it there? The OnActivate can be triggered multiple times during the lifetime of the TForm (after each Form1.Show). Did you perhaps want it in OnCreate (where it's guaranteed to only show once, during creation of your Form1) ? https://wiki.lazarus.freepascal.org/Event_order#Forms ---------------------------------------------------------------------- pjtuloup · 2024-07-03 17:49 Nothing works from everything I've tried. Also, I abandoned the idea of ​​making a modal window. The problem is that I can't close the non-modal window so that the Main form reappears. I agree that run a secondary window in the MainFormActivate() was not a good idea. But it's not better with the MainFormShow(). Here's what I did or tried to do next: I thought that the secondary window (FormIdentif) should only be launched if the user identification has not yet been done and I created the global variable IdentifOK to store the information. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.FormShow(Sender: TObject);beginif IdentifOK=false then   begin   FormIdentif.Show;   endend; And clicking on the famous "continue" button now launches the following actions Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TFormIdentif.Btn_ContinuerClick(Sender: TObject);begin  //Close  //Hide;  Application.MainForm.Show;end;     Nota: elsewhere in the code IdentifOK= true if the identification was successful But all this doesn't work either: when I click on the "continue button", the MainForm does not appear and the procedure actually loops. I spent the day on this, I'm tired, I'm going to sleep... ---------------------------------------------------------------------- rvk · 2024-07-03 18:05 Quote from: pjtuloup on July 03, 2024, 07:49:12 pmNothing works from everything I've tried. Also, I abandoned the idea of making a modal window. The problem is that I can't close the non-modal window so that the Main form reappears. We showed you how it would work. You can make a new small project with main form and secondary form and just try it with that. It'll probably work. Then you can find out why it doesn't in your big project. Quote from: pjtuloup on July 03, 2024, 07:49:12 pmI agree that run a secondary window in the MainFormActivate() was not a good idea. But it's not better with the MainFormShow().As I already said... I worked put it in the OnCreate (TForm1.FormCreate). Not OnShow. The main form is not visible yet but it will show the secondary form as modal. Sort of a splash or login form. (was that what you were going for?) Quote from: pjtuloup on July 03, 2024, 07:49:12 pmHere's what I did or tried to do next: I thought that the secondary window (FormIdentif) should only be launched if the user identification has not yet been done and I created the global variable IdentifOK to store the information.So it's a login form. I would definitely use a showmodal for that. Or block the main menu ir action until you are sure the credentials are correct. Quote from: pjtuloup on July 03, 2024, 07:49:12 pmBut all this doesn't work either: when I click on the "continue button", the MainForm does not appear and the procedure actually loops.Yep. In the login you call mainform.show which triggers the event again. I think your first draft with showmodal should have worked but I think you have something in your code which gives you problems. That's why it's best to create a small sample project to show it should work. BTW. Isn't there a special login component which you can use (with username and password). Or do you have other special things on you login form? Good night 😴 ---------------------------------------------------------------------- wp · 2024-07-03 18:11 Find in the attachment a small project which shows how to close a modal form by setting its ModalResult to mrClose (or anything else, except for mrNone). ---------------------------------------------------------------------- MarkMLl · 2024-07-03 19:28 Quote from: pjtuloup on July 03, 2024, 07:49:12 pmThe problem is that I can't close the non-modal window so that the Main form reappears. Reappears? What are you doing to make it disappear: a modal window/form would normally simply appear in front of the original one and be assigned the focus. MarkMLl ---------------------------------------------------------------------- egsuh · 2024-07-04 05:54 I believe wp's example will show the structure very well. I just want to add some more explanations, hoping that it would be easier for you to understand. When you want to display another form (let's say Form2) from original form (let's say Form1), you can use          Form2.Show; This will show Form2. But you can go back to Form1 while Form2 is floating. And if you call          Form2.ShowModal; then you have to close this form in order to go back to your original form (Form1). In order to close a modal form, you can call Close or set the form's ModalResult property to any value of TModalResult type. There are several TModalResults values like mrNone, mrAll, mrCancel, mrOK, mrAbort, mrRetry, mrIgnore, mrYes, mrNo. So you can close shown-modal form in one of following ways.  But if you assign ModalResult := mrNone then the form will not be closed. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm2.Button1Click(Sender: TObject);begin       Close;       // or     ModalResult := mrOK;  // or mrCancel,  mrNo, mrYes, etc.  but mrNone will not close the form.end; Now, in the calling program, you will need the content in the modal form (form2) or not. So, if you have ALREADY CREATED form2, then following will work (and form2 is still stay in memory. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Button1Click(Sender: TObject);begin       if Form2.ShowModal = mrOK then begin          Edit1.Text := Form2.Edit1.Text;   // here, first Edit1 is Self.Edit1, which is in the form.          Edit2.Text := Form2.Edit2.Text;   // Edit2,          AnyField := Form2.AField;   // Anyfield as well.     end; end; In the above example, the key is :       if Form2.ShowModal = mrOK Which will be called when form2 returns modalresult, i.e. when the form is closed.  The form is CLOSED but still ALIVE in memory. The codes within the if block will be executed only when the modal form (form2) was closed with mrOK, but will not be executed if form was closed with modal results of mrCancel, mrYes, etc. If you have put two buttons on TForm2, one with OK and another with Cancel, then you will want update form1's content when the user clicked OK button but not Cancel button. To do that ModalResult will be assigned different values depending on the clicked button. Here, you can set it up in a few different ways. You may define different event handler for the two buttons: procedure TForm2.Button1Click(Sender); procedure TForm2.Button2Click(Sender); or,  you may use one single event handler for both buttons. procedure TForm2.Button1Click(Sender); begin       if Sender = Button1 then ModalResult := mrOK      else if Sender = Button2 then  ModalResult := mrCancel; end; Or you can set        ModalResult property of buttons directly at the object inspector at design time. And if you close Form2 by calling Close, not assigning ModalResult, then the codes will not be executed. There are cases when you do not want to pre-create form2. You may want to create it only when it is necessary. You'd better get familiar with following structure. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Button2Click(Sender: TObject);begin     with TForm2.Create (nil) do begin  // an instance is created here,         try          if ShowModal = mrOK then begin                 Self.Edit1.Text := Edit1.Text;           // First Edit1 needs Self. Without self, it will be regarded as TForm2's Edit1, as the second Edit1,                Self.Edit2.Text := Edit2.Text;           // because this code is within with-block .                 Self.AnyField := AField;           end;        finally            Free;   // and the instance is freed here.        end;   end; end; Well, these are what I had most difficulty when I first tried to use modal forms. Good Luck. ---------------------------------------------------------------------- Zvoni · 2024-07-04 06:34 Right, here's my take with my approach. Reason for my approach: A Form is, in a nutshell, a class like any other you use throughout your program. And there is one iron rule: A child never updates its parent. The Parent creates the child and sends it to play The child does its stuff When done, the child returns to its parent, offering whatever results are expected. The parent sends the child to bed after looking at the results ---------------------------------------------------------------------- af0815 · 2024-07-04 06:41 Quote from: Zvoni on July 04, 2024, 08:34:33 amAnd there is one iron rule: A child never updates its parent. a little extension, if the child have to communicate with the parent, do it with callbacks (events), if a simple result is not enough. For me, the same rules are for my Frames. ---------------------------------------------------------------------- cdbc · 2024-07-04 06:54 Hi This:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Button2Click(Sender: TObject);begin    with TForm2.Create (nil) do begin  // an instance is created here,        try            if ShowModal = mrOK then begin                Self.Edit1 := Edit1;         // First Edit1 needs Self. Without self, it will be regarded as TForm2's Edit1, as the second Edit1,                Self.Edit2 := Edit2;           // because this code is within with-block .              Self.AnyField := AField;            end;       finally          Free;   // and the instance is freed here.       end;   end;end;Will blow up in your face! How the H*** can you point perfectly good edits to another set of edits, that are going to be free'd in the next line of code?!? Eaten some magic mushrooms lately, have you?!? DO NOT DO THAT! Regards Benny ---------------------------------------------------------------------- Zvoni · 2024-07-04 06:57 Quote from: af0815 on July 04, 2024, 08:41:39 amQuote from: Zvoni on July 04, 2024, 08:34:33 amAnd there is one iron rule: A child never updates its parent. a little extension, if the child have to communicate with the parent, do it with callbacks (events), if a simple result is not enough. For me, the same rules are for my Frames. IMO, this only applies if the childForm is still active/visible AND it's NOT a Modal Form Remember: Showing a ChildForm in Modal state STOPS code-Execution in the Parent. With a Callback-Event you would force code-execution in the Parent, which will probably blow up. I'm not even sure that this could work ---------------------------------------------------------------------- rvk · 2024-07-04 06:59 Quote from: cdbc on July 04, 2024, 08:54:37 amWill blow up in your face! How the H*** can you point perfectly good edits to another set of edits, that are going to be free'd in the next line of code?!? Eaten some magic mushrooms lately, have you?!? What was probably meant was something like Self.Edit1.Text := EditUsername.Text; etc. ---------------------------------------------------------------------- wp · 2024-07-04 07:07 Quote from: cdbc on July 04, 2024, 08:54:37 amHi This:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Button2Click(Sender: TObject);begin    with TForm2.Create (nil) do begin  // an instance is created here,        try            if ShowModal = mrOK then begin                Self.Edit1 := Edit1;         // First Edit1 needs Self. Without self, it will be regarded as TForm2's Edit1, as the second Edit1,                Self.Edit2 := Edit2;           // because this code is within with-block .              Self.AnyField := AField;            end;       finally          Free;   // and the instance is freed here.       end;   end;end;Will blow up in your face! How the H*** can you point perfectly good edits to another set of edits, that are going to be free'd in the next line of code?!? Eaten some magic mushrooms lately, have you?!? DO NOT DO THAT! Regards Benny You're planning to be the next grumpy man in this forum? Are such harsh words really needed to indicate a typo (Self.Edit1 := Edit1 rather than Self.Edit1.Text := Edit1.Text)? What I don't like in egsuh's code, however, is the use of the with instruction - it makes it unnecessarily hard to tell to which "Edit1" refers. ---------------------------------------------------------------------- egsuh · 2024-07-04 07:17 QuoteHow the H*** can you point perfectly good edits to another set of edits, that are going to be free'd in the next line of code?!? Eaten some magic mushrooms lately, have you?!? DO NOT DO THAT! You are right. QuoteWhat I don't like in egsuh's code, however, is the use of the with instruction - it makes it unnecessarily hard to tell to which "Edit1" refers. In practice, it's more likely to write like   (form1.)UserName := (form2.)edName.Text;, so not much confusion in most cases. But once I made mistake with "with", and want to underline the scope issue. ---------------------------------------------------------------------- Zvoni · 2024-07-04 07:44 Quote from: egsuh on July 04, 2024, 09:17:19 amBut once I made mistake with "with", and want to underline the scope issue. Easy solution: Don't use "with" Have never used it in over 20 years of programming (Visual Basic, FPC) ---------------------------------------------------------------------- MarkMLl · 2024-07-04 07:55 Quote from: Zvoni on July 04, 2024, 09:44:34 amQuote from: egsuh on July 04, 2024, 09:17:19 amBut once I made mistake with "with", and want to underline the scope issue. Easy solution: Don't use "with" Have never used it in over 20 years of programming (Visual Basic, FPC) I have, and intend to continue to. However there are two situations where I consider it to be bad news: a) When nested. b) As here: with ... create ... do ... free ... end; Much has been written in the past by Sven and others drawing attention to other unfortunate cases. But I consider (b) above to be particularly pernicious, since not only does it risk generating unexpected code but it does not leave a (local) variable in a state where it can be inspected by the debugger. An inline declaration along the lines of with a: sometype= b do, with a limited-scope local variable a acting as a shortcut in lieu of a more complex expression, would solve many of the problems but has been vetoed by the core language team. MarkMLl ---------------------------------------------------------------------- pjtuloup · 2024-07-04 07:59 Really, thank you all, thank you very much! I believe that the whole problem comes from the order in which the forms are created in the project options, and this bad order results from a bad arrangement of my procedures: because markMLI's remark is very correct, my main form should appear and it doesn't appear because my login form appears before. I'll do all this again after a better analysis and carefully reading all your messages (thanks for your time). I'll keep you informed. ---------------------------------------------------------------------- pjtuloup · 2024-07-10 08:56 Hi all, I'm sorry but I tried to transpose the code kindly provided into Modal.zip and it doesn't work. I'm not saying that the code is wrong but it must not be compatible with my logic and I don't master Lazarus to find out why. Too bad, I give up, thank you all! ---------------------------------------------------------------------- Thaddy · 2024-07-10 09:09 What is so difficult to understand you can only close a modal form from the modal form itself without hacks? (I know I am repeating myself ) ---------------------------------------------------------------------- pjtuloup · 2024-07-10 09:11 A thousand apologies to everyone: before giving up I wanted to double- check everything once again and I finally found the solution, everything works perfectly. (the mistake was as big as me) A huge thank you to everyone who helped me!!! ---------------------------------------------------------------------- Zvoni · 2024-07-10 09:58 Would be nice to know, what the solution is, in case someone else has the same problem..... ---------------------------------------------------------------------- cdbc · 2024-07-10 10:16 Hi I'd hazard a guess here: "He didn't look at his own code". Regards Benny ---------------------------------------------------------------------- MarkMLl · 2024-07-10 11:06 I wouldn't be that cruel, but this is definitely a case where we could have done with seeing the entire project in case there was something odd with form/unit ordering etc. My suspicion is that- as he hinted himself- OP might have messed up something in that area while he was floundering. MarkMLl ---------------------------------------------------------------------- pjtuloup · 2024-07-10 13:11 To redeem myself I will indeed publish the entire code and indicate what it is for, in case it helps someone with the same needs as me. The need is, when launching an application, to display a modal window used for user identification. This identification is carried out by comparing the entry with the elements appearing in a table of a MySQL database, whose name, and IP address of the hosting server, are specified in an ini file read at launch. In this modal window there are three buttons. A validation button launches the comparison of the entry with the data in the Mysql table. If successful, a "Continue" button becomes active and is used to close the modal window and allows access to the general menu. A final button allows you to abandon, close the modal window and terminate the application. In the code, the main form is called "MasterForm". The identification form is "FormIdentif". A uoutils unit is used to declare global variables. A DataAccess unit (Form DataModule1) is used for relationships with the MySQL database. There is also a FormApropos form (About...) The construction order declared in the project options is as follows: FormMaster DataModule1 FormAbout And now the code (Which would require a little cleaning) Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Maitre; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ActnList, Menus, Unit1, IniFiles, uidentification, uoutils; type   { TFormMaitre }   TFormMaitre = class(TForm)    MenuGen: TMainMenu;    MenuItem1: TMenuItem;    MenuItem10: TMenuItem;    MenuItem11: TMenuItem;    MenuItem12: TMenuItem;    MenuItem13: TMenuItem;    MenuItem14: TMenuItem;    MenuItem15: TMenuItem;    MenuItem16: TMenuItem;    MenuItem17: TMenuItem;    MenuItem18: TMenuItem;    MenuItem19: TMenuItem;    MenuItem2: TMenuItem;    MenuItem3: TMenuItem;    MenuItem4: TMenuItem;    MenuItem5: TMenuItem;    MenuItem6: TMenuItem;    MenuItem7: TMenuItem;    MenuItem8: TMenuItem;    MenuItem9: TMenuItem;    Retour: TMenuItem;    procedure FormCreate(Sender: TObject);    procedure FormShow(Sender: TObject);    procedure MenuItem10Click(Sender: TObject);    procedure MenuItem9Click(Sender: TObject);    function iniRead(s : string) : string;  private  FirstRun:Boolean;  Procedure ShowModalForm;  public   end;   const  Section =   'Serveur'; var  FormMaitre: TFormMaitre;  INI       :TINIFile; implementation {$R *.lfm} { TFormMaitre } procedure TFormMaitre.FormCreate(Sender: TObject);var   callResult : String;begin    iniPath           := Application.Location;    callResult        := iniRead(iniPath);    FirstRun:=True;end; procedure TFormMaitre.FormShow(Sender: TObject);begin    If FirstRun Then    Begin      ShowModalForm;      FirstRun:=False;    end;end; procedure TFormMaitre.ShowModalForm;begin  FormIdentif:=TFormIdentif.Create(Self);  FormIdentif.ShowModal;  If FormIdentif.IsCanceled Then    ShowMessage('Abandon: '+FormIdentif.ReturnValue)  Else    ShowMessage('Poursuite: '+FormIdentif.ReturnValue);  FormIdentif.Close;  FormIdentif.Free;end; procedure TFormMaitre.MenuItem10Click(Sender: TObject);beginApplication.MainForm.Close;end; procedure TFormMaitre.MenuItem9Click(Sender: TObject);begin  FormAPropos.Show;end; function TFormMaitre.iniRead(s : string) : string;  var     str: string;  begin     INI :=TINIFile.Create('Luges.ini');     try       IpServeur  :=INI.ReadString(Section,'IP','');       NomBase  :=INI.ReadString(Section,'Base','');       ShowMessage('Nom de la base lu dans le fichier ini: '+NomBase);     finally       INI.Free;     str := 'Process Worked';       Result := str;     end;  end; end.  Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   unit uIdentification;   {$mode ObjFPC}{$H+}   interface   uses    Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls,    StdCtrls, DBCtrls, uoutils, DataAccess;   type     { TFormIdentif }     TFormIdentif = class(TForm)      Btn_Valider: TButton;      Btn_Quitter: TButton;      Btn_Continuer: TButton;      SaisUser: TEdit;      SaisMdp: TEdit;      AffProfil: TEdit;      AffDiv: TEdit;      GroupBox1: TGroupBox;      GroupBox2: TGroupBox;      GroupBox3: TGroupBox;      GroupBox4: TGroupBox;      GroupBox5: TGroupBox;      Label1: TLabel;      Label2: TLabel;      Panel1: TPanel;      procedure Btn_ValiderClick(Sender: TObject);      procedure Btn_QuitterClick(Sender: TObject);      procedure Btn_ContinuerClick(Sender: TObject);      procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);      procedure FormCreate(Sender: TObject);    private     public       IsCanceled:Boolean;       ReturnValue:String;    end;    var    FormIdentif: TFormIdentif;    Ok : Boolean = false;   implementation   {$R *.lfm}   { TFormIdentif }   procedure TFormIdentif.Btn_QuitterClick(Sender: TObject);  begin    IsCanceled:=True;    ReturnValue:='Sortie de l''application!';    Self.Close;  end; procedure TFormIdentif.Btn_ContinuerClick(Sender: TObject);begin  IsCanceled:=False;  ReturnValue:='Accès autorisé!';  Self.Close;end;   procedure TFormIdentif.FormClose(Sender: TObject; var CloseAction: TCloseAction);    //var CloseAction: TCloseAction);  begin    CloseAction:=caHide;  end; procedure TFormIdentif.FormCreate(Sender: TObject);begin  IsCanceled:=False;end;   procedure TFormIdentif.Btn_ValiderClick(Sender: TObject);  var    Ok1 : Boolean;    Ok2 : Boolean;    NbUsers : LongInt;  begin    Ok1:= false;    Ok2:= false;    ReqUserHabil:='SELECT B.Iduser, B.Nom AS NOM ,B.Prenom AS PRENOM, B.Pwd AS PWD, B.IdDiv, C.IdProfil AS IDPROFIL, C.LibProfil AS PROFIL, E.LibDiv AS DIVISION FROM gusers AS B Left Join ghabil AS A on B.IdUser=A.IdUser Left Join gprofils AS C on C.IdProfil=A.IdProfil Left Join gdiv AS E on E.IdDiv=A.IdDiv WHERE B.Nom=';     if (SaisUser.Text='') and (SaisMdp.Text='')  then       begin       Application.MessageBox('Veuillez saisir votre nom d utilisateur et votre mot de passe!', 'Alerte Utilisateur');       end    else       begin       if SaisUser.Text='' then          begin        Application.MessageBox('Veuillez saisir votre nom d utilisateur', 'Alerte Utilisateur');          end       else          Ok1:= true;     if SaisMdp.Text='' then          begin            Application.MessageBox('Veuillez saisir votre mot de passe!', 'Alerte Utilisateur');          end       else          Ok2:=true;        if ((Ok1=true) and (Ok2=true)) then          begin            IdentifOK:=true;//ShowMessage('Test: '+boolean.ToString(true=true));//ShowMessage('Apres controle: '+boolean.ToString(IdentifOK));//ShowMessage('ok');          //Initialisation requête          ReqUserHabil+=#39+SaisUser.Text+#39;          ReqUserHabil+=';';        //Réinitialisation des affichages          AffProfil.Text:='';        AffDiv.Text:='';          DataModule1.ChargeUsers;          NbUsers:=DataModule1.SQLQueryUsers.RecordCount;          if NbUsers=0 then             begin             Application.MessageBox('Aucun utilisateur habilité de ce nom!', 'Alerte Utilisateur');             DataModule1.SQLQueryUsers.Close;             end          else           begin             if SaisMdp.Text<>DataModule1.SQLQueryUsers.FieldByName('PWD').AsString  then                begin                Application.MessageBox('Le mot de passe est erroné!', 'Alerte Utilisateur');                end           else                begin                AffProfil.Text:=Dat aModule1.SQLQueryUsers.FieldByName('PROFIL').AsString;                AffDiv.Text:=DataModule1.SQLQueryUsers.FieldByName('DIVISION').AsStrin g;                UserEncours:=DataModule1.SQLQueryUsers.FieldByName('NOM').AsString;              UserEnCours+=' ';                UserEnCours:=DataModule1. SQLQueryUsers.FieldByName('PRENOM').AsString;                ProfilEnC ours:=DataModule1.SQLQueryUsers.FieldByName('PROFIL').AsString;              Btn_Continuer.Enabled:=true;                end             end          end       end  end;   end.  Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit uoutils; {$mode ObjFPC}{$H+} interface uses  Classes, SysUtils; varIpServeur           :String;NomBase             :String;iniPath             :String;UserEnCours         :String;ProfilEnCours       :String;IdentifOK           :Boolean;//RequetesReqUserHabil        :String; implementation end.  Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit DataAccess; {$mode ObjFPC}{$H+} interface uses  Classes, SysUtils, mysql80conn, SQLDB, Dialogs,db,uoutils; type   { TDataModule1 }   TDataModule1 = class(TDataModule)    DataSourceUsers: TDataSource;    SQLConnection1: TMySQL80Connection;    SQLQueryUsers: TSQLQuery;    SQLTransaction: TSQLTransaction;    procedure DataModuleCreate(Sender: TObject);  private   public     function Login: Boolean;     procedure Logoff;     procedure ChargeUsers;  end; var  DataModule1: TDataModule1;  implementation {$R *.lfm} { TDataModule1 } procedure TDataModule1.DataModuleCreate(Sender: TObject);begin  If not Login then      begin        Login;        end;end; function TDataModule1.Login: Boolean; begin//ShowMessage('Nom de la base dans la variable NomBase: '+NomBase);Result := true;SQLConnection1.Hostname := IpServeur;SQLConnection1.DatabaseName := NomBase;SQLConnection1.UserName := (censored);SQLConnection1.Password := (censored);try  SQLConnection1.Connected := true;  SQLTransaction.Active := true;except  on e : ESQLDatabaseError do  begin    MessageDlg('Erreur de connexion à la base :'#10#10#13 + IntToStr(e.ErrorCode) + ' : ' + e.Message + #10#10#13'Application terminée.',mtError,[mbOK],0);    Result := false;;  end;  on e : EDatabaseError do  begin    MessageDlg('Erreur de connexion à la base :'#10#10#13'Application terminée.',mtError,[mbOK],0);    Result := false;;  end;end;if Result = true then   //MessageDlg('Base Luges disponible!',mtError,[mbOK],0);    //Application.MessageBox('Base Luges disponible!', 'Info Utilisateur');    ShowMessage('Base Luges disponible!');end;procedure TDataModule1.Logoff;beginif SQLTransaction.Active then   SQLTransaction.Active := false;if SQLConnection1.Connected  then    SQLConnection1.Connected := false;end; procedure TDataModule1.ChargeUsers;begin  with SQLQueryUsers do      begin         Close;         SQL.Text:=ReqUserHabil;         Open;      endend; end. ---------------------------------------------------------------------- MarkMLl · 2024-07-10 14:45 No need to "redeem" yourself :-) But we do collectively want to help, and since- if there's a real screw-up- we'll need to look at the project and possibly form files the easiest thing would be if you used the IDE's Project -> Publish Project facility to dump the whole lot. We anticipate that it might not contain any custom libraries you're using, but it's very likely that we'll be able to see the problem if we cut out a whole lot of the DB-related stuff etc. and focus on the form interaction. MarkMLl ---------------------------------------------------------------------- pjtuloup · 2024-07-10 15:47 Thanks ! I didn't know the Project->Publish function. I will use it in the future! ---------------------------------------------------------------------- rvk · 2024-07-10 16:44 Quote from: pjtuloup on July 10, 2024, 03:11:30 pmTo redeem myself I will indeed publish the entire code and indicate what it is for, in case it helps someone with the same needs as me.Great job (also for showing the code). I do have a few small remarks. And one big one. I hope you don't mind... 1) Creation of the modalform: First. I take it you moved FormIdentif from being autocreated (in the project options>Forms). That's ok. But then you used the same FormIdentif variable for creating the modal form. Because FormIdentif is limited to your OnShow procedure (and you create and free it there), I would remove the FormIdentif from the unit uIdentification and create FormIdentif as LOCAL variable for OnShow. That way you can't make any mistakes later on. Second... you might want to use the try/finally construction for when there is a problem (to make sure the form is really freed). It just good programming that way. Third... you don't need Close for FormIdentif because it's a modal form and when you return, it's already closed. O, and because you are going to free the form itself, you can use Create(nil) instead of Create(Self). You (normally) only use Self if you want that 'Self' to handle the destruction. So: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TFormMaitre.ShowModalForm;var  FormIdentif22: TFormIdentif; // I just added 22 to make sure you don't use the other one which should be removedbegin  FormIdentif22 := TFormIdentif.Create(nil);  try    FormIdentif22.ShowModal;    if FormIdentif22.IsCanceled Then      ShowMessage('Abandon: ' + FormIdentif22.ReturnValue)    else      ShowMessage('Poursuite: ' + FormIdentif22.ReturnValue);  finally    FormIdentif22.Free;  end;end; 2) Using ModalResult for easy result of the modal form Instead of IsCanceled you can use ModalResult. If you use the X button at the top, the ShowModal will always return mrCancel. For the continue button you can set ModalResult := mrOk and for the cancel button you do ModalResult := mrCancel. DON'T USE Self.Close; Just set ModalResult correctly. It will close the modal form automatically and return the given value as function result. In the ShowModalForm you can change the IsCancelled check into (so you can remove the IsCancelled variable entirely): Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TFormMaitre.ShowModalForm;var  FormIdentif22: TFormIdentif; // I just added 22 to make sure you don't use the other one which should be removed  Result: Integer;begin  FormIdentif22 := TFormIdentif.Create(nil);  try    Result := FormIdentif22.ShowModal;  if Result = mrOk then       ShowMessage('Poursuite: Accès autorisé!') // also maybe save the user info??    else      ShowMessage('Abandon: Sortie de l''application!');  finally    FormIdentif22.Free;  end;end; Above will make the login form a bit more streamlined and work according to correct ShowModal principles. 3) Now one which can be a very BIG problem... !!! Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i ReqUserHabil := 'SELECT B.Iduser, B.Nom AS NOM ,B.Prenom AS PRENOM, B.Pwd AS PWD, B.IdDiv, C.IdProfil AS IDPROFIL, C.LibProfil AS PROFIL, E.LibDiv AS DIVISION FROM gusers AS B Left Join ghabil AS A on B.IdUser=A.IdUser Left Join gprofils AS C on C.IdProfil=A.IdProfil Left Join gdiv AS E on E.IdDiv=A.IdDiv WHERE B.Nom=';ReqUserHabil += #39+SaisUser.Text+#39; // <---- PROBLEMReqUserHabil += ';'; If you are going to use your program only internally, with people you trust, you can get away with this (although even than it's not advised). But if you want to make it secure (why else have a login), you really need to take care of that SQL injection vulnerability. ANYONE can mess up your database (delete records, delete the entire database, gain access, etc, etc) when you use SaisUser.Text like that and just append it to your SELECT statement. See https://www.w3schools.com/sql/sql_injection.asp So, even if you don't do anything with the first 2 things... that last one is definitely something you really need to look at and understand... ---------------------------------------------------------------------- MarkMLl · 2024-07-10 18:51 RVK got in first... complete with obligatory xkcd :-) OP: Does that fix things? MarkMLl ---------------------------------------------------------------------- pjtuloup · 2024-07-24 15:33 Quote from: rvk on July 10, 2024, 06:44:25 pm 3) Now one which can be a very BIG problem... !!! Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i ReqUserHabil := 'SELECT B.Iduser, B.Nom AS NOM ,B.Prenom AS PRENOM, B.Pwd AS PWD, B.IdDiv, C.IdProfil AS IDPROFIL, C.LibProfil AS PROFIL, E.LibDiv AS DIVISION FROM gusers AS B Left Join ghabil AS A on B.IdUser=A.IdUser Left Join gprofils AS C on C.IdProfil=A.IdProfil Left Join gdiv AS E on E.IdDiv=A.IdDiv WHERE B.Nom=';ReqUserHabil += #39+SaisUser.Text+#39; // <---- PROBLEMReqUserHabil += ';'; If you are going to use your program only internally, with people you trust, you can get away with this (although even than it's not advised). But if you want to make it secure (why else have a login), you really need to take care of that SQL injection vulnerability. ANYONE can mess up your database (delete records, delete the entire database, gain access, etc, etc) when you use SaisUser.Text like that and just append it to your SELECT statement. See https://www.w3schools.com/sql/sql_injection.asp So, even if you don't do anything with the first 2 things... that last one is definitely something you really need to look at and understand... Thanks rvk, I will study that.