Customizing the APRO status dialogs

Async Professional comes with several status dialogs that show the progress of particular operations.  We have an ApdFaxStatus component that displays a dialog while faxing, ApdProtocolStatus that displays a dialog while transferring file data with our ApdProtocol component, and several others.  These dialogs show just about everything that we can know about whatever the dialog is showing, but sometimes you want a different dialog that is customized to your users' needs.  Fortunately, it's pretty easy to use a dialog of your own.  To keep things simple in this tech tip, we'll concentrate on customizing the fax status dialog.  The protocol status dialog is very similar, so it should be easy to transfer this info to the protocols.

There are a few different ways to implement a new status dialog.  You could derive a new status component from our TApdAbstractFaxStatus class, or you can use the OnFaxStatus event to update your own dialog.  Updating your own dialog is the easiest way to do it, but deriving from the TApdAbstractFaxStatus class would be more re-usable in the long run. 

Since we're designing a new dialog, let's start off with a new form.  To keep things real simple, yet still provide a small glimpse into what you can do, add the following components to the form: TLabel, TButton, and a TAnimate.  The label will be used to display status text, the button will be used to cancel the fax if desired, and the Animate control will be used to display one of the nifty common AVI movies (if your compiler doesn't have TAnimate, don't worry, you can substitute another TLabel and have it say something like "This is a placeholder for a real cool graphic").  Arrange the components into a format that you find somewhat appealing, this is how I've done it:



We'll want a method to update all of the controls from; I called my updating method UpdateValues.  To make things easier to read, we'll pass in the fax component that we're doing the status for.  The ApdSendFax and ApdReceiveFax components are derived from the TApdAbstractCustomFax class, so use that as the parameter type.  The entire dialog declaration now looks like this:


  TNewFaxStatusDisplay = class(TForm)

    Animate1: TAnimate;

    Button1: TButton;

    Label1: TLabel;


    procedure UpdateValues(Fax : TApdCustomAbstractFax);



The UpdateValues method will use the properties of the Fax that is passed in to update the visual controls.  The TApdCustomAbstractFax is declared in the AdFax.pas unit, so go ahead and add that unit to your uses clause.  While you're there, add OoMisc; that is where the FaxProgress values are kept.  The Fax.FaxProgress property will tell you what the Fax is doing.  See the APRO 3 Reference Guide (the thick book) on page 616 618 for details on what the different FaxProgress values indicate, as well as descriptions of other properties that you may want to display.  Here's what I did to update the status label with a short description of what the Fax is doing and change the TAnimate's AVI.  I'm just using the CommonAVI movies, so the pictures won't necessarily match up with what the Fax is doing, but you can replace the AVIs with ones of your own.


procedure TNewFaxStatusDisplay.UpdateValues(Fax: TApdCustomAbstractFax);
  { update our status label }
  case Fax.FaxProgress of
    fpInitModem : Label1.Caption := 'Initializing the modem';
    fpDialing   : Label1.Caption := 'Dialing ' + TApdSendFax(Fax).PhoneNumber;
    fpBusyWait  : Label1.Caption := 'Line was busy, waiting to retry...';
    fpSendPage  : Label1.Caption := 'Page data being transmitted';
    fpSendPageStatus : Label1.Caption :='Page ' + 'IntToStr(Fax.CurrentPage)'
      + ' complete, awaiting confirmation';
    fpPageError : Label1.Caption := 'Error while sending page ' +
      IntToStr(Fax.CurrentPage) + ', please resend';
    fpPageOK    : Label1.Caption := 'Page ' + IntToStr(Fax.CurrentPage)
      + ' received OK';
    fpWaiting   : Label1.Caption := 'Waiting for fax';
    fpNoConnect : Label1.Caption := 'Last call was not a fax';
    fpAnswer    : Label1.Caption := 'Answering...';
    fpIncoming  : Label1.Caption := 'Incoming call is a fax';
    fpGetPage   : Label1.Caption := 'Page data being received';
    fpGetPageResult  : Label1.Caption := 'Page ' + IntToStr(Fax.CurrentPage)
      + ' received';
    fpCheckMorePages : Label1.Caption := 'Waiting for more pages';
    fpGetHangup : Label1.Caption := 'Hanging up';
    fpSessionParams  : Label1.Caption := 'Got session parameters';
    fpGotRemoteID : Label1.Caption := 'Connected to ' + Fax.RemoteId;
    fpCancel    : Label1.Caption := 'Cancelling';
    fpFinished  : Label1.Caption := 'Finished';
  { update the animation type }
  case Fax.FaxProgress of
    { show aviFindFolder while waiting for something }
    fpWaiting..fpIncoming   : Animate1.CommonAVI := aviFindFolder;
    { show aviDeleteFile while sending the fax }
    fpSendPage..fpPageOK    : Animate1.CommonAVI := aviDeleteFile;
    { show aviCopyFile while receiving the fax }
    fpGetPage..fpCheckMorePages : Animate1.CommonAVI := aviCopyFile;
    { show aviFindFile when negotiating }
    fpSessionParams, fpGotRemoteID : Animate1.CommonAVI := aviFindFile;
  { make sure the animation is playing }
  if Animate1.CommonAVI <> aviNone then
    Animate1.Active := True;

Now all we need is to put some code behind the Cancel button and we're done with the dialog.  To cancel a fax, you need to call the CancelFax method of the fax component.  Our dialog has no knowledge of the fax component, except while the UpdateValues method is executing.  You could set a flag in the button click event and pick it up the next time UpdateValues runs, or just call the form's Owner's Fax.CancelFax method (the owner of the form is going to be our installable status component, and that will have a Fax property)  To do all this, make your button click event look like this:


procedure TNewFaxStatusDisplay.Button1Click(Sender: TObject);


That's all there is to the dialog itself, now we can do the installable component part.

Our new fax status component needs to be derived from the TApdAbstractFaxStatus class.  The ApdSendFax and ApdReceiveFax.StatusDisplay properties will be looking for components descended from TApdAbstractFaxStatus, and calling methods declared in that class.


The TApdAbstractFaxStatus class is pretty simple.  It has three abstract methods that must be overridden, and one variable that must be added before it can be a functional interface between your fax component and the dialog.   Add the following shell below the status dialog's type declaration:


  TNewFaxStatus = class(TApdAbstractFaxStatus)
    Fax : TApdCustomAbstractFax;
    procedure CreateDisplay; override;
    procedure DestroyDisplay; override;
    procedure UpdateDisplay(const First, Last : Boolean); override;


The fax component will call the CreateDisplay method when it is ready to create the dialog; the DestroyDisplay method when it is done with the dialog, and the UpdataDisplay method when something has changed and the dialog should be updated.  Pretty simple, eh?


My dialog doesn't need anything explicitly initialized or created, so all the CreateDisplay method needs to do is create the dialog itself.  If you needed to initialize anything, or create something, this is the place to do it.


procedure TNewFaxStatus.CreateDisplay;
  { Display is declared in the TApdAbstractFaxStatus class as a TForm }
  Display := TNewFaxStatusDisplay.Create(Self);


Since my dialog doesn't create anything special, it doesn't need to destroy anything except for the dialog itself.


procedure TNewFaxStatus.DestroyDisplay;
  if Assigned(Display) then


The UpdateDisplay method is where all the work happens.  The First parameter will be True on the first time the method is called in the fax session, you will usually want to initialize things then.  The Last parameter will be True for the final status display; you can do whatever cleanup you need to then.  When First is False and Last is False, you get the opportunity to update the dialog to reflect the status of the session.  We've already created the UpdateValues method in the dialog so we'll just call that.  Since Display is declared as a TForm, we'll need to typecast it to a TNewFaxStatusDisplay.


procedure TNewFaxStatus.UpdateDisplay(const First, Last: Boolean);
  if First then begin
  if Last then
    Display.Visible := False
  else begin


To install this new component on to the APRO Fax tab of the component palette, add this method:


procedure Register;
{$R *.DFM}
procedure Register;
  RegisterComponents('APRO Fax', [TNewFaxStatus]);


Once you save everything you can install it using the usual techniques.  To test it, create a new project and add a TApdComPort, TApdSendFax, TButton and the newly installed component on the form.  Set the TApdComPort.ComNumber to the port number of the faxmodem you want to use.  Set the TApdSendFax.FaxFile property to the path\name of an APF to send (you can use APROLOGO.APF in your APRO\Examples\{compiler} folder), and the PhoneNumber property to the number of a fax machine to test with.  The TApdSendFax.StatusDisplay property should be pointing to your new component automatically.  Create an OnClick event handler for the button and make it look like this:

procedure TForm1.Button1Click(Sender: TObject);

Compile, run, click the button, and watch your new status dialog in action.  If you've followed what I did, you should see a minimal but visually stunning dialog much like this one:




This site is not affiliated, endorsed, or otherwise associated with the entity formerly known as TurboPower Software. The owners and maintainers of were merely meager employees of the aforementioned organization, providing this site out of the pure goodness of their collective hearts. Logo

Last updated: July 22, 2003.