Create a new project and drag a Progress Control over from your tool box. You can
resize it to the desired effect you would like. Also drag four Static Text controls over
for the text we will be sending to the dialog box. Just below WinMain you will notice
a new structure INTCOMMONCONTROLSEX. We are going to use this to tell it we want to use a
progress bar. Place your curser in front of INTCOMMONCONTROLSEX and press the F1 key.
You can see all the bit flags that you can use. We will be using the ICC_PROGRESS_CLASS
to load our progress bar. At the bottom of the page you will see that we need to include
a new header #include "commctrl.h".
You send a message to it telling it to update...
do item 1...
//set progres bar to 10 percent done
SendDlgItemMessage( hwnd, IDC_PROGRESS1, PBM_SETPOS, 10, 0 );
do item 2...
//set progress bar to 40 percent done
SendDlgItemMessage( hwnd, IDC_PROGRESS1, PBM_SETPOS, 40, 0 );
do item 3...
//set progess bar to 70 percent done
SendDlgItemMessage( hwnd, IDC_PROGRESS1, PBM_SETPOS, 70, 0 );
PBM_SETPOS is the message you send it, and the 4th parameter is the amount to update. (0 through 100). Neat huh?
Here we are manually incrementing the progress bar 10,40 and 70. If you wanted the progress bar to increment
depending lets say on the remaining bytes that need to be copied you could do the following.
You will need to search the help files for fseek and ftell :)Here is a snippet..
//Open the source file
pSource = fopen( pSource,"rb" );
//Seek to the end of the file
fseek( pSource, 0, SEEK_END );
//The amount counted = count
int count = ftell( pSource );
//rewind to the beginining
fseek( pSource, 0, SEEK_SET );
pDest = fopen( final,"wb" );
int current =0;
while ( fread( &byte, sizeof( unsigned char ), 1, pSource) != 0 )
{
current++;
float progress = (float) current / count;
int totalProgress = (int) (progress * 100);
SendDlgItemMessage( passhwnd, IDC_PROGRESS1,
PBM_SETPOS, totalProgress, 0 );
CheckMessages( );
fwrite( &byte, sizeof( unsigned char ), 1, pDest );
}
fclose( pSource );
fclose( pDest );
You take the total amount of items ( or bytes above )and divide that by the current item ( or byte )you are on then multiply by 100....
if I had 500 items and i was on item 10 it would be
10 / 500 = .02
.02 * 100 = 2 which is 2% done :)
the only trick is you need to cast them to float to do the divide (because if they are just ints it'll round to 0)
float progress = (float) amountDone / totalAmount;
int totalProgress = (int) (progress * 100);
we do the progress * 100 inside paranthesis so it keeps the accuracy of the float value and then it turns it into an int as it's putting it in the totalProgress variable.
I will use a new function to slow down our program so that you can watch the progress bar increment. Without
this function the program would appear and disappear faster than you could see the bar move. The function I use
is Sleep()
//this will suspend our code from
//running for 500 milliseconds
Sleep(500);
The Sleep function suspends the execution of the current thread for at least the specified interval.
This brings up a problem that we can handle now as well...
Remember that windows is messaged based. Since I am calling Sleep() four times, I am not allowing Windows
to check for messages for about two seconds. If you tried to move the dialog box while it was running it
would freeze up and wouldn't repaint. I haven't showed you how to actually let windows handle other messages, so I'll show you now.
MSG msg;
//check the message queue,
//if there is a message in there, remove it
//and dispatch it to wherever it needs to go
if ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage ( &msg );
}
You could put that code in a function that lets it handle 10 messages.
void CheckMessages( )
{
for ( i = 0; i < 10; i++ )
{
MSG msg;
//check the message queue, if
//there is a message in there,
//remove it and dispatch it to
//wherever it needs to go
if ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage ( &msg );
}
else
{
//if there are no other messages in the queue
//then we can break out of this function
break;
}
}
}
Now you could put that every so often in your code (as your code is looping
through stuff) and windows will then routinely handle the other messages it needs to.
You can see how I used it in the code below :)
__________________________________________________________
#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <windows.h>
#include "resource.h"
#include "commctrl.h"
#pragma comment ( lib, "comctl32.lib" )
//function to let windows check for messages
void CheckMessages( )
{
int i;
for ( i = 0; i < 10; i++ )
{
MSG msg;
//check the message queue, if there
//is a message in there, remove it
//and dispatch it to wherever it needs to go
if ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage ( &msg );
}
else
{
//if there are no other messages in the queue
//then we can break out of this function
break;
}
}
}
INT_PTR CALLBACK DialogMessages(HWND hwnd,UINT
uMsg,WPARAM wparam,LPARAM lparam)
{
if ( uMsg == WM_COMMAND )
{
if ( HIWORD(wparam) == BN_CLICKED )
{
if (LOWORD(wparam) == IDOK)
{
SendDlgItemMessage( hwnd,IDC_LINE1,WM_SETTEXT,0,
(LPARAM) "First line" );
//advance the progress bar to 25%
SendDlgItemMessage( hwnd, IDC_PROGRESS1,
PBM_SETPOS, 25, 0 );
Sleep(500);
CheckMessages( );
SendDlgItemMessage( hwnd,IDC_LINE2,WM_SETTEXT,0,
(LPARAM) "Second Line" );
//advance the progress bar to 50%
SendDlgItemMessage( hwnd, IDC_PROGRESS1,
PBM_SETPOS, 50, 0 );
Sleep(500);
CheckMessages( );
SendDlgItemMessage( hwnd,IDC_LINE3,WM_SETTEXT,0,
(LPARAM) "Third Line" );
//advance the progress bar to 75%
SendDlgItemMessage( hwnd, IDC_PROGRESS1,
PBM_SETPOS, 75, 0 );
Sleep(500);
CheckMessages( );
SendDlgItemMessage( hwnd,IDC_LINE4,WM_SETTEXT,0,
(LPARAM) "Last Line" );
//advance the progress bar to 100%
SendDlgItemMessage( hwnd, IDC_PROGRESS1,
PBM_SETPOS, 100, 0 );
Sleep(500);
CheckMessages( );
EndDialog( hwnd, 0 );
return TRUE;
}
else if (LOWORD(wparam) == IDCANCEL)
{
EndDialog( hwnd, 0 );
return TRUE;
}
}
}
return FALSE;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE
hPrevInstance, LPSTR pCmdLine, int iCmdShow)
{
//structure
INITCOMMONCONTROLSEX controls;
//Set of bit flags that indicate which
//common control classes will be loaded
controls.dwICC = ICC_PROGRESS_CLASS;
//Size of the structure, in bytes.
controls.dwSize = sizeof(INITCOMMONCONTROLSEX);
//function
//tells windows to load any controls specified in dwICC
InitCommonControlsEx(&controls);
DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_PROG),
NULL, DialogMessages);
return 0;
}