Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

How to force listening to buttonclick

Posted on 2014-02-24
12
Medium Priority
?
280 Views
Last Modified: 2014-02-25
Hi,

In my application I do some fast processing. When the processing starts I want to be able to pause it.
For this purpose I have added a pause-button to the form. The only thing is, that when I press the button it doesn't react immediately. Sometimes I have to press it multiple times before it works. Meanwhile processing takes on.
Is there a way to make sure that the buttonclick will always be noticed and processing of the job is paused immediately?
0
Comment
Question by:Delphiwizard
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 4
  • 2
  • +1
12 Comments
 
LVL 24

Expert Comment

by:jimyX
ID: 39882360
It depends on what you are doing, and what easy changes to be made to catch the button OnClick.

From top of my mind i can say use "Application.ProcessMessages" to process the button's code. But you need to use with care as it enforces processing all the queued messages.
0
 

Author Comment

by:Delphiwizard
ID: 39882605
I'll try to use it and see what happens.
0
 
LVL 27

Assisted Solution

by:Sinisa Vuk
Sinisa Vuk earned 400 total points
ID: 39882972
you can use threaded job to accomplish this. (Like BMThread). Thread will not stop your app and it can be easily stopped/paused.
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
LVL 38

Accepted Solution

by:
Geert Gruwez earned 1600 total points
ID: 39884862
here is a sample on how to use threading with a slow frontend
http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/A_6613.html

to add pausing and resuming you need access to thread instance.
changing the procedure into a function solves that
function LoadData(obj: TObject; DataLoaded: TDataLoadedProc): TLoadDataThread;
begin
  Result := nil;
  if not mLoadDataThreadRunning then
  begin
    mLoadDataThreadRunning := True;
    Result := TLoadDataThread.Create(Obj, DataLoaded);
  end;
end;

Open in new window


off course you need to save the result of that function in your form instance
  TfrmEEThreads = class(TForm)
  ... 
  private
    fLoadingThread: TThread;
  end;

procedure TfrmEEThreads.btnShowDataClick(Sender: TObject);
begin
  // Call procedure and pass grid to load and proc to load the grid
  fLoadingData := LoadData(sgData, ShowData);
end;

Open in new window

the button would simply do pause/resume the thread
procedure TfrmEEThreads.btnPause(Sender: TObject);
begin
  if (fLoadingData <> nil) then 
    fLoadingData.Pause;
end;

procedure TfrmEEThreads.btnResume(Sender: TObject);
begin
  if (fLoadingData <> nil) then 
    fLoadingData.Resume;
end;

Open in new window

0
 

Author Closing Comment

by:Delphiwizard
ID: 39885000
Thank you all for the support.
I'll went for the approach suggested by Geert Gruwez. The posted article is great Geert.
0
 

Author Comment

by:Delphiwizard
ID: 39885141
@Geert Gruwez:
Using your example: I've tried to change the procedure into a function, but I get an error.
[DCC Error] uEELoadData.pas(35): E2065 Unsatisfied forward or external declaration: 'TLoadDataThread.LoadData'

Can you point me in the right direction?

unit uEELoadData;

interface

uses Classes;

const
  WaitSleep = 500;

type
  TDataLoadedProc = procedure (obj: TObject; List: TStrings) of object;
  TDataProgressProc = procedure (obj: TObject; ProcentDone: integer) of object;

implementation

uses SysUtils;

var
  mLoadDataThreadRunning: boolean;

type
  TLoadDataThread = class(TThread)
  private
    fDataLoaded: TDataLoadedProc;
    fDataProgress: TDataProgressProc;
    fObj: TObject;
    fList: TStrings;
    fProcentDone: integer;
    procedure DoDataLoaded;
    procedure DoProgress;
    function LoadData(obj: TObject; DataLoaded: TDataLoadedProc; DataProgress: TDataProgressProc): TLoadDataThread;
  protected
    procedure ReportProgress(ProcentDone: Integer);
    procedure Execute; override;
    property List: TStrings read fList;
  public
    constructor Create(Obj: TObject; DataLoaded: TDataLoadedProc; DataProgress: TDataProgressProc); reintroduce; virtual;
    destructor Destroy; override;
  end;

{ TLoadDataThread }

constructor TLoadDataThread.Create(Obj: TObject; DataLoaded: TDataLoadedProc; DataProgress: TDataProgressProc);
begin
  // Create thread not suspended
  inherited Create(False);
  // When finished, autofree
  FreeOnTerminate := True;
  // remember parameters
  fObj := Obj;
  fDataLoaded := DataLoaded;
  fDataProgress := DataProgress;
  fList := TStringList.Create;
end;

destructor TLoadDataThread.Destroy;
begin
  fList.Free;
  inherited Destroy;
end;

procedure TLoadDataThread.Execute;
const
  DataRows = 10;
  DataCols = 5;
var I, J: Integer;
  temp: string;
begin
  // Create the data
  List.Values['ROWS'] := IntToStr(DataRows +1);
  List.Values['COLS'] := IntToStr(DataCols +1);
  for I := 1 to DataRows +1 do
    for J := 1 to DataCols +1 do
    begin
      temp := '';
      if (J = 1) and (I > 1) then
        temp := Format('Row %d', [I-1])
      else if (I = 1) and (J > 1) then
        temp := Format('Column %d', [J-1])
      else if (J > 1) and (I > 1) then
        Temp := Format('Data %d_%d', [I-1, J-1]);
      List.Values[Format('%d_%d', [I, J])] := Temp;
      ReportProgress(Trunc(((I-1) * (DataCols+1) + J-1) / ((DataRows+1) * (DataCols+1))*100));
      Sleep(WaitSleep);
    end;
  ReportProgress(100);
  // Call the show procedure with the obj to show the created data in
  Synchronize(DoDataLoaded);
end;

procedure TLoadDataThread.ReportProgress(ProcentDone: Integer);
begin
  fProcentDone := ProcentDone;
  Synchronize(DoProgress);
end;

procedure TLoadDataThread.DoDataLoaded;
begin
  // Make sure we have all items assigned
  if Assigned(fDataLoaded) and Assigned(fObj) then
    fDataLoaded(fObj, fList);

  // clear the flag to stop a second thread
  mLoadDataThreadRunning := False;
end;

procedure TLoadDataThread.DoProgress;
begin
  if Assigned(fDataProgress) then
    fDataProgress(fObj, fProcentDone);
end;

function LoadData(obj: TObject; DataLoaded: TDataLoadedProc; DataProgress: TDataProgressProc): TLoadDataThread;
begin
  Result := nil;
  if not mLoadDataThreadRunning then
  begin
    mLoadDataThreadRunning := True;
    Result := TLoadDataThread.Create(Obj, DataLoaded, DataProgress);
  end;
end;

initialization
  mLoadDataThreadRunning := False;

end.

Open in new window

0
 
LVL 27

Expert Comment

by:Sinisa Vuk
ID: 39885157
As I can see - you must create thread as suspended:
inherited Create(False);

Open in new window


Later - after you call function and it returns thread - do call Resume.
0
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 39885173
i see, you used 2 articles, the progress and the loaddata ... :)

 you've made a method function of an ordinary function
the loaddata is not part of the Thread class

the mainform uses the TThread ancestor class for resume and pause

the ordinary function will create a thread on the fly
> doesn't really matter if it's started immediately

the one thing still needed is cleanup
the thread should still call a finishing routine when finished to reset the variable for the thread to nil
or you'll get AV's here and there

hmmm, it's been a while since i worked with this code...
i'll try and create a sample with cleanup and multiple threads
0
 

Author Comment

by:Delphiwizard
ID: 39885236
That would be great. :-)
0
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 39885288
well ... here the sample is
what the threads do is rather trivial in this sample ... count to 100 and sleep a little

the simulation
> start 2 threads
> when they have both finished, start a 3rd thread
> when that 3rd thread is finished optionally start the first 2 again
and so on ...

ooo ... crap, no delphi dproj files allowed.
i'll add an attention for the mods :)

here is the zipped project:
prjEEThreads.zip
0
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 39885308
change the last line in the main unit to take the checkbox into account ... :)

  if Task3Done and chkRepeatSimul.Checked and (fThreadTask1 = nil) and  (fThreadTask2 = nil) then
    btnStartSimul.Click;
end;

end.

Open in new window

0
 

Author Comment

by:Delphiwizard
ID: 39886187
Hi Geert,

That is some great simulation, thank you...
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
In this video, Percona Solution Engineer Dimitri Vanoverbeke discusses why you want to use at least three nodes in a database cluster. To discuss how Percona Consulting can help with your design and architecture needs for your database and infras…
In this video, Percona Director of Solution Engineering Jon Tobin discusses the function and features of Percona Server for MongoDB. How Percona can help Percona can help you determine if Percona Server for MongoDB is the right solution for …
Suggested Courses

722 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question