delphi - using windows key press to break out of loop (non keyPress event) -
using delphi 2010
hi, looking way break out of loop using key press (example 'x')
procedure tfrmmain.btnspinclick(sender: tobject); function iscontrolkeypressed: boolean; begin result := getkeystate(ord('x')) < 0; end; var productlist: tstringlist; i, integer; begin screen.cursor:= crhourglass; spinning:= true; updateall; application.processmessages; //create product list productlist:= tstringlist.create; productlist.loadfromfile(edtproductsfile.text); progressbar1.min:= 1; progressbar1.max:= productlist.count - 1; //interate through product list //skip first line (its field names) , start @ second line i:= 1 productlist.count - 1 begin //*************** //other code here //*************** progressbar1.position:= progressbar1.position + 1; ***if iscontrolkeypressed break; application.processmessages;*** end; //for i:= 1 productlist.count - 1 productlist.clear; productlist.free; thesaurus.clear; thesaurus.free; screen.cursor:= crdefault; spinning:= false; updateall; application.processmessages; end;
move long-running code separate thread. in it, check whether flag set. when it's set, stop.
then, write onkeypress
event handler form. when event handler detects magic key combination has been pressed, set flag. cause thread stop doing work.
it work this:
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;
the constructor receives information need work, doesn't start doing of it. that's reserved execute
method. set freeonterminate := false
because main thread need continue have access thread object after it's begun running.
constructor tprocessproductlistthread.create(const afilename: string; aprogressbar: tprogressbar; onthreadterminate: tnotifyevent); begin inherited create(false); ffilename := afilename; fprogressbar := aprogressbar; onterminate := onthreadterminate; freeonterminate := false; end;
your code interacts gui in couple of places. needs happen gui thread, we'll extract code separate methods can passed 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;
you'll notice execute
method looks similar original code. notice how uses values saved constructor.
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 field names) , start @ second line := 1 productlist.count - 1 begin processproduct(productlist[i]); synchronize(incrementprogressbar); if terminated exit; end; productlist.free; end; end;
to start thread, create this:
processthread := tprocessproductlist.create(edtproductsfile.text, progressbar1, onprocessproductlistterminate);
handle termination event handler below. it's stuff epilogue of original code, clears processthread
; way, value can indicate whether thread still running.
procedure tform1.onprocessproductlistterminate(sender: tobject); begin thesaurus.clear; thesaurus.free; updateall; processthread := nil; end;
remember said should set flag when key pressed? in code above, flag checks thread's own terminated
property. set it, call thread's terminate
method.
procedure tform1.formkeypress(sender: tobject; var key: char); begin if char = 'x' begin processthread.terminate; processthread.free; char := #0; end; end;
Comments
Post a Comment