Регистрация | Вход 
Просмотр статьи
ModProgressBar: Пишем свой control

Win32 API: пример создания собственного контрола на C++.

Здравствуйте! Сегодня мы с вами напишем свой класс progress bar’a, который вы потом сможете использовать в своих проектах.

Для начала я вам скажу, что вы научитесь за этот урок:

  • Загружать рисунки ( из ресурсов/файлов )
  • Выводить рисунки
  • Работа с классами
  • Работа с таймерами

Вот и все (. Далее нам нужно сформировать список функций, которые будет использовать наш контролл:

  • Задание размеров
  • Задание положения
  • Задание рисунка-загрузки
  • Перерисовка контролла
  • Увеличение количества процентов
  • Получение поличества процентов

Думаю, все.

Давайте теперь продумаем работу:

Создаем объект прогресс бара. После создания хендла окна вызываем методы, с помощью которых мы настроим наш прогресс бар( размеры, расположение, рисунки ). После этого вызываем метод инициализации, там мы будет грузить рисунки задавать начальное количество процентов и т.д.. Далее дописываем метод перерисовки контролла в сообщение WM_PAINT.

Ну что же, приступим к объявлению класса. Создаем новый файл: CModProgressBar.h.

Вот его код:

// Эту конструкцию мы применяем для исключения повторного подключения этого файла
#ifndef _CMODPROGRESSBAR_H_
#define _CMODPROGRESSBAR_H_

class CModProgressBar {
private:
int barSizeX; // Ширина бара
int barSizeY; // Высота
int barPosX; // Позиция относительно оси X
int barPosY; // Позиция относительно оси Y

int barPercent; // Содержит количество процентов исполненной работы
BITMAP bitmap; // Используем для «вытягивания» информации о bitmap
char *setLoadingPict; // Путь к рисунку загрузки
int drawPixels; // Количество пикселей, которые нужно выводить( высчитывается по процентам )
HBITMAP progressLoading;// Handle рисунка загрузки
public:
CModProgressBar(); // Конструктор
~CModProgressBar(); // Деструктор
int getPercent() {return barPercent;}; // Возвращает количество процентов
bool setBarSize( int x, int y ); // Установка размера бара
bool setBarPos( int x, int y ); // Установка позиции бара
bool setBarPercent( int percent ); // Установка количества процентов
bool setLoadingPicture( char *dest ); // Указание пути к рисунку загрузки
bool renderBar( HWND hWnd, HINSTANCE hInst ); // Рисование бара
bool renderBar( HWND hWnd, HINSTANCE hInst, HDC dc ); // Если вам нужно отрисовать бар не только в сообщении WM_PAINT
};

#endif // _CMODPROGRESSBAR_H_

Все, базовую часть работы сделали. Приступим к основному, реализации функций-членов нашего класса. Для этого создайте новый файл CModProgressBar.cpp, в нем мы и будем реализировать все функции. В самом начале нужно подключить наш заголовочный файл с классом:

#include "stdafx.h"
#include "CModProgressBar.h"

Первое, что нужно сделать, это реализовать конструктор и деструктор. В них мы зададим переменным-членам класса стандартные( начальные ) значения:

 

CModProgressBar::CModProgressBar() {
barSizeX = 100; // Стандартное значение ширины( если не задано )
barSizeY = 20; // Стандартное значение высоты( если не задано )
barPosX = 10; // Стандартное значение позиции относительно оси Х
barPosY = 10; // Стандартное значение позиции относительно оси Y
setLoadingPict = ""; // Стандартное значение пути к рисунку
barPercent = 0; // Начальное количество процентов
};

CModProgressBar::~CModProgressBar() {
// Пусто …
};

Далее начнем с размера прогресс бара. Здесь все просто:

bool CModProgressBar::setBarSize( int x, int y ) {
barSizeX = x; // Просто назначаем закрытым переменным значения, передаваемые в аргументах нашей функции.
barSizeY = y;
return true;
};

Тепер задаем положения относительно нашего окна:

bool CModProgressBar::setBarPos( int x, int y ) {
barPosX = x;
barPosY = y;
return true;
};

Ну а далее все похоже( кроме основной функции – рендера бара ):

bool CModProgressBar::setBarPercent( int percent ) {
barPercent = percent;
return true;
};

Рисунок загрузки:

bool CModProgressBar::setLoadingPicture( char *dest ) {
setLoadingPict = dest;
return true;
};

Теперь напишем основную функцию, она будет перепросчитывать заданные ей проценты под длину прогресс бара и отрисовывать картинку:

bool CModProgressBar::renderBar(HWND hWnd, HINSTANCE hInst) {

// Загрузка рисунка
progressLoading = (HBITMAP)LoadImage( hInst, setLoadingPict, IMAGE_BITMAP, 0,0, LR_LOADFROMFILE );

// Получаем DeviceContext
HDC appDC = GetDC( hWnd );
// Создает память для нашего DC
HDC progressLoadingDC = CreateCompatibleDC( appDC );

// Вставляет объект в специальное DC
SelectObject( progressLoadingDC, progressLoading );
// Получаем информацию о bitmap
GetObject( progressLoading , sizeof( BITMAP ), &bitmap );

// Узнаем, сколько пикселей загрузки рисовать относительно всей длины прогресс бара
int drawPixels = ( barPercent * bitmap.bmWidth ) / 100;
// Выводим рисунок загрузки, учитывая с количеством пикселей
BitBlt( appDC, barPosX, barPosY, drawPixels, barSizeY, progressLoadingDC, 0,0, SRCCOPY );
// Перерисовывает регион на каком-то окне.( NULL – полностью все окно )
ValidateRect( hWnd, NULL );

// Освобождаем контекстное устройство( если этого не сделать, после нескольких перерисовок память переполнится )
DeleteDC( progressLoadingDC );
DeleteDC( appDC );

return true;
};
СОВЕТ

Внимание! Не забывайте смотреть в MSDN, там можно найти очень много полезной информации.

Теперь переписываем последнюю функцию, только с учетом того, что будем рисовать на заданном DC.( Используется, при получении сообщения WM_PAINT ).

bool CModProgressBar::renderBar( HWND hWnd, HINSTANCE hInst, HDC dc ) {
HBITMAP progressLoading = (HBITMAP)LoadImage( hInst, setLoadingPict, IMAGE_BITMAP, 0,0, LR_LOADFROMFILE );
HDC progressLoadingDC = CreateCompatibleDC( dc );
SelectObject( progressLoadingDC, progressLoading );
GetObject( progressLoading , sizeof( BITMAP ), &bitmap );
drawPixels = ( barPercent * bitmap.bmWidth ) / 100;
BitBlt( dc, barPosX, barPosY, drawPixels, barSizeY, progressLoadingDC, 0,0, SRCCOPY );
ValidateRect( hWnd, NULL );
DeleteDC( progressLoadingDC );

return true;
};

Вот и все! Мы реализовали все нужные функции нашего контролла… Хотя назвать наш прогресс бар контроллом тяжело, он не отсылает/принимает никаких сообщений( разве, только, перерисовку ). Теперь попытаемся использовать его на практике. Я использовал этот прогресс бар для вывода количества процентов набранной строки. Но это уже выходит за рамки проекта, и вы увидите эту реализацию на следующем проекте( по которому будет статья ).

А сейчас мы просто будем увеличивать проценты по таймеру. Создайте новый проект, если хотите. Подключите к нему .h && .cpp файлы.

Теперь создаем в главном .cpp файле объект класса нашего прогресс бара. Создавать нужно глобально( в самом начале, чтобы было доступно всем функциям );

CModProgressBar *bar;

Теперь, после создания нашего главного окна:

hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

Проинициализируем наш прогресс бар:

// Устанавливаем позицию прогресс бара
bar->setBarPos( 200, 150 );
// Размеры
bar->setBarSize( 100, 15 );
// Путь к картинке загрузки
bar->setLoadingPicture( "loading.bmp" );
// Прорисовываем бар
bar->renderBar( hWnd, hInst );

Теперь установим таймер( идентификатор его «1», но посколько будем использовать только один таймер в приложении – мы не будем проверять от какого пришло сообщение), который каждые пол секунды будет посылать сообщение WM_TIMER и там мы уже будем отрисовывать.

SetTimer( hWnd, 1, 500, NULL );

Теперь идем к функции WndProc. Создайте в самом начале переменную:

int temp1;

Будем использовать ее, при увеличении процентов.

Далее, в конструкции «разбора» сообщений находим прием сообщения WM_PAINT и дописываем прорисовку:

case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// Прорисовка. В качестве 3 параметра передаем dc приложения, которое используется в функции BeginPaint
bar.renderBar( hWnd, hInst, hdc );
EndPaint(hWnd, &ps);
break;

Ну и последнее! Допишите обработку сообщения WM_TIMER:

case WM_TIMER:
// Получаем текущее количество процентов
temp1 = bar.getPercent();
// Добавляем к процентам еще 5
bar.setBarPercent( temp1+5 );
// Перерисовка бара
bar.renderBar( hWnd, hInst );
break;

И долгожданный конец! Начинаем билд и запускаем программу. (

Вот вам пару скринов:

Конечно, в этом контроле много недостатков. Например, нету проверки на превишение границы процентов( чтобы не более 100% было ), но это уже работа

для вас! Желаю вам удачи во всем!

Тысленко Максим (Ockonal)
29.06.2008


Автор: Ockonal
Дата публикации: 01.07.2008
Число просмотров: 2102

Возврат


Copyright 2007-2009 by Alexander Ignatyev