2
votes

I have a question about threads and controls. I made a syncing modal dialog. There's three progressbars and couple of captions. If application is opened for a first time, then it will open syncing dialog and do the update thing. On dialog Show() method I create three different threads. Each thread controls data download, xml parsing and database inserting. And then shows progress on progressbar. All described, is working fine.

Now the problem - I want to close this dialog automatically when all items are downloaded, parsed and inserted to database. I tried to check if progressbar.position equals to progressbar.max and I tried check if threads are terminated.If I go with the progressbar way, dialog closes too early and one progressbar isn't totally ended. If I go with the thread checking way, then progressbars stop in the middle of process and that's all.

Maybe you have done it and tell the Delphi n00b, how is the best way to do it.

Thanks in advance...

3

3 Answers

5
votes

For this simple thing, you can use the thread OnTerminate event (which runs in the context of the main thread) just to decrement a "thread count" variable initialized to 3 at thread creation moment.

When the thread count reaches 0, you can safely close the form.

begin
  //..thread creation, stuff
  FThreadCount := 3;
  DownloadThread.OnTerminate := DecThreadCount;
  ParseThread.OnTerminate := DecThreadCount;
  InsertThread.OnTerminate := DecThreadCount;
  //resume threads and other stuff
end;

procedure TForm1.DecThreadCount(Sender: TObject);
begin
  Dec(FThreadCount);
  if FThreadCount = 0 then
    Close;
end;
2
votes

Are you using Windows Vista or Windows 7? Microsoft changed the way progress bars work in Vista, so that instead of immediately jumping to the indicated position, it gradually slides towards it. This means that your progress can actually be finished, but the bar won't indicate that for another second or so, so it looks like the dialog is closed before you're done, especially if the bar has a small number of progress steps.

It's kinda ugly, but you can work around this by using a helper function that does something like this:

procedure UpdateProgressBar(bar: TProgressBar);
begin
  bar.StepIt;
  bar.Max := bar.Max + 1;
  bar.Max := bar.Max - 1;
end;

This will ensure that it immediately jumps to the correct position.

EDIT: Details in How do I make TProgressBar stop lagging?

1
votes

I'd get your threads to post a message back to the dialog when they complete. Once all three messages have been received you can close the dialog.