[WTL] CProgressDlg
Файлы
Пример использования и сам класс в файле ProgressDlg.h лежит здесь
Используемые библиотеки
Скриншоты
Описание
К сожалению, современные компьютеры еще не настолько быстрые, чтобы выполнять все, что надо от них пользователю, мгновенно. Естественно, что эти операции делают в отдельном потоке, чтобы те, кто сидит за компьютером, не думали, что программа повисла. При этом хорошо бы было еще показывать процент выполнения и оставшееся время до конца операции. Вот для облегчения этого случая я и написал этот класс. Только здесь надо сказать об одном предположении. Считается, что во время выполнения операции пользователь больше ничего не может делать паралелльно, т.е. процесс выполнения показывается в модальном диалоге.
Вообще то CProgressDlg я делал ужасно давно, уже даже не помню под какую версию Visual C++. А тут недавно мне напомнили про этот класс, я попробовал его скомпилить в Visual C++ 2005, получил ошибки и, мягко выражаясь, удивился насколько плохо был написал этот класс. Поэтому сейчас я его значительно исправил, да и описание дополнил.
Использование
- Создать структуру параметров для потока, например
{
int foo;
int bar
};
В будущем этот тип будет передаваться в качестве параметра шаблона.
- Создать в ресурсах диалог, например, пусть у него идентификатор будет IDD_PROGRESS. У этого диалога должно быть текстровое поле, в которое будет писаться оставшееся время, например с идентификатором IDC_TIME.
- Создать потоковую функцию такую, как описано в MSDN. Т.е. она должна иметь вид
Только здесь есть одна особенность. В эту функцию передается не та структура, которую мы создали ранее на первом шаге (ThreadParams), а другая, описанная ниже
{
T* pParams;
IProgress* pProgress;
};
Здесь тип T как раз и должен быть типом для параметра, который мы определили выше (в данном случае ThreadParams), первое поле pParams - это и есть этот самый параметр, а второй - указатель на интерфейс работы с диалогом. Он объявлен вот так:
{
public:
virtual void SetProgressRange (int minval, int maxval, int currval) = 0;
virtual void SetProgress(int val) = 0;
};
Функция SetProgressRange() задает интервал некоторой измеряемой величины, которая символизирует процент выполнения, а SetProgress() устанавливает новый процент. Слово "процент" здесь используется как аналогия, т.е. величина может меняться в любых пределах.
- Создаем переменную типа CProgressDlg.
¶ms,
_T("Пожалуйста, подождите") );
В шаблон класса мы передаем тип параметров, идентификатор диалога IDD_PROGRESS и идентификатор текстового поля IDC_TIME. Конструктор класса CProgressDlg принимает функцию, выполняемую в отдельном потоке, параметры для потока (переменная станет членом pParams) и заголовок диалога.
Вот пример функции потока:
DWORD WINAPI ThreadFunc (void* params)
{
// Получаем экземпляр класса ProgressParam<ThreadParams>,
// который хранит указатель на IProgress и на параметры
ProgressParam<ThreadParams> *pp = (ProgressParam<ThreadParams>*)params;
// Получаем параметры, но в данном случае ничего с ними не делаем
ThreadParams* threadParams = (ThreadParams*)pp->pParams;
// Устанавливаем диапазон изменения индикатора прогресса
pp->pProgress->SetProgressRange(0, 100, 0);
// Выполянем долгий цикл
for (int i = 0; i < 100; ++i)
{
Sleep (100);
pp->pProgress->SetProgress(i + 1);
}
return 0;
}
- И, наконец, запускаем наш поток, и одновременно открывается диалог.
Полностью код с использованием WTL выглядит следующим образом (функция tWinMain была сгенерирована мастером):
#include "resource.h"
#include "ProgressDlg.h"
CAppModule _Module;
struct ThreadParams
{
int foo;
int bar;
};
// Эта функция выполняется в отдельном потоке
DWORD WINAPI ThreadFunc (void* params)
{
// Получаем экземпляр класса ProgressParam<ThreadParams>,
// который хранит указатель на IProgress и на параметры
ProgressParam<ThreadParams> *pp = (ProgressParam<ThreadParams>*)params;
// Получаем параметры, но в данном случае ничего с ними не делаем
ThreadParams* threadParams = (ThreadParams*)pp->pParams;
// Устанавливаем диапазон изменения индикатора прогресса
pp->pProgress->SetProgressRange(0, 100, 0);
// Выполянем долгий цикл
for (int i = 0; i < 100; ++i)
{
Sleep (100);
pp->pProgress->SetProgress(i + 1);
}
return 0;
}
int Run(LPTSTR /*lpstrCmdLine*/ = NULL, int nCmdShow = SW_SHOWDEFAULT)
{
ThreadParams params;
params.foo = 10;
params.bar = 20;
CProgressDlg <ThreadParams, IDD_PROGRESS, IDC_TIME > dlg (ThreadFunc, ¶ms, _T("Пожалуйста, подождите") );
dlg.Start();
return 0;
}
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow)
{
HRESULT hRes = ::CoInitialize(NULL);
// If you are running on NT 4.0 or higher you can use the following call instead to
// make the EXE free threaded. This means that calls come in on a random RPC thread.
// HRESULT hRes = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
ATLASSERT(SUCCEEDED(hRes));
// this resolves ATL window thunking problem when Microsoft Layer for Unicode (MSLU) is used
::DefWindowProc(NULL, 0, 0, 0L);
AtlInitCommonControls(ICC_BAR_CLASSES); // add flags to support other controls
hRes = _Module.Init(NULL, hInstance);
ATLASSERT(SUCCEEDED(hRes));
int nRet = Run(lpstrCmdLine, nCmdShow);
_Module.Term();
::CoUninitialize();
return nRet;
}
Особенности
Расчет общего времени на выполнение всей операции рассчитывается за первый шаг, а потом считается, что все шаги занимают одно и то же время.
Вы можете подписаться на новости сайта через RSS, Группу Вконтакте или Канал в Telegram.