[WTL] CProgressDlg

Немного рекламы

Файлы

Пример использования и сам класс в файле ProgressDlg.h лежит здесь

Используемые библиотеки

WTL

Скриншоты

Описание

К сожалению, современные компьютеры еще не настолько быстрые, чтобы выполнять все, что надо от них пользователю, мгновенно. Естественно, что эти операции делают в отдельном потоке, чтобы те, кто сидит за компьютером, не думали, что программа повисла. При этом хорошо бы было еще показывать процент выполнения и оставшееся время до конца операции. Вот для облегчения этого случая я и написал этот класс. Только здесь надо сказать об одном предположении. Считается, что во время выполнения операции пользователь больше ничего не может делать паралелльно, т.е. процесс выполнения показывается в модальном диалоге.

Вообще то CProgressDlg я делал ужасно давно, уже даже не помню под какую версию Visual C++. А тут недавно мне напомнили про этот класс, я попробовал его скомпилить в Visual C++ 2005, получил ошибки и, мягко выражаясь, удивился насколько плохо был написал этот класс. Поэтому сейчас я его значительно исправил, да и описание дополнил.

Использование

  • Создать структуру параметров для потока, например
struct ThreadParams
{
  int foo;
  int bar
};

В будущем этот тип будет передаваться в качестве параметра шаблона.

  • Создать в ресурсах диалог, например, пусть у него идентификатор будет IDD_PROGRESS. У этого диалога должно быть текстровое поле, в которое будет писаться оставшееся время, например с идентификатором IDC_TIME.
  • Создать потоковую функцию такую, как описано в MSDN. Т.е. она должна иметь вид
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.
CProgressDlg <ThreadParams, IDD_PROGRESS, IDC_TIME > dlg (ThreadFunc,
        &params,
        _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, &params, _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.
5 stars

Рейтинг 4.6/5. Всего 9 голос(а, ов)



[DIWMS] 01.03.2011 - 19:32

Cool!

То что искал =) grinning smiley
Спасибо огромное!!!!!!!!)))


Подписаться на комментарии
Автор:
Тема:
 Ваш комментарий
 
 
Введите код 789