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
}