emu10k1
asked on
Problem with TThread
Hi, my problem is when I create an instance of TCombinationThread and start the method execute, it do the job but can't access any component of main form... when I try to access, for example, a label or a button, it generate an exception.
the class descending TThread:
type
TCombinationThread = class(TThread)
private
FValue: String;
FMin, FLevel: Integer;
FList: TStrings;
procedure FindCombinations(Value: string; Min, Level: Integer);
protected
procedure Execute; override;
published
property Value: String read FValue write FValue;
property Min: Integer read FMin write FMin;
property Level: Integer read FLevel write FLevel;
property List: TStrings read FList write FList;
end;
procedure TCombinationThread.FindCom binations( Value: string; Min, Level: Integer);
var
I: Integer;
begin
if (Level > 0) then begin
for I := Min to 25 do
if frmGerarCombinacao.verific a(I) then
FindCombinations(Format('% s- %2.2d ', [Value, I]), I + 1, Level - 1);
end
else begin
FList.Add(CuringasText + Copy(Value, 2, Length(Value)));
end;
end;
procedure TCombinationThread.Execute ;
begin
FindCombinations(FValue, FMin, FLevel);
Form1.Label1.Caption:='tes ting'; // for example
ExitThread(0);
end;
I think that when I try to write or read any component on Main form, it generate the error message.
Please, help me.
the class descending TThread:
type
TCombinationThread = class(TThread)
private
FValue: String;
FMin, FLevel: Integer;
FList: TStrings;
procedure FindCombinations(Value: string; Min, Level: Integer);
protected
procedure Execute; override;
published
property Value: String read FValue write FValue;
property Min: Integer read FMin write FMin;
property Level: Integer read FLevel write FLevel;
property List: TStrings read FList write FList;
end;
procedure TCombinationThread.FindCom
var
I: Integer;
begin
if (Level > 0) then begin
for I := Min to 25 do
if frmGerarCombinacao.verific
FindCombinations(Format('%
end
else begin
FList.Add(CuringasText + Copy(Value, 2, Length(Value)));
end;
end;
procedure TCombinationThread.Execute
begin
FindCombinations(FValue, FMin, FLevel);
Form1.Label1.Caption:='tes
ExitThread(0);
end;
I think that when I try to write or read any component on Main form, it generate the error message.
Please, help me.
You have to syncronize to be able to use the VCL
Example coming....
Shane
Example coming....
Shane
procedure TCombinationThread.DoSomet hing;
begin
FindCombinations(FValue, FMin, FLevel);
Form1.Label1.Caption:='tes ting'; // for example
ExitThread(0);
end;
procedure TCombinationThread.Execute ;
begin
while not terminated do
begin
Synchronize(DoSomeThing);
end;
end;
Shane
begin
FindCombinations(FValue, FMin, FLevel);
Form1.Label1.Caption:='tes
ExitThread(0);
end;
procedure TCombinationThread.Execute
begin
while not terminated do
begin
Synchronize(DoSomeThing);
end;
end;
Shane
ASKER
but doing this, it will call the function findocmbinations a lot of times, and I want to call this function only one time.
ASKER
but doing this, it will call the function findcombinations a lot of times, and I want to call this function only one time.
Your question was that you "can't access any component of main form"
The solution was the syncronization.
Note:
When the execute method is ran, it runs through the entire execute method. It is not a timer. It is not called over and over like the OnTImerEvent. Unless of course you call it from an external source (like a timer) over and over again.
Im not sure what FindCombinations does, but unless it has a repeat until or somekind of loop telling it to repeat, it should be only called once
Shane
The solution was the syncronization.
Note:
When the execute method is ran, it runs through the entire execute method. It is not a timer. It is not called over and over like the OnTImerEvent. Unless of course you call it from an external source (like a timer) over and over again.
Im not sure what FindCombinations does, but unless it has a repeat until or somekind of loop telling it to repeat, it should be only called once
Shane
Never mind (Duh, i got the FindCombinations).
It looks like its called recursively here...
if (Level > 0) then begin
for I := Min to 25 do
if frmGerarCombinacao.verific a(I) then
FindCombinations(Format('% s- %2.2d ', [Value, I]), I + 1, Level - 1); ************
Shane
It looks like its called recursively here...
if (Level > 0) then begin
for I := Min to 25 do
if frmGerarCombinacao.verific
FindCombinations(Format('%
Shane
ASKER
so, What I have to do to solve this problem?
Can you explain to me in layman terms what your app does, and what this
method below does, i might be able to come up with a solution
if (Level > 0) then begin
for I := Min to 25 do
if frmGerarCombinacao.verific a(I) then
FindCombinations(Format('% s- %2.2d ', [Value, I]), I + 1, Level - 1); ************
Shane
method below does, i might be able to come up with a solution
if (Level > 0) then begin
for I := Min to 25 do
if frmGerarCombinacao.verific
FindCombinations(Format('%
Shane
ASKER
function TfrmGerarCombinacoes.verif ica(Numero : Integer): boolean;
begin
if Lista.IndexOf(IntToStr(Num ero)) >= 0 then result := true
else result := false;
end;
verifica will check if the number I is in the StringList (Lista) and if Yes, call the function again with I+1 and Level-1, it will generate a combination of number max range (1-25), but only using the numbers at Lista....
it will result something like this:
01-02-03-04-05-06-07-08-09 -10-11-12- 13-14-15
01-02-03-04-05-06-07-08-09 -10-16-17- 18-19-20
01-02-03-04-05-06-07-08-09 -10-21-22- 23-24-25
01-02-03-04-05-06-07-08-09 -14-15-18- 19-22-23
01-02-03-04-05-06-07-09-12 -13-15-18- 22-24-25
01-02-03-04-05-06-07-10-13 -16-18-19- 21-24-25
01-02-03-04-05-06-07-11-12 -13-16-17- 18-21-22
01-02-03-04-05-06-07-11-12 -13-19-20- 23-24-25
01-02-03-04-05-06-07-14-15 -16-17-18- 23-24-25
01-02-03-04-05-06-08-11-14 -15-16-19- 20-21-22
01-02-03-04-05-06-08-12-14 -16-18-21- 22-24-25
01-02-03-04-05-07-09-12-14 -15-17-19- 20-21-23
01-02-03-04-05-07-10-13-14 -15-18-19- 20-22-24
01-02-03-04-05-07-11-14-15 -18-20-21- 22-23-25
01-02-03-04-05-08-09-11-12 -14-16-17- 19-24-25
01-02-03-04-05-08-09-11-12 -15-18-20- 22-23-24
01-02-03-04-05-08-09-13-14 -15-17-18- 21-22-25
01-02-03-04-05-08-10-11-13 -14-16-18- 20-23-25
begin
if Lista.IndexOf(IntToStr(Num
else result := false;
end;
verifica will check if the number I is in the StringList (Lista) and if Yes, call the function again with I+1 and Level-1, it will generate a combination of number max range (1-25), but only using the numbers at Lista....
it will result something like this:
01-02-03-04-05-06-07-08-09
01-02-03-04-05-06-07-08-09
01-02-03-04-05-06-07-08-09
01-02-03-04-05-06-07-08-09
01-02-03-04-05-06-07-09-12
01-02-03-04-05-06-07-10-13
01-02-03-04-05-06-07-11-12
01-02-03-04-05-06-07-11-12
01-02-03-04-05-06-07-14-15
01-02-03-04-05-06-08-11-14
01-02-03-04-05-06-08-12-14
01-02-03-04-05-07-09-12-14
01-02-03-04-05-07-10-13-14
01-02-03-04-05-07-11-14-15
01-02-03-04-05-08-09-11-12
01-02-03-04-05-08-09-11-12
01-02-03-04-05-08-09-13-14
01-02-03-04-05-08-10-11-13
Something like:
constructor TCombinationThread.Create( v: string; m, l: integer);
begin
inherited Create(true);
FList.TStringList.Create;
FValue := v;
FMin := m;
FLevel := l;
FreeOnTerminate := true;
Resume;
end;
destructor TCombinationThread.Destroy ;
begin
FList.Free;
inherited;
end;
procedure TCombinationThread.SetALab el;
begin
Form1.Label1.Caption:='tes ting'; // for example
end;
procedure TCombinationThread.ResetAL abel;
begin
Form1.Label1.Caption:='fin ished'; // for example
end;
procedure TCombinationThread.SetResu lt;
begin
Form1.Memo1.Lines.Text := FList.Text; // for example
end;
procedure TCombinationThread.Execute ;
begin
Synchronize(SetALabel);
Application.ProcessMessage s;
FindCombinations(FValue, FMin, FLevel);
Synchronize(ResetALabel);
Synchronize(SetResult);
end;
and use it like:
AThread := TCombinationThread.Create( 'name', 5, 10);
Regards, Geo
constructor TCombinationThread.Create(
begin
inherited Create(true);
FList.TStringList.Create;
FValue := v;
FMin := m;
FLevel := l;
FreeOnTerminate := true;
Resume;
end;
destructor TCombinationThread.Destroy
begin
FList.Free;
inherited;
end;
procedure TCombinationThread.SetALab
begin
Form1.Label1.Caption:='tes
end;
procedure TCombinationThread.ResetAL
begin
Form1.Label1.Caption:='fin
end;
procedure TCombinationThread.SetResu
begin
Form1.Memo1.Lines.Text := FList.Text; // for example
end;
procedure TCombinationThread.Execute
begin
Synchronize(SetALabel);
Application.ProcessMessage
FindCombinations(FValue, FMin, FLevel);
Synchronize(ResetALabel);
Synchronize(SetResult);
end;
and use it like:
AThread := TCombinationThread.Create(
Regards, Geo
Looks like you will have to break apart your code, and create a few more methods which will need to be called in the Synchronize....
creating an example
Shane
creating an example
Shane
Never mind, looks like Geo has found the solution for ya...
Shane
Shane
ASKER
geobul: I try your code but the error it shows me the same error message at "Form1.Label1.Caption:='te sting'; // for example"
ASKER
sorry, it shows me that same error message at "Form1.Label1.Caption:='te sting';" line.
I believe he knew that already!
Shane
Shane
ASKER
I think so, Shane :)
ASKER
I know what is happening... when I put this form (mdi child) to auto-create, it works fine, but when I delete this form from auto-create form's list, and use for example,
" TfrmGerarCombinacoes.Creat e(Self);" to create the form, it generate the error message.
" TfrmGerarCombinacoes.Creat
ahhhhhhhhh, you didn't say anything about any MDI forms...... that was an important aspect, seeing they dont behave 100 % like standard forms
Shane
Shane
try
TfrmGerarCombinacoes.Creat e(Applicat ion);"
TfrmGerarCombinacoes.Creat
ASKER
More one thing, If I replace "TfrmGerarCombinacoes.Crea te(Self);" tp "Application.CreateForm(Tf rmGerarCom binacao, frmGerarCombinacao);" it works fine, I can delete from auto-create form's list, but I can only use one form, If I create 2 forms and click on FindCombinations one time at 2 forms, it will generate an error, if I click at first, and when the first end, I click at second it works fine, but the 2 forms at same time generate an error...
what I have to do? What the better solution for this?
thanks
what I have to do? What the better solution for this?
thanks
I dont see any of your code here for creating and then releasing the forms, can you show it to us please
Shane
Shane
ASKER
to create I've tried "TfrmGerarCombinacoes.Crea te(Applica tion);" and "TfrmGerarCombinacoes.Crea te(Self);" and they generate an error message.
When I use "Application.CreateForm(Tf rmGerarCom binacao, frmGerarCombinacao);" it works, but at only first form, If I open 2 forms, it generate an error when I try to use the thread at second form.
and onClose, I'm using "Action := CaFree;"
procedure TfrmGerarCombinacoes.FormC lose(Sende r: TObject; var Action: TCloseAction);
begin
Action := CaFree;
end;
When I use "Application.CreateForm(Tf
and onClose, I'm using "Action := CaFree;"
procedure TfrmGerarCombinacoes.FormC
begin
Action := CaFree;
end;
Your saying - "Application.CreateForm(Tf rmGerarCom binacao, frmGerarCombinacao); does not cause an error. but TfrmGerarCombinacoes.Creat e(Applicat ion); does
AGAIN , can we see the code where this is!
TfrmGerarCombinacoes.Creat e(Applicat ion);
Shane
AGAIN , can we see the code where this is!
TfrmGerarCombinacoes.Creat
Shane
ASKER
procedure TfrmLotoFacil.Combinar1Cli ck(Sender: TObject);
begin
TfrmGerarCombinacoes.Creat e(Applicat ion);
//Application.CreateForm(T frmGerarCo mbinacao, frmGerarCombinacao);
//TfrmGerarCombinacoes.Cre ate(Self);
end;
I try create(Application) it generate an error when the thread try to access the mdi form, create(Self) too, and Application.CreateForm works ( the thread can access the mdi form).
begin
TfrmGerarCombinacoes.Creat
//Application.CreateForm(T
//TfrmGerarCombinacoes.Cre
end;
I try create(Application) it generate an error when the thread try to access the mdi form, create(Self) too, and Application.CreateForm works ( the thread can access the mdi form).
You need a variable
var
MyForm: TfrmGerarCombinacoes;
MyFom:= TfrmGerarCombinacoes.Creat e(Applicat ion);
Shane
var
MyForm: TfrmGerarCombinacoes;
MyFom:= TfrmGerarCombinacoes.Creat
Shane
ASKER
I try this too... the same error...
Then there is something else we haven't seen for code
if the AutoCreate form works, the RunTIme Creation should work as well
Can you send me your code , so as i can see it all -
holmesshane AT charter DOT net
Shane
if the AutoCreate form works, the RunTIme Creation should work as well
Can you send me your code , so as i can see it all -
holmesshane AT charter DOT net
Shane
>it works fine, but when I delete this form from auto-create form's list,
>and use for example,
>" TfrmGerarCombinacoes.Creat e(Self);" to create the form, it
>generate the error message.
you need a reference to be forwarded to your thread,
and in the thread remove formX from the calls
to doing so, you can overload the thread-constructor
just ask, if you need details
meikl ;-)
>and use for example,
>" TfrmGerarCombinacoes.Creat
>generate the error message.
you need a reference to be forwarded to your thread,
and in the thread remove formX from the calls
to doing so, you can overload the thread-constructor
just ask, if you need details
meikl ;-)
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
There are other more complicated ways for doing the same without using Synchronize like:
- using a critical section for accessing a shared resource (the label's caption in your case). You have to access it via the same critical section in the all threads and in the main VCL thread (i.e. in your forms).
- the thread can send a custom message to a form, the form then must handle that message and change the value of the label's caption in the message handler.
Regards, Geo
- using a critical section for accessing a shared resource (the label's caption in your case). You have to access it via the same critical section in the all threads and in the main VCL thread (i.e. in your forms).
- the thread can send a custom message to a form, the form then must handle that message and change the value of the label's caption in the message handler.
Regards, Geo
type
TCombinationThread = class(TThread)
private
Owner_Form : TForm; // here you will take Form
public
constructor Create (OwnerHandle : THandle; .....your params here ...)
end;
constructor TCombinationThread.Create(
begin
...
Owner_Form := Owner;
...
end;
// now you have the handle of the form in the thread
// in my opinion this is all you need.
you can access the label like this :
(Owner.FindComponent('Labe
ASKER
Thanks geobul, it works now.
:-)
ASKER
please, how I can solve this problem?