How to make it possible for a user to interupt a search process?

Hi again :)

I have a small program written in Delphi 6.

The program search through small textfiles (5 - 10 kB) for textstrings the user specify and list the names of all files where the text match.
It search through a specified folder and it's subfolders. There are thousands of files so in the worse case , there can be more than thousen hits.
In that case, the user may want to interupt the search process and be more specific what he search for.

In the code I use a FindFirst  and FindNext to search through all files.

How do I make it possible for the user to interupt the process?
mieowAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Wim ten BrinkSelf-employed developerCommented:
Use a boolean variable, set it to False before you loop through the files list and set it to true when the user cancels the process. While you walk through the files, you also check if this variable is set to true. If so, quit looping...

Now, the problem is that while you're in this loop, the application won't respond to any messages. So also call Application.ProcessMessages in your loop or use multiple threads and walk through the files/folders in a separate loop. The latter option has a slightly higher performance but the first option is a lot easier.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
mieowAuthor Commented:
I tried with a boolean but as you say, the application won't respond.
Can you give an example how to use Application.ProcessMessages?
0
swift99Commented:
It is generally bad practice to call ProcessMessages from within your application - it can lead to unintended (and virtually untracable) event loops with nasty side effects.  I know Borland did this in some examples, but all that means is that hey get lazy sometimes too.

Another option is to use event driven programming techniques.  Kick the process off, and at the end of the process Postmessage with the message to perform the next step.  The event loop does all of the work, and your app never stops responding.

TMyForm = class (TForm)
...
protected
    procedure CancelProcess (message: TMessage); message WM_HandleCancel;
    procedure handlenextthing (message: TMessage); message WM_HandleNext;
...
end;

procedure CancelProcess (message: TMessage);
begin
    processing := false;
end;

procedure myForm.handlenextthing (message: TMessage);
begin
    if processing and (not myDataset.EOF) then
    begin
        myDataset.Next;
        ... Do Processing ...;
        PostMessage (handle, WM_HandleNext, 0, 0);
    end;
end;

This code has not been compiled or tested (obviously), and there are some places where I would go back and look at the online docs, such as the usage of the message directive.
0
HTML5 and CSS3 Fundamentals

Build a website from the ground up by first learning the fundamentals of HTML5 and CSS3, the two popular programming languages used to present content online. HTML deals with fonts, colors, graphics, and hyperlinks, while CSS describes how HTML elements are to be displayed.

geobulCommented:
Hi,

Workshop_Alex is talking about something like (pressing Button1 starts the search and pressing Button2 stops it):

type
  TForm1 = class(TForm)
    Button1: TButton;
    RichEdit1: TRichEdit;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  stop: boolean;

implementation

{$R *.DFM}

function SearchInAFile(FileName: string; what: string): boolean;
begin
  result := true; // just for testing
  Sleep(200);
  // your code here
end;

procedure SearchFiles(DirStr: String; what: string; List: TStrings);
var
  DirInfo: TSearchRec;
  R: Integer;
begin
  R := FindFirst(DirStr + '*.*', faAnyfile, DirInfo);
  if R = 0 then begin
    repeat
      Application.ProcessMessages; // process messages inside the loop and check the boolean value
      if stop then exit;
      if (DirInfo.Name <> '.') and (DirInfo.Name <> '..') then begin
        if (DirInfo.Attr and faDirectory) <> 0 then begin
          SearchFiles(DirStr + DirInfo.Name + '\', what, List);
        end else begin
          if SearchInAFile(DirStr + DirInfo.Name, what) then
            List.Add(DirStr + DirInfo.Name);
        end;
      end;
      R := FindNext(DirInfo);
    until R <> 0;
    FindClose(DirInfo);
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  stop := false;
  SearchFiles('C:\', 'geobul', RichEdit1.Lines);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  stop := true;
end;

end.

Regards, Geo
0
Wim ten BrinkSelf-employed developerCommented:
Yep, Geo gives the example that I had in mind. However, you have to be careful when you use ProcessMessages since it could lead to an endless loop of events and other problems. Theoretically, it would allow the user to press that buttun more than once,
Thus the use of a separate thread is a better solution. The separate thread could walk through the files and folders while your main thread just keeps processing everything. However, threads also have minor, annoying issues and need some careful planning.

The most useful trick however is simple: use a splash form with a single button and display this form as a modal form. Use ProcessMessages to keep the splashform responsive and once the user presses the button on the splashform, the user is able to create other events in your application too. (The splashform just blocks the other events.) Of course, when you're done walking through all files and folders you could close the splashform too. Using a small splashform this way would be the easiest way to get around the problems that swift99 mentioned...
0
mieowAuthor Commented:
Thanks both of you, Workshop_Alex and Geo.
The solution with Application.ProcessMessages worked like a charm.
I'll have to give both of you credits for this.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.