多线程单元的主要代码如下:
constructor TThreadHttp.create(myurl: string);
begin
  inherited Create(false);
  aURL:=myurl;
end;procedure TThreadHttp.Execute;
var
  tStream: TFileStream;
  aFile : string;
  IdHTTP1 : TIdHttp;
begin
  FreeOnTerminate:=true;
  IdHTTP1:=TIdHTTP.Create(nil);
  aFile:=GetURLFileName(aURL);
  if FileExists(aFile) then tStream := TFileStream.Create(aFile, fmOpenWrite)
  else tStream := TFileStream.Create(aFile, fmCreate);
  IdHTTP1.Request.ContentRangeStart := 0;
  try
    IdHTTP1.Get(aURL, tStream);
  except
    MessageBox(handle,PChar('请检查网络!'),'提示',MB_OK+MB_ICONINFORMATION);
    tStream.Free;
    IdHTTP1.Disconnect;
    Exit;
  end;
  tStream.Free;
  IdHTTP1.Disconnect;
end;主窗体"下载"按钮的主要代码如下:
procedure TUpdatefrm.sbnstartClick(Sender: TObject);
var
 ThreadDown1: TThreadHttp;
begin
   ThreadDown1:=TThreadHttp.Create('http://xxx/yy/a.txt');
   Showmessage('下载成功!');   
   //CopyFile(ExtractFilePath + 'a.txt',ExtractFilePath+'bb\b.txt',false);
end;现在,我要问的问题是:
因为是多线程的,当我点击"下载"按钮执行到   ThreadDown1:=TThreadHttp.Create('http://xxx/yy/a.txt');
这句时,也就是程序正在下载时,比如a.txt有2M,程序还刚在下载过程中即只下载了1M的时候就执行下面的代码,
提示“下载成功”了。这时候文件还没有下载完全,所以不可能下载成功,更不可以执行我注释掉的那句(拷贝
下载完成的文件到指定的目录下)。
当我做成不是多线程的程序时,只要idhttp1.get(),程序会等到全部下载完成后再提示“下载成功!”,接着拷贝
文件也不会有问题了。
请问,我如果在多线程程序下得到文件下载完成这个状态,然后才提示“下载成功!”呢?在线等。。

解决方案 »

  1.   

    一般可以通过线程同步(Synchronize)调用主窗口的一个函数,或者发送消息到主窗口完成线程到主窗口的通讯。
      

  2.   

    ThreadDown1:=TThreadHttp.Create('http://xxx/yy/a.txt');
    Showmessage('下载成功!'); =============================
    其实这个代码是顺序执行的,线程创建后,showmessage就执行了。
    并不是等你下载完了才执行后面的语句。
    下载动作是在线程中执行的。你可以在线程中向主线程PostMessage,告知任务完成。自定义一个消息:
    WM_SUCCED = WM_USER + 1;
    procedure TThreadHttp.Execute;
    var
      
      ...  tStream.Free;
      IdHTTP1.Disconnect;
      PostMessage(FrmMain.Handle, WM_SUCCED, 0, 0);
    end;窗体中定义处理此消息的过程:
    procedure ProcessSucessed(var message:TMessage);message WM_SUCCED;
    procedure TFrmMain.ProcessSucessed(var Message: TMessage);
    begin
      Showmessage('下载成功!');  
    end;
      

  3.   

    就是楼上这个意思。你可以查一下Synchronize这个函数的帮助,可以在线程里直接操纵界面,使用这个函数同步。
      

  4.   

    谢谢你们!已经帮助我很多了!只是还要麻烦一下你们!
    其实我下载的文件不只一个,比如有三个,我写在xml里,
    其余的代码不变,“下载”按钮的代码去循环读xml里的文件名下载,如下:
    procedure TUpdatefrm.sbnstartClick(Sender: TObject);
    var
     XMLDocument :IXMLDocument;
     XMLNode :IXMLNode;
     Node_name:string;
    begin
      XMLDocument:=TXMLDocument.Create(xmldir+'/aa/a.xml');
      XMLDocument.Active;
      XMLNode := XMLDocument.DocumentElement;
      j := XMLNode.ChildNodes.Count-1;
      for i:=0 to j do
      begin
        XMLNode := XMLDocument.DocumentElement;
        XMLNode:=XMLNode.ChildNodes.Nodes[i];
        if strtoint(XMLNode.Attributes['date'])>strtoint(nowverdate) then //比较时间
        begin
          Node_name:=XMLNode.NodeValue;
          ThreadDown1:=TThreadHttp.Create(xmldir+'/bb/'+Node_name);   //创建下载线程
        end;
      end;
    end;
    按照YouToBe的方法我已经解决了一个文件下载结束的问题,如果像上面一样有多个文件在xml里要下载,就会有几个文件下载就弹出几个“下载成功”。
    请问怎么判断最后一个文件下载完成?
    我本来以为当i=j的时候执行完:
    procedure TUpdatefrm.ProcessSucessed(var Message: TMessage);
    begin
      if i=j then
      Showmessage('下载成功!');
    end;但是好像行不通。请大家帮忙了。。
      

  5.   

    主线程定义2个变量
    var
      iTotal: integer;//总文件数
      iSucced:integer;//成功个数先在sbnstartClick过程中取得总文件数量,赋值给iTotal并且iSucced初始化为0;
    iTotal := ?
    iSucced:= 0;然后:procedure TUpdatefrm.ProcessSucessed(var Message: TMessage);
    begin
      Inc(iSucced);
      if iSucced = iTotal then
        Showmessage('下载成功!');
    end;
      

  6.   

    iTotal := ?
    iSucced:= 0;在你创建下载线程之前进行赋值