2

カードリーダーから情報を読み取るためのアプリケーションを開発しました。ここでは、タイマーを使用して5秒ごとに情報を取得しているため、リーダーから情報を取得するため、5秒ごとにユーザーインターフェイスが遅くなります。ユーザーインターフェイスに影響を与えずにバックグラウンドでタイマーを実行する方法

unit frmVistorreg;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms;

type
 thread1=class(TThread)
 private
 FEvent: THandle;
 protected
 procedure Execute; override;
 public
 procedure MyTerminate;
end;


TForm3 = class(TForm)     
txt_name: TEdit;   
txt_cardno.Text  TEdit;        

private

public

end;

var
Form3: TForm3;

implementation

{$R *.dfm}


procedure thread1.Execute;
var
idcard_info :array[0..1024*5] of byte;
flag :Integer;
portflag :Integer;
st :TStrings;
str :string;  
begin

FEvent:= CreateEvent(nil, False, false, nil);
try
while not Terminated do begin
if  MainForm.PortFlag=0 then
begin

 Form3.Label11.Caption:='port has been successfully opened';
 Form3.Label11.Font.Color :=32768;
 flag := GetIdCardInfo(@idcard_info[0],1024*5,5);
 str := byteArray2Str(@idcard_info[0],1024*5);

        if(flag=0) then
        begin
           st := TStringList.Create;
           try
              SplitStr('^_^',str,st);
              Form3.txt_name.Text := st.Strings[0]; 
              Form3.txt_cardno.Text := st.Strings[5]; 
          finally
        st.Free;
          end;
        end;

end
else
begin 

Form3.Label11.Caption:='Please open the port';
Form3.Label11.Font.Color:=clRed;
end;

if WaitForSingleObject(FEvent, 500) <> WAIT_TIMEOUT // 5 seconds timeout
then Terminate;
end;

finally
CloseHandle(FEvent);
end;
end;


procedure thread1.MyTerminate;
begin
 SetEvent(FEvent);
end;


procedure TForm3.FormClose(Sender: TObject; var Action: TCloseAction);
var
Objthread1:thread1;
begin   
Objthread1.MyTerminate;
Action := caFree;
end;


procedure TForm3.FormCreate(Sender: TObject);
var
Objthread1:thread1;
begin
Objthread1:=thread1.Create(false);  
end;

end.

フォームを閉じると、次のようなエラーが発生します

Project MDIAPP.exe raised exception class EAccessViolation with message 'Access violation at address 0051B9F1 in module 'MDIAPP.exe'. Read of address 00000198'.

どうすればこれを解決できますか。

4

1 に答える 1

10

そのためのタイマーコンポーネントは必要ありません。バックグラウンドスレッドが必要です。最も簡単な解決策はSleep、スレッドで関数を使用することです。

unit Unit2;

interface

uses
  Classes;

type
  TMyThread = class(TThread)
  protected
    procedure Execute; override;
  end;

implementation

procedure TMyThread.Execute;
begin
  while not Terminated do begin
// do your processing here
    Sleep(5000);   // wait 5 seconds
  end;
end;

end.

より良いアプローチは、5秒の遅延なしにバックグラウンドスレッドをすぐに終了できるようにするWaitForSingleObject代わりに、イベントを使用することです。Sleep

unit Unit2;

interface

uses
  Windows, Classes;

type
  TMyThread = class(TThread)
  private
    FEvent: THandle;
  protected
    procedure Execute; override;
  public
    procedure MyTerminate;
  end;

implementation

procedure TMyThread.Execute;
begin
  FEvent:= CreateEvent(nil, False, False, nil);
  try
    while not Terminated do begin
// do your processing here
// ..
      if WaitForSingleObject(FEvent, 5000) <> WAIT_TIMEOUT // 5 seconds timeout
        then Terminate;
    end;
  finally
    CloseHandle(FEvent);
  end;
end;

procedure TMyThread.MyTerminate;
begin
  SetEvent(FEvent);
end;

end.

フォームのイベントハンドラーからTMyThreadフォーム呼び出しMyTerminateメソッドを閉じるときにインスタンスを終了します。OnClose

そして、はい、「エラーを表示する」だけでなく、どのエラーメッセージを受け取るかを知ることは興味深いことです。

于 2012-06-27T06:21:36.623 に答える