1. Technology

How to Display a Progress Bar for a TBatchMove Operation

By

How to Display a Progress Bar for a TBatchMove Operation

While the BDE might be deprecated by Borland, there are still many developers using it to build various database applications.

Recently, I had to move some (very old) FoxPro tables over to a database server (Interbase). The natural choice for the component to do the task was the TBatchMove. This powerful component performs database operations on groups of records or entire tables using the BDE.

Progress of a Batch Move operation?

When you set the properties of the BatchMove component (Source, Destination, Mode, etc.) and call the Execute method, the actuall process happens "behind the scenes".
Suppose you need to move 1 milion records from one database table to another (database). No metter how fast the machine is, some time will pass before the operation finishes.

To let the user know that the application is running, you might want to add the progress bar to show the actuall progress value.

Since the TBatchMove does not provide any event to handle, in order to get the progress value, and as the Help system suggest, the only way to show a progress indicator is to "dive" into BDE callbacks.

TBDECallback & cbGENPROGRESS
The TBDECallback class is a wrapper for a Borland Database Engine callback function.

When you install a callback function to the BDE, the BDE will "call back" to a function in your application, letting your application know when certain events take place, and in some cases, allow your application to return information back to the BDE.

While TBDECallback's constructor might look scary, it's not so hard to "crack".

There are 3 main points you need to know in order to create a BDE callback for a BDE operation progress value:

  1. The CBType parameter should be set to cbGENPROGRESS.
  2. The CBBuf parameter (and CBBufSize) should "point" to the correct callback descriptor defined in the BDE.pas unit. In the cbGENPROGRESS case this is CBPROGRESSDesc.
  3. The CallbackEvent parameter points to the function that the BDE will call. The CBInfo it gets maps to the CBPROGRESSDesc record.
The BDE will call back to your application every so often, reporting either a text message containing the number of records it has processed or how far the batch move has progressed, expressed as an integer percentage.

The CBPROGRESSDesc structure contains the following two fields: szMsg and iPercentDone.
If the iPercentDone of the callback structure is greater than -1, then the percentage is correct and you can update your progress bar. If the percentage reported is less than zero, the callback has received a text message in the szTMsg field containing a message that includes the number of records processed ("Records appended: XYZ").

BatchMove Progress Example
Drop a TBacthMove ("BatchMove1") component on a form ("Form1") along with two TTable objects ("TableSRC" and "TableDesc"). A button named "ExecuteButton" will start a "batCopy" operation on the tables.

procedure TForm1.ExecuteButtonClick(Sender: TObject) ;
var
   bdec : TBDECallback;
   cbDataBuff : CBPROGRESSDesc;
begin
   ProgressBar1.Position := 0;
   with BatchMove1 do
   begin
     Source := TableSRC;
     TableDEST.TableName := TableSRC.TableName + '_copy';
     Destination := TableDEST;
     Mode := batCopy;
     RecordCount := 0; //all
     try
       bdec := TBDECallback.Create(nil,TableSRC.Handle,cbGENPROGRESS,@cbDataBuff, SizeOf(cbDataBuff),BatchProgressCallback,true) ;
       try
         Execute;
         ShowMessage(Format('%d records copied.',[MovedCount])) ;
       finally
         FreeAndNil(bdec) ;
       end;
     except on E:Exception do
       begin
         showmessage(E.Message) ;
       end;
     end;
   end;
end; //ExecuteButtonClick

function TForm1.BatchProgressCallback(CBInfo: Pointer): CBRType;
var
   s : string;
begin
   if pCBPROGRESSDesc(cbInfo).iPercentDone < 0 then
   begin
     //"Records appended: XYZ"
     s := pCBPROGRESSDesc(cbInfo).szMsg;
     Delete(s, 1, Pos(': ', s) + 1) ;
     ProgressBar1.Position := Round((StrToInt(s) / TableSRC.RecordCount) * 100) ;
   end
   else
   begin
     ProgressBar1.Position := pCBPROGRESSDesc(cbInfo).iPercentDone;
   end;

   result := cbrCONTINUE;
end; //BatchProgressCallback

And that's all.

  1. About.com
  2. Technology
  3. Delphi
  4. Build Database Applications
  5. BDE
  6. How to Display a Progress Bar for a TBatchMove Operation (in Delphi applications)

©2014 About.com. All rights reserved.