Recent

Author Topic: Make control in thread  (Read 16662 times)

Okoba

  • Hero Member
  • *****
  • Posts: 617
Make control in thread
« on: September 03, 2016, 06:17:47 pm »
ATTENTION: Updating GUI from a different thread is not a appropriate way, read this talk just for your information and learning about side effects.

Hello,
I have a weird problem today and wanted to share that with you:
Code: Pascal  [Select][+][-]
  1. type
  2.  
  3.   { TForm1 }
  4.  
  5.   TForm1 = class(TForm)
  6.     Button1: TButton;
  7.     Button2: TButton;
  8.     procedure Button1Click(Sender: TObject);
  9.     procedure Button2Click(Sender: TObject);
  10.   private
  11.   public
  12.     bb: TButton;
  13.   end;
  14.  
  15.   TBThread = class(TThread)
  16.     procedure Execute; override;
  17.   end;
  18.  
  19. var
  20.   Form1: TForm1;
  21.  
  22. implementation
  23.  
  24. {$R *.lfm}
  25.  
  26. procedure TBThread.Execute;
  27. begin
  28.   Form1.bb := TButton.Create(Form1);
  29.   with  Form1.bb do
  30.   begin
  31.     Parent := Form1;
  32.     Left := 0;
  33.     Top := 0;
  34.     Width := 100;
  35.     Height := 100;
  36.     Caption:='Button';
  37.   end;
  38. end;
  39.  
  40. { TForm1 }
  41.  
  42. procedure TForm1.Button1Click(Sender: TObject);
  43. begin
  44.   TBThread.Create(False);
  45. end;
  46.  
  47. procedure TForm1.Button2Click(Sender: TObject);
  48. begin
  49.   Self.Caption := bb.Caption;
  50.   ShowMessage(IntToStr(ControlCount));
  51. end;          

As you can see I want to make a button in separate thread and my check shows the button will be made and ControlCount shows that too but I cant see it in my Form.
Im testing this project in Windows 10 and Last Lazarus Trunk.

« Last Edit: September 07, 2016, 07:52:49 am by OkobaPatino »

Thaddy

  • Hero Member
  • *****
  • Posts: 16945
  • Ceterum censeo Trump esse delendam
Re: Make control in thread
« Reply #1 on: September 03, 2016, 06:41:35 pm »
Why would you want to create a Button in a thread? That is a very bad idea.
What you should do is implement the functionalty that the button triggers inside a thread if you want, but the control itself should NEVER be in a thread.
Can you explain what you want to achieve?
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

Fungus

  • Sr. Member
  • ****
  • Posts: 353
Re: Make control in thread
« Reply #2 on: September 03, 2016, 07:24:49 pm »
In order for that to work, you probably need to stuff the creation of the button in a synchronized method:

Code: Pascal  [Select][+][-]
  1. procedure TBThread.MakeButton;
  2. begin
  3.   Form1.bb := TButton.Create(Form1);
  4.   with  Form1.bb do
  5.   begin
  6.     Parent := Form1;
  7.     Left := 0;
  8.     Top := 0;
  9.     Width := 100;
  10.     Height := 100;
  11.     Caption:='Button';
  12.   end;
  13. end;
  14.  
  15. procedure TBThread.Execute;
  16. begin
  17.   Synchronize(MakeButton);
  18. end;

But.. You should NEVER EVER handle GUI related stuff from anywhere else than the main application thread. If you need to update a control (or any other elements of the GUI) depending on work done in a secondary thread you should send a message to the main thread in order to let the main thread do the GUI update. Synchronizing multiple threads can be hard and cumbersome but if you do not, you program will cause problems that are very hard to debug.

Okoba

  • Hero Member
  • *****
  • Posts: 617
Re: Make control in thread
« Reply #3 on: September 03, 2016, 07:34:44 pm »
Yeah sure I know that I should not make work with GUI in thread and here is more explanation:

That was a sample code, in real code I want to Make TOpenGLControl and when it will create and I want to set Parent property it takes 500 to 1500ms in debug mode in my machine so I want to make it in a separate thread.

Also I know that is wrong but I thought with myself I can do that in a controlled situation but this behavior seems weird, where is the control? am I wrong?

Here is the updated version:

Code: Pascal  [Select][+][-]
  1. unit Main;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, FileUtil, Forms, Controls, StdCtrls, Graphics, Dialogs,
  9.   OpenGLContext;
  10.  
  11. type
  12.  
  13.   { TForm1 }
  14.  
  15.   TForm1 = class(TForm)
  16.     Button1: TButton;
  17.     Button2: TButton;
  18.     procedure Button1Click(Sender: TObject);
  19.     procedure Button2Click(Sender: TObject);
  20.   private
  21.   public
  22.     op: TOpenGLControl;
  23.   end;
  24.  
  25.   TBThread = class(TThread)
  26.     procedure Execute; override;
  27.   end;
  28.  
  29. var
  30.   Form1: TForm1;
  31.  
  32. implementation
  33.  
  34. {$R *.lfm}
  35.  
  36. procedure TBThread.Execute;
  37. begin
  38.   //This will take around 1000ms !
  39.   Form1.op := TOpenGLControl.Create(Form1);
  40.   with  Form1.op do
  41.   begin
  42.     Parent := Form1;
  43.     Left := 0;
  44.     Top := 0;
  45.     Width := 100;
  46.     Height := 100;
  47.     Caption:='TOpenGLControl';
  48.   end;
  49. end;
  50.  
  51. { TForm1 }
  52.  
  53. procedure TForm1.Button1Click(Sender: TObject);
  54. begin
  55.   TBThread.Create(False);
  56. end;
  57.  
  58. procedure TForm1.Button2Click(Sender: TObject);
  59. begin
  60.   ShowMessage(IntToStr(ControlCount));
  61. end;
  62. end.

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: Make control in thread
« Reply #4 on: September 03, 2016, 08:10:39 pm »
That was a sample code, in real code I want to Make TOpenGLControl and when it will create and I want to set Parent property it takes 500 to 1500ms in debug mode in my machine so I want to make it in a separate thread.
Meaning ? That your application/form takes that amount of time in order to start/show ? And how exactly is using a thread going to help you with that ? Just asking, because i don't see the benefit.

Quote
Also I know that is wrong but I thought with myself I can do that in a controlled situation but this behavior seems weird, where is the control? am I wrong?
Yes, you are wrong. There is no weird behaviour there, other then how threads behave/work. You are accessing a variable from another thread and didn't follow the rules.

So the question, becomes again: what are you trying to achieve exactly ? That your form shows up quicker (or application starts quicker) ? Sorry, but you'd have to life with that, because the gl context needs to be initialized and that simply takes time.

However, camouflaging the start-up delay is possible but a simple timer or onidle event is sufficient for that. Just create the gl context where it is least obvious for the user to notice, preferably when the form isn't visible (for the user) at all.
« Last Edit: September 03, 2016, 08:23:04 pm by molly »

Okoba

  • Hero Member
  • *****
  • Posts: 617
Re: Make control in thread
« Reply #5 on: September 03, 2016, 08:21:42 pm »
Thanks for the answer but it was not what I want.
Yes it takes time and I dont like it, and there must be a way for it and using thread was a not really good way.
Weird behavior is that when you make a control and set everything why form dont show that? technical asking.

Thaddy

  • Hero Member
  • *****
  • Posts: 16945
  • Ceterum censeo Trump esse delendam
Re: Make control in thread
« Reply #6 on: September 03, 2016, 08:25:31 pm »
I might add that reliable timing of execution speed is hardly possible in debug mode, so forget about that. It is even silly to try and create some code in a thread just because of debug mode speed issues.
That's a novelty for me :)  IOW: Nobody does that, for a reason....

Try Molly's pointers: OnIdle, ProcessMessages, A Timer, and the like but not a thread. You don't know yet what you are doing.
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: Make control in thread
« Reply #7 on: September 03, 2016, 08:28:34 pm »
Well, in theory there is nothing wrong with creating components for a form that is part of another thread. That is to say, it should be possible when following the rules. It is just very bad habit, and i would personally advise against it.

For the technical part, please read here (but also read the complete wiki article to understand threading better. Just do a google search on "freepascal accessing variables from another thread", and read the articles (also those related to Delphi and available on stackoverflow).

Programming threads requires a bit of a different mindset if you are not familiar with them.

Thaddy

  • Hero Member
  • *****
  • Posts: 16945
  • Ceterum censeo Trump esse delendam
Re: Make control in thread
« Reply #8 on: September 03, 2016, 08:30:18 pm »
Thanks for the answer but it was not what I want.
Yes it takes time and I dont like it, and there must be a way for it and using thread was a not really good way.
Weird behavior is that when you make a control and set everything why form dont show that? technical asking.

The form doesn't show that because it is part of a completely different thread. And all the painting, housekeppeing etc is done in the main thread, not in YOUR thread, just to name a few side effects, but there are many more to consider.!
 Threads have their own universe. It is possible, but believe me, you don't want it. Way too complex for your skill-level.
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

Thaddy

  • Hero Member
  • *****
  • Posts: 16945
  • Ceterum censeo Trump esse delendam
Re: Make control in thread
« Reply #9 on: September 03, 2016, 08:32:20 pm »
Molly's post crossed mine. He tries to convince you in the same manner I do not to continue on this path.
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

Okoba

  • Hero Member
  • *****
  • Posts: 617
Re: Make control in thread
« Reply #10 on: September 03, 2016, 08:34:05 pm »
With all respect Thaddy, I know what Im doing and I know it is not fully correct and I didnt just try debug mode.
All ways you saying are make the app freeze and I dont want that, if you have a better way to remove the initializing delay please share.

molly I know multi threading programming and I know that it is not a good way to do GUI stuff in another thread but as I said before I try this way only to maybe make it works but if you have another way to make it without delay please tell me about that.

About weird behavior as I said before its a question for me why my component dont show although it is made and all needed property are set.

Fungus

  • Sr. Member
  • ****
  • Posts: 353
Re: Make control in thread
« Reply #11 on: September 03, 2016, 08:36:25 pm »
The OpenGL control will not be crated faster by doing it in a thread. You might want to defer the creation of the control until all other initialization is done and the main form is showing. Then you can ad some sort of "Wait, initializing..." marquee in order to display that the control is being constructed. I think you'll have a hard time creating the OpenGL control in a secondary thread and transferring it's ownership to the main thread.

P.S: Initializing OpenGL and/or DirectX just takes a bit of time, live with it.. :-)

Okoba

  • Hero Member
  • *****
  • Posts: 617
Re: Make control in thread
« Reply #12 on: September 03, 2016, 08:38:42 pm »
Maybe I need to tell again:

I dont want a loading or a delay, I want to do OpenGL stuff in a separate thread and when all stuff done show them in Main form and problem is making TOpenGLControl takes time.

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: Make control in thread
« Reply #13 on: September 03, 2016, 08:45:32 pm »
*sight*

molly I know multi threading programming and I know that it is not a good way to do GUI stuff in another thread but as I said before I try this way only to maybe make it works but if you have another way to make it without delay please tell me about that.
Answered in one of my previous posts.

Quote
About weird behavior as I said before its a question for me why my component dont show although it is made and all needed property are set.
Which tells me you do not know anything about threads. Sorry to sound harsh but Thaddy already explained that to you (as well as the wiki and all the other articles you are able to find with that google search i mentioned).

Like i said: it requires a different mindset  :)

Maybe I need to tell again:

I dont want a loading or a delay, I want to do OpenGL stuff in a separate thread and when all stuff done show them in Main form and problem is making TOpenGLControl takes time.
Yes, i understand that you do not want the delay. As also answered, creating a gl context takes time: learn to live with it.

Workaround the problem using a timer, or onidle event. do not show the form to the user but create it in the background and show the user something else first so that you are able to distract from the delay.

Okoba

  • Hero Member
  • *****
  • Posts: 617
Re: Make control in thread
« Reply #14 on: September 03, 2016, 08:48:27 pm »
Thanks for your helps but "learn to live with it" is not a good answer, sorry.
So please tell me "why" form wont show the control?

 

TinyPortal © 2005-2018