Delphi 使用windows按键打破循环(非按键事件)

Delphi 使用windows按键打破循环(非按键事件),delphi,Delphi,使用Delphi2010 您好,我正在寻找一种使用按键打破循环的方法(例如“x”) 过程TfrmMain.btnSpinClick(发送方:TObject); 函数IsControl键按下:布尔值; 开始 结果:=GetKeyState(Ord('x'))

使用Delphi2010

您好,我正在寻找一种使用按键打破循环的方法(例如“x”)

过程TfrmMain.btnSpinClick(发送方:TObject);
函数IsControl键按下:布尔值;
开始
结果:=GetKeyState(Ord('x'))<0;
终止
变量
产品列表:TStringList;
一、 整数;
开始
Screen.Cursor:=crHourGlass;
旋转:=真;
更新全部;
Application.ProcessMessages;
//创建产品列表
ProductList:=TStringList.Create;
ProductList.LoadFromFile(edtProductsFile.Text);
Progressbar1.Min:=1;
Progressbar1.Max:=ProductList.Count-1;
//通过产品清单进行交互
//跳过第一行(字段名),从第二行开始
对于I:=1到ProductList.Count-1 do
开始
//***************
//这里还有其他代码
//***************
Progressbar1.位置:=Progressbar1.位置+1;
***如果按了IsControl键,则断开;
Application.ProcessMessages***
结束//对于I:=1到ProductList.Count-1 do
ProductList.Clear;
ProductList.Free;
同义词表。清晰;
同义词表。免费;
Screen.Cursor:=crDefault;
旋转:=假;
更新全部;
Application.ProcessMessages;
终止

将长时间运行的代码移动到单独的线程中。在其中,偶尔检查是否设置了某个标志。设定好后,停下来

然后,为表单编写一个
OnKeyPress
事件处理程序。当该事件处理程序检测到按下了魔术键组合时,设置该标志。这将导致线程停止工作

它可以像这样工作:

type
  TProcessProductListThread = class(TThread)
  private
    FFileName: string;
    FProgressBar: TProgressBar;
    FMax: Integer;
    procedure SetProgressBarRange;
    procedure IncrementProgressBar;
    procedure ProcessProduct(const AProduct: string);
  protected
    procedure Execute; override;
  public
    constructor Create(const AFileName: string; AProgressBar: TProgressBar;
      OnThreadTerminate: TNotifyEvent);
  end;
ProcessThread := TProcessProductList.Create(edtProductsFile.Text, Progressbar1,
  OnProcessProductListTerminate);
构造函数接收完成其工作所需的所有信息,但实际上并不开始执行任何操作。这是为
Execute
方法保留的。我们设置了
FreeOnTerminate:=False
,因为主线程在开始运行之后需要继续访问线程对象

constructor TProcessProductListThread.Create(const AFileName: string;
  AProgressBar: TProgressBar; OnThreadTerminate: TNotifyEvent);
begin
  inherited Create(False);
  FFileName := AFileName;
  FProgressBar := AProgressBar;
  OnTerminate := OnThreadTerminate;
  FreeOnTerminate := False;
end;
您的代码在几个地方与GUI交互。这需要从GUI线程中实现,因此我们将把代码提取到单独的方法中,这些方法可以传递到
Synchronize

procedure TProcessProductList.SetProgressBarRange);
begin
  FProgressBar.Min := 1;
  FProgressBar.Position := FProgressBar.Min;
  FProgressBar.Max := FMax;
end;

procedure TProcessProduceList.IncrementProgressBar;
begin
  FProgressBar.Position := FProgressBar.Position + 1;
end;
您会注意到,
Execute
方法看起来与原始代码类似。注意它如何使用以前从构造函数保存的值

procedure TProcessProductList.Execute;
var
  ProductList: TStringList;
  I: Integer;
begin
  ProductList := TStringList.Create;
  try
    ProductList.LoadFromFile(FFileName);
    FMax := ProductList.Count - 1;
    Synchronize(SetProgressBarRange);

    // skip first line (it's the field names) and start at the second line
    for I := 1 to ProductList.Count - 1 do begin
      ProcessProduct(ProductList[I]);

      Synchronize(IncrementProgressBar);
      if Terminated then
        exit;
    end;
  finally
    ProductList.Free;
  end;
end;
要启动线程,请按如下方式创建它:

type
  TProcessProductListThread = class(TThread)
  private
    FFileName: string;
    FProgressBar: TProgressBar;
    FMax: Integer;
    procedure SetProgressBarRange;
    procedure IncrementProgressBar;
    procedure ProcessProduct(const AProduct: string);
  protected
    procedure Execute; override;
  public
    constructor Create(const AFileName: string; AProgressBar: TProgressBar;
      OnThreadTerminate: TNotifyEvent);
  end;
ProcessThread := TProcessProductList.Create(edtProductsFile.Text, Progressbar1,
  OnProcessProductListTerminate);
使用事件处理程序处理终止,如下所示。它主要是源代码的尾声中的内容,但它也清除了
ProcessThread
;这样,它的值可以指示线程是否仍在运行

procedure TForm1.OnProcessProductListTerminate(Sender: TObject);
begin
  Thesaurus.Clear;
  Thesaurus.Free;
  UpdateAll;
  ProcessThread := nil;
end;
记得我说过你应该在按键时设置一个标志吗?在上面的代码中,它检查的标志只是线程自己的
终止属性。要设置它,请调用线程的
Terminate
方法

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
  if Char = 'X' then begin
    ProcessThread.Terminate;
    ProcessThread.Free;
    Char := #0;
  end;
end;

因为多线程很难,@Jerry,当它的竞争对手是单线程时,没有人会接受多线程的答案。Jake,请不要对此感到生气,但请看下面的文章,了解为什么
ProcessMessages
不是一个好的解决方案: