2017-04-07 87 views
-3

我有装入数据的表单的方法,有些数据可能需要很长时间才能加载。数据的这一部分是可选的,并且这数据被加载之前的形式可以被关闭:确定该表单是否有效

procedure TForm1.LoadData(Sender: TObject); 
begin 
    // Load and add data to the form 
    ... 
    TThread.CreateAnonymousThread(procedure 
    begin 
    // Long data loading 
    ... 
    TThread.Synchronize(nil, procedure 
    begin 
     // Add data to the form 
     ... 
    end); 
    end).Start; 
end; 

而问题:这是确定形式最好的方法是活着(未封闭的),用于FMX以避免异常时从数据应该添加线程?长时间加载我的意思是不是几小时或十分钟,这可能会长达一分钟。

更新:关闭窗体后,我不再需要额外的数据,线程可以终止。这将以任何方式终止,但我必须毫无例外地这样做。目前,我有

TThread.Synchronize(nil, procedure 
    begin 
     // Add data to the form 
     try 
     ... 
     except 
     end; 
    end); 

,这是工作,但我搜索决策无一例外

+0

没有任何意见,11个意见和-2票 - 这是非常简单的问题或错误的实现? –

+0

不要让线程在运行时关闭表单。或者不要从线程访问表单(这意味着在没有调用Synchronize的情况下运行它)。你不能两面都有。如果你站在树上的树枝上,你无法控制锯子通过时发生的情况。 –

回答

0

好,可能的决定之一:

添加到以下形式:

protected 
    FThread: TThread; 

更改的加载方法:

procedure TForm1.LoadData(Sender: TObject); 
begin 
    // Load and add data to the form 
    ... 
    FThread := TThread.CreateAnonymousThread(procedure 
    begin 
    // Long data loading 
    ... 
    if not TThread.Current.CheckTerminated then 
     TThread.Synchronize(nil, procedure 
     begin 
     // Add data to the form 
     ... 
     end); 
    end); 
    FThread.Start; 
end; 

而在Form.OnClose:

if not FThread.ExternalThread then 
    FThread.Terminate; 

线程移动到ExternalThreads列表(内部用Delphi)时我们调用TThread.Current方法,这意味着它已经发送了TThread.Synchronize部分代码。当您为这个答案投票时,会很高兴看到任何额外的评论。

+0

为什么你坚持使用匿名线程? –

+0

用匿名线程我可以把加载代码放在一个过程中,这对于查看和检查这个更加有用,以前这个部分是在TThread类中(在Delphi 5上) –

0

您可以检查表的Visible属性来查找窗体显示或关闭,像这样:

begin 
    Form.Show; 
    // Load data 
    TThread.CreateAnonymousThread(procedure 
    var 
    I, N : Integer; 
    begin 
    // Long data loading 
    N := 0; 
    for I := 0 to 1000000000 do 
    N := N + 1; 

    TThread.Synchronize(nil, procedure 
    begin 
    if Form.Visible then 
     Form.Label1.Text := IntToStr(N); 

     // Add data to the form 
    end); 
    end).Start; 
end; 

但这不是一个好主意,当表单关闭时,您无法停止加载数据。您应该创建一个的TThread类,并使用它的终止标志取消加载数据时,窗体关闭,例如:

TMyThread = class(TThread) 
    public 
    constructor Create; 
    protected 
    procedure Execute; override; 
end; 

... 

{ TMyThread } 

constructor TMyThread.Create; 
begin 
inherited Create(True); 
FreeOnTerminate := True; 

end; 

procedure TMyThread.Execute; 
var 
I, N : Integer; 
Stop : Boolean; 
begin 
N := 0; 
Stop := False; 

for I := 1 to 1000000000 do 
    begin 
    if Terminated then 
    begin 
    Stop := True; 
    Break; 
    end; 

    N := N + 1; 
    end; 

if not Stop then 
    begin 
    Synchronize(Procedure 
       begin 
       Form.Label1.Text := IntToStr(N); 
       end); 
    end; 
end; 

展会形式和启动主题:

var 
MyThread : TMyThread; { Global Variable } 
... 

begin 
Form.Show; 

MyThread := TMyThread.Create; 
MyThread.Start; 
end; 

,并终止线程时关闭窗体:

procedure TForm.FormClose(Sender: TObject; var Action: TCloseAction); 
begin 
if Assigned(MyThread) then 
    begin 
    MyThread.Terminate; 
    MyThread := nil; 
    end; 
end; 
+1

这个问题没有询问表单是否可见**。它询问用户**正在更新该表单时正在运行的线程正在关闭表单。 **关闭** <> **隐藏**。 –

+0

@KenWhite“alive”的含义是什么?,如果窗体显示(visible = True),它将被更新,否则(visible = False)不需要更新。检查Visible属性有什么问题?如果表单应该更新,天气显示与否,那么如果我们假设表单是自动创建的,那么关闭表单并不重要。问题不是很清楚,但是我建议使用TThread类并在表单关闭时取消加载是一个更好的解决方案。 –

+0

活着的意思是不关闭 –