|
ФайлыПример использования и сам класс в файле ProgressDlg.h лежит здесь Используемые библиотекиСкриншоты![]() ОписаниеК сожалению, современные компьютеры еще не настолько быстрые, чтобы выполнять все, что надо от них пользователю, мгновенно. Естественно, что эти операции делают в отдельном потоке, чтобы те, кто сидит за компьютером, не думали, что программа повисла. При этом хорошо бы было еще показывать процент выполнения и оставшееся время до конца операции. Вот для облегчения этого случая я и написал этот класс. Только здесь надо сказать об одном предположении. Считается, что во время выполнения операции пользователь больше ничего не может делать паралелльно, т.е. процесс выполнения показывается в модальном диалоге. Вообще то CProgressDlg я делал ужасно давно, уже даже не помню под какую версию Visual C++. А тут недавно мне напомнили про этот класс, я попробовал его скомпилить в Visual C++ 2005, получил ошибки и, мягко выражаясь, удивился насколько плохо был написал этот класс. Поэтому сейчас я его значительно исправил, да и описание дополнил. Использование
struct ThreadParams { int foo; int bar }; В будущем этот тип будет передаваться в качестве параметра шаблона.
DWORD WINAPI ThreadFunc(void *params); Только здесь есть одна особенность. В эту функцию передается не та структура, которую мы создали ранее на первом шаге (ThreadParams), а другая, описанная ниже template<class T> struct ProgressParam { T* pParams; IProgress* pProgress; }; Здесь тип T как раз и должен быть типом для параметра, который мы определили выше (в данном случае ThreadParams), первое поле pParams - это и есть этот самый параметр, а второй - указатель на интерфейс работы с диалогом. Он объявлен вот так: class IProgress { public: virtual void SetProgressRange (int minval, int maxval, int currval) = 0; virtual void SetProgress(int val) = 0; }; Функция SetProgressRange() задает интервал некоторой измеряемой величины, которая символизирует процент выполнения, а SetProgress() устанавливает новый процент. Слово "процент" здесь используется как аналогия, т.е. величина может меняться в любых пределах.
CProgressDlg <ThreadParams, IDD_PROGRESS, IDC_TIME > dlg (ThreadFunc, ¶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; }
dlg.Start(); Полностью код с использованием WTL выглядит следующим образом (функция tWinMain была сгенерирована мастером): #include "stdafx.h" #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; } ОсобенностиРасчет общего времени на выполнение всей операции рассчитывается за первый шаг, а потом считается, что все шаги занимают одно и то же время.
Пожалуйста, оцените материал
|