Forum > LCL

[SOLVED] How to switch a Form from Show-mode to ShowModal() without flicker?

(1/2) > >>

Hartmut:
My program uses a 2nd Form to display some infos. Some of these infos need a couple of seconds to gather them. I want to display the 1st part immediately and add the 2nd part after it is ready to display. Therefore I use Show() to make the 1st part visible. After the 2nd part is displayed, I can switch the Form to modal-mode.

The problem is, that before the ShowModal() a Hide() is required and between those 2 commands a flicker occurs. I want to avoid that flicker. I have this flicker only on Linux Ubuntu 18.04 but not on Windows 7. I use Lazarus 2.0.6 (but have the same results with 2.0.10).

I attached a small compilable project. Thanks in advance.


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---// Extract from Unit1:procedure TForm1.Button1Click(Sender: TObject);   begin   Form2.display_Infos;   end; // Extract from Unit2:procedure TForm2.display_Infos;   begin   Memo1.Clear;   Memo1.Lines.Add('This are Infos part 1');   Show; {display Infos part 1}   Application.ProcessMessages; {neccessary to display Infos part 1}    sleep(2000); {simulates gathering Infos part 2}    Memo1.Lines.Add('This are Infos part 2');   Hide; {is neccessary before ShowModal()}   ShowModal; {a flicker occurs between Hide() and ShowModal()}   end; procedure TForm2.Button_ActionClick(Sender: TObject);   begin   // do some actions...   Close;   end; procedure TForm2.Button_CloseClick(Sender: TObject);   begin   Close;   end;  

GetMem:
@Hartmut

Show the form with FormX.ShowModal, then on FormShow event start a timer, like this:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---procedure TFormX.FormShow(Sender: TObject);begin  Timer1.Interval := 300;  Timer1.Enabled := True;end; procedure TFormX.Timer1Timer(Sender: TObject);begin  Timer1.Enabled := False;  Memo1.Clear;  Memo1.Lines.Add('This are Infos part 1');   Self.Enabled := False; //prevent user to close form  try    //do lengthy process here    Memo1.Lines.Add('This are Infos part 2');  finally    Self.Enabled := True;  end;end;  
PS: On design time set Timer1.Enabled to false.

Hartmut:
Thanks a lot GetMem for your quick reply. Before I try to implement it, may I ask a question? Why do you recommend a timer for this? Is it not possible to do everything directly in FormShow() - or in FormActivate(), where I already had experimented with?
Because I'm still a beginner to GUI programming I want to understand and to learn. Thanks.

GetMem:
@Hartmut

--- Quote ---Thanks a lot GetMem for your quick reply.
--- End quote ---
You are welcome!


--- Quote ---Before I try to implement it, may I ask a question? Why do you recommend a timer for this?
--- End quote ---
Because is the least painful solution. If you put a lengthy code in the FormShow event, the form won't be visible until the lengthy process is over. With a timer you immediately exit the OnShow event and the user will have a visual feedback. FormActivate is also OK, but you have to be careful because FormActivate is always called when the from receive focus.
There are other ways to achieve the same thing, like running the lengthy code on FormCreate and showing a busy cursor in the caller form. In my opinion a timer is the most straightforward solution.

Hartmut:
Hello GetMem, thank you very much for your explanations.

Meanwhile I implemented your suggestion. The good news is: no more flicker :-))

But the 2nd Form is not longer "really" modal: as long as it is open, you still can press Button1 from Form1 and get a Runtime-Error, because Form2 ist already displayed. I have this both on Lazarus 2.0.6 and 2.0.10. In my "original" demo version Button1 is blocked (in 2.0.6 and 2.0.10), as it should be for modal Forms. Here is my new code:


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---procedure TForm2.display_Infos;   begin   ShowModal; {calls FormShow()}   end; procedure TForm2.FormShow(Sender: TObject);   {Event "OnShow"}   begin   writeln('OnShow - start Timer');   Timer1.Interval := 300; {in ms}   Timer1.Enabled := True;   end; procedure TForm2.Timer1Timer(Sender: TObject);   {Event "OnTimer" des Timers}   begin   Timer1.Enabled := False;   writeln('Timer1Timer');    Memo1.Clear;   Memo1.Lines.Add('This are Infos part 1');   Application.ProcessMessages; {neccessary to display Infos part 1}    Self.Enabled := False; // prevent user to close form   try //do lengthy process here:       sleep(2000); {simulates gathering Infos part 2}       Memo1.Lines.Add('This are Infos part 2');   finally       Self.Enabled := True;   end; {try}   end;
Did I made something wrong?

Navigation

[0] Message Index

[#] Next page

Go to full version