Adding a progress bar dialog to 16- and 32-bit OWL apps



Date: 19 May 1998
Author: Greg Chicares
 

Here's a progress bar dialog class I've written and placed in the public domain. It displays progress both as text and, graphically, as a percentage:

 

If you hit the Cancel button, execution will stop after the current item is done.

I've tested this with 16- and 32-bit BC++5.02 projects. I left the AppExpert tags in so that you can use ClassExpert to modify the source if you like.

Example

Create an AppExpert project named "test" and accept all defaults. Add progress.cpp to your .exe target, and insert
    #include progress.rc
in your .rc file. Run ClassExpert on TTestEditView and install a handler for CM_EDITUNDO. In the .cpp file, replace the CmEditundo() handler with the following code. 

#include <classlib\time.h>
void DoSomethingThatTakesAWhile()
{
  ClockTy s = TTime().Seconds();
  for(;;)
    if(s < TTime().Seconds())
      break;
}

#include "progress.hpp"
unsigned MaximumNumberOfTimes = 7;
void TTestEditView::CmEditundo()
{
  TEditView::CmEditUndo();
  // INSERT>> Your code here.
  TProgressDialog* Progress = new TProgressDialog
    (GetApplication()->GetMainWindow(), MaximumNumberOfTimes);
  Progress->Create();  // modeless

  for(unsigned j = 0; j < MaximumNumberOfTimes; j++)
    {
    if(!Progress->HWindow)
      break// canceled

    DoSomethingThatTakesAWhile();
    Progress->ShowProgress(1 + j);
    }

  // next line just pauses to let you see the gauge hit 100%
  DoSomethingThatTakesAWhile();
  delete Progress;
}

FILE PROGRESS.CPP

// Delete next two lines if you're not doing precompiled headers this way
#include <owl/pch.h>
#pragma hdrstop

#include <stdio.h>      // sprintf()
#include <stdlib.h>     // max(), min()
#include "progress.hpp"

//{{TProgressDialog Implementation}}
static TProgressDialogXfer TProgressDialogData;

//============================================================================
TProgressDialog::TProgressDialog
  (TWindow*         parent
  ,double           MaxVal
  ,double           MinVal
  ,char const*const Caption
  ,char const*const TextFormat
  ,char const*const GaugeFormat
  ,TResId           resId
  ,TModule*         module
  )
  :TDialog     (parent, resId, module)
  ,MaxVal      (MaxVal)
  ,MinVal      (MinVal)
  ,TextFormat  (TextFormat)
  ,GaugeFormat (GaugeFormat)
{
//{{TProgressDialogXFER_USE}}
  OWLGAUGE = new TGauge(this, IDC_OWLGAUGE);
  PROGRESS_TEXT = new TStatic(this, IDC_PROGRESS_TEXT, 255);

  SetTransferBuffer(&TProgressDialogData);
//{{TProgressDialogXFER_USE_END}}

  // INSERT>> Your constructor code here.
  SetCaption(Caption);

  OWLGAUGE->SetNativeUse(nuNever);
  OWLGAUGE->SetLed(0, 0);
}

//============================================================================
TProgressDialog::~TProgressDialog()
{
  // This object doesn't exist when TDialog::~TDialog() calls Destroy()
  if(HWindow)
    Destroy();
  // INSERT>> Your destructor code here.
}

//============================================================================
void TProgressDialog::SetupWindow()
{
  TDialog::SetupWindow();
  // INSERT>> Your code here.
  OWLGAUGE->SetCaption(GaugeFormat);  // done here cuz it needs hwnd
  // Note: range is (0, 100) by default

  ShowProgress(0);

  // Disable parent window so user can't do other stuff there
  Parent->EnableWindow(false);
}

//============================================================================
void TProgressDialog::Destroy(int)
{
  // Let parent window regain focus
  Parent->EnableWindow(true);
  TDialog::Destroy();
  // INSERT>> Your code here.
}

//============================================================================
void TProgressDialog::ShowProgress(double DoneSoFar)
{
  unsigned percentage = static_cast<unsigned>
    (100.5 * (DoneSoFar - MinVal) / (MaxVal - MinVal));
    // 100%, + .5 to round to nearest because the cast truncates
  percentage = max(0U, min(100U, percentage));
  OWLGAUGE->SetValue(percentage);

  sprintf
    (TProgressDialogData.PROGRESS_TEXT
    ,TextFormat
    ,static_cast<int>(DoneSoFar)
    ,static_cast<int>(MaxVal)
    );
  PROGRESS_TEXT->SetText(TProgressDialogData.PROGRESS_TEXT);
  GetApplication()->PumpWaitingMessages();
}

FILE PROGRESS.HPP

#if !defined(progress_hpp)
#define progress_hpp

// Delete next two lines if you're not doing precompiled headers this way
#include <owl/pch.h>
#pragma hdrstop

#ifndef OWL_DIALOG_H
  #include <owl/dialog.h>
#endif
#ifndef OWL_STATIC_H
  #include <owl/static.h>
#endif
#ifndef OWL_GAUGE_H
  #include <owl/gauge.h>
#endif

#include "progress.rh"

#include <services/preclass.h>

//{{TDialog = TProgressDialog}}
struct TProgressDialogXfer {
//{{TProgressDialogXFER_DATA}}
  char PROGRESS_TEXT[ 255 ];
//{{TProgressDialogXFER_DATA_END}}
};

class TProgressDialog
  :public TDialog
{
public:
  // Leave original ctor here for rescan: it uses the first ctor it finds,
  // even if it's in a comment
  // TProgressDialog(TWindow* parent, TResId resId = IDD_PROGRESSDLG, TModule* module = 0);
  TProgressDialog
  (TWindow*         parent
  ,double           MaxVal      = 100.0
  ,double           MinVal      = 0.0
  ,char const*const Caption     = "Progress"
  ,char const*const TextFormat  = "Completed %d of %d"
  ,char const*const GaugeFormat = "%d%%"
  ,TResId           resId       = IDD_PROGRESSDLG
  ,TModule*         module      = 0
  );
  virtual ~TProgressDialog();
  void ShowProgress(double DoneSoFar);

protected:
  TGauge*          OwlGauge;
  const double     MaxVal;
  const double     MinVal;
  char const*const TextFormat;
  char const*const GaugeFormat;

//{{TProgressDialogVIRTUAL_BEGIN}}
public:
  virtual void SetupWindow();
  virtual void Destroy(int retVal = IDCANCEL);
//{{TProgressDialogVIRTUAL_END}}

//{{TProgressDialogXFER_DEF}}
protected:
  TStatic* PROGRESS_TEXT;
  TGauge*  OWLGAUGE;
//{{TProgressDialogXFER_DEF_END}}
};    //{{TProgressDialog}}

#include <services/posclass.h>

#endif

FILE PROGRESS.RH

#define IDD_PROGRESSDLG   23001
#define IDC_PROGRESS_TEXT 23002
#define IDC_OWLGAUGE      23003

FILE PROGRESS.RC

#include "progress.rh"

IDD_PROGRESSDLG DIALOG 0, 0, 200, 70
STYLE DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION
CAPTION "Progress"
FONT 8, "MS Sans Serif"
{
 CONTROL "Cancel", IDCANCEL, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 75, 48, 50, 14
 CONTROL "", IDC_OWLGAUGE, "OWL_Gauge", WS_CHILD | WS_VISIBLE, 20, 25, 160, 14
 CONTROL "", IDC_PROGRESS_TEXT, "static", SS_CENTER | WS_CHILD | WS_VISIBLE, 20, 7, 160, 14
#ifdef __WIN32__
                                                                                           , WS_EX_STATICEDGE
#endif
}