![]() |
![]() |
|||||||
|
Login Change Info Logout
DOWNLOADS |
by Joe Magura
Windows has always been known for its user friendly progress controls indicating that, for instance, setup is 25% done or the file copy is nearly finished. While the progress indicator many people are familiar with is the progress bar with percentage
with the new common controls for Windows comes a different version of the progress bar:
In MFC this windows control is wrapped by the CProgressCtrl class. This class provides an easy way to give your end user feedback about the progress of any lengthy processing that might otherwise lead the user to think that the application was hung or idle. While you can use a progress control anywhere you like, two common uses are on dialogs and on status bars. Examples of each of these is provided below. Use of CProgressCtrl on a DialogSince dialogs are commonly designed in the resource editor with controls being placed and sized at design time, you will generally specify many of the attributes of your progress control via the editor and the control properties dialog. Doing this side steps the use of the CProgressCtrl::Create() function which is used to specify the control's attributes when creating the control dynamically. With the control placed on the dialog you can either use Classwizard to make an association between the control and a CProgressCtrl member variable in the dialog class (use Classwizard directly or CTRL-doubleclick the progress control for the short cut to Classwizard) or use CWnd::GetDlgItem() to get a pointer to the CProgessCtrl. Once you have a way to reference the control, you can manipulate it as needed. You will likely want to initialize those attributes of the control that can not be set via the resource editor. CProgressCtrl::SetRange(),CProgressCtrl::SetPos(), and CProgressCtrl::SetStep() allow you to determine the total range of the control, the position within that range-useful for setting the initial position, and the granularity of the progress indication. These functions are best used in a WM_INITDIALOG handler so you can set the attributes prior to the display of the control. The actual use of the progress control depends on the nature of the processing you are performing that requires progress feedback. For instance, in iterative processing you can have every ith iteration of your processing loop step the control to indicate progress. Obviously you would chose a value for i and for the range of the control and step size so that when the loop completes the control is at maximum progress. CProgressCtrl::StepIt() will use the current step granularity to determine how much to lengthen the progress bar of the control. Alternatively, in processing where progress is not linear, you could use CProgressCtrl::OffsetPos() to provide more exact control of the progress display. CProgressCtrl::SetPos() can always be used to set an absolute position. Using the about box of any MFC application, place a progress control, IDC_PROGRESS1, and a button, IDC_BUTTON_STEP, on the dialog template. Associate the progress control with a member variable of the about box dialog class. You could put the following code in a WM_INITDIALOG override to initialize the control (here the control has been associated with the variable m_MyProg which is declared as CProgressCtrl m_MyProg; by the wizard).
BOOL CAboutDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// the following three lines of code were added to the
// wizard-provided override:
// set the range, initial position, and step size of
// the control (use the member variable we have
//associated with the control on the dialog via Classwizard)
m_MyProg.SetRange(0, 100);
m_MyProg.SetPos(20);
m_MyProg.SetStep(10);
// return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
return TRUE;
}
Adding a button press handler for the step button lets us step the progress control for every button press:
void CAboutDlg::OnButtonStep()
{
// step the progess control (use CWnd::GetDlgItem() to
// get a pointer to the control as an alternative to
// using the member variable)
CProgressCtrl * pProgress=(CProgressCtrl *) GetDlgItem(IDC_PROGRESS1);
pProgress->StepIt();
}
One thing you may notice about the progress control is that the size of the blocks that are used to construct the progress bar portion of the control is related solely to the height of the control—the width, range, and step size have no affect on the block size. This can lead to a fully filled progress control ending with a partial block. If this is a concern for you, you will need to size your control so that the height to width ratio results in a fully displayed final block. Use of CProgressCtrl on a Status BarIf you want to have an SDI or MDI application indicate progress of some operation (perhaps a file load), you may want to put a progress control in the status bar. This requires dynamic creation of the control since there will generally be no dialog template that describes the layout of the elements in the status bar. For simplicity, this example implements all its code in the CMainFrame class of an MDI application—this is simpler since the status bar for the frame is protected. Here are the steps to place and use the progress control on the status bar of an MDI application: Note: In the following code "magic numbers" (i.e. hardcoded values) are used for the width of the progress control and for the control's attributes. Use of magic numbers is not recommended. 1) Add a variable of type CProgressCtrl * to your CMainFrame class and initialize and delete it as shown:
from MainFrm.h:
public:
CProgressCtrl * m_pProgressCtrl;
from MainFrm.cpp:
CMainFrame::CMainFrame()
{
// initialize the control pointer so we'll know
// when it has been assigned a valid value
m_pProgressCtrl = NULL;
}
CMainFrame::~CMainFrame()
{
delete m_pProgressCtrl;
}
2) Modify the indicators structure which is declared in MainFrm.cpp to add a new pane for the progress control:
static UINT indicators[] =
{
ID_SEPARATOR, // status line indicator
ID_PROGRESS, // progress control
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
};
3) Additionally, you must add ID_PROGRESS to the string table for your project and supply a dummy string (the string's contents are irrelevant and only act as a place holder). 4) Provide a handler in your CMainFrame class for WM_SIZE. A WM_SIZE message will be received by the frame upon initial display and whenever the frame is resized. Modify it to read as follows:
void CMainFrame::OnSize(UINT nType, int cx, int cy)
{
CMDIFrameWnd::OnSize(nType, cx, cy);
if (m_wndStatusBar)
{
// get the index of the progress pane
int nIndex = m_wndStatusBar.CommandToIndex(ID_PROGRESS);
ASSERT(-1 != nIndex);
// Set the new width of the progress control pane
// (the initial width isdetermined by the contents
// of the ID_PROGRESS string in the string table)
UINT nID, nStyle;
int cxWidth;
// we only want to change the width, so get the ID
// and style and retain those
m_wndStatusBar.GetPaneInfo(nIndex, nID, nStyle, cxWidth);
m_wndStatusBar.SetPaneInfo(nIndex, nID, nStyle, 100);
// get the position and size of the progress
// control's pane
CRect rect;
m_wndStatusBar.GetItemRect(nIndex, &rect);
// only create once
if (NULL == m_pProgressCtrl)
{
m_pProgressCtrl = new CProgressCtrl;
// create the window (ID of 99 is arbitrary)
m_pProgressCtrl->Create(WS_CHILD | WS_VISIBLE,
rect,
&m_wndStatusBar,
99);
m_pProgressCtrl->SetRange(0, 100);
m_pProgressCtrl->SetPos(20);
m_pProgressCtrl->SetStep(10);
}
// else move the window so we are drawing in the right place
else
{
m_pProgressCtrl->MoveWindow(rect);
}
}
}
5) Finally, you will need some mechanism to step the progress control. One easy way is to start a timer in your CMainFrame::OnCreate() and then add a WM_TIMER handler that looks like this:
void CMainFrame::OnTimer(UINT nIDEvent)
{
// step the progress control
m_pProgressCtrl->StepIt();
CMDIFrameWnd::OnTimer(nIDEvent);
}
The progress control will continuously step, reaching its maximum and then recycling. Any resizing of the frame will result in the progress control moving to remain in the appropriate pane of the status bar. Of course, in an actual application you would likely not continuously cycle the control but instead hide it or set its current position to the minimum range so as to make it inactive. In ConclusionUsing the progress common control is an easy way to let your end user know that your application is working and not simply being unresponsive. The two examples presented here are just the tip of the iceberg when it comes to places and ways to employ this control.
|
|
|
|||||||||||||||||||||||
|
Questions or Comments? devcentral AT iticentral DOT com PRIVACY POLICY |