NovaMonoFix
Errores PHP
X
Usuario
Password
0 FPS

Tutorial WinAPI C++ 3.1 Creación del ObjetoBarraProgreso

06 de Noviembre del 2010 por Josep Antoni Bover, 0 visitas, 0 comentarios, 0 votos
Categorías : Windows, Programación, C y C++.
La web está en segundo plano, animación en pausa.
Cargando animación...
Tutorial WinAPI C++ 3.1 Creación del ObjetoBarraProgreso

En este tutorial nos vamos a hacer nuestra barra de progreso desde cero, que se usara en el instalador final para mostrar el progreso de instalación.

Al ser un control 'visual' que no requiere interaccion por parte del usuario, sera bastante facil de programar. Lo unico que tenemos que tener claro es que la barra puede ser vertical o horizontal, y esto se decidira por su forma inicial al crearla. Por ejemplo si creamos una barra de 200 pixeles de ancho por 10 de alto, esta barra sera horizontal.

En primer lugar creamos la clase ObjetoBarraProgreso que heredara de ObjetoControl, y definimos sus miembros. Vamos a necesitar varios miembros para asignar/obtener el mínimo, el valor y el máximo de la barra, además de los colores para el control :

Archivo : ObjetoBarraProgreso.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// Clase que hereda ObjetoControl y se centra en las funciones
// de la clase ObjetoBarraProgreso
class ObjetoBarraProgreso : public ObjetoControl {
public : //////// Miembros publicos
// -Constructor
ObjetoBarraProgreso(void);
// -Destructor
~ObjetoBarraProgreso(void);
// -Función para crear la progressbar
HWND CrearBarraProgreso( HWND hWndParent, const UINT nID,
// Posición y tamaño
const int cX, const int cY,
const int cAncho, const int cAlto,
// Valores y colores por defecto
const float nMin = 0.0f, const float nMax = 100.0f,
const float nValor = 0.0f,
COLORREF ColorDegradadoSuperior= RGB(200, 200, 200),
COLORREF ColorDegradadoInferior= RGB(100, 100, 100),
COLORREF ColorBordeExterno = RGB(128, 128, 128),
COLORREF ColorBordeInterno = RGB(192, 192, 192),
COLORREF ColorFondo = RGB(220, 220, 220)
/* FIN declaración CrearBarraProgreso */ );
// -Función para asignar el minimo de la progressbar
void Minimo(const float nMinimo, const bool nRepintar = false);
// -Función para obtener el minimo de la progressbar
inline float Minimo(void) const { return _Minimo; };
// -Función para asignar el maximo de la progressbar
void Maximo(const float nMaximo, const bool nRepintar = false);
// -Función para obtener el maximo de la progressbar
inline float Maximo(void) const { return _Maximo; };
// -Función para asignar el valor de la progressbar
void Valor(const float nValor, const bool nRepintar = true);
// -Función para obtener el valor de la progressbar
// (ojo que devuelve UINT)
inline float Valor(void) const { return _Valor; };
// -Función que repinta el control
void Repintar(void);
// -Función que pinta el control
LRESULT Evento_Pintar(HDC hDC, PAINTSTRUCT &PS);
//////////////// Colores
// -Macro que crea funciones para asignar y obtener
// el COLORREF _Color_DegradadoSuperior
AGREGAR_COLOR(Color_DegradadoSuperior);
// -Macro que crea funciones para asignar y obtener
// el COLORREF _Color_DegradadoInferior
AGREGAR_COLOR(Color_DegradadoInferior);
// -Macro que crea funciones para asignar y obtener
// el COLORREF _Color_BordeExterno
AGREGAR_COLOR(Color_BordeExterno);
// -Macro que crea funciones para asignar y obtener
// el COLORREF _Color_BordeInterno
AGREGAR_COLOR(Color_BordeInterno);
// -Macro que crea funciones para asignar y obtener
// el COLORREF _Color_Fondo
AGREGAR_COLOR(Color_Fondo);
protected : ///// Miembros protegidos
float _Minimo;
float _Maximo;
float _Valor;
};

Podríamos haber hecho que mínimo siempre fuera 0 y máximo siempre fuera 100, pero me parece interesante poder asignar esos valores y que la barra calcule el porcentaje, ya que nos ahorrara código para calcular el porcentaje en la aplicación final. Pensad por ejemplo que tenemos 433 archivos y queremos mostrar el porcentaje completado, si la barra tuviera mínimo 0 y máximo 100, la aplicación sería la encargada de calcular el porcentaje, en cambio al hacer que el mínimo y el máximo sean variables de forma que el ObjetoBarraProgreso tenga que calcularlos internamente, nos ahorramos tener que escribir un código para calcular el porcentaje en la aplicación.

El ObjetoBarraProgreso es un control que no requiere acciones del usuario por lo que será bastante fácil de programar, ya que no necesitamos responder a la mayoría de eventos. El único evento que necesitaremos re-escribir es el Evento_Pintar :

Archivo : ObjetoBarraProgreso.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
LRESULT ObjetoBarraProgreso::Evento_Pintar(HDC hDC, PAINTSTRUCT &PS) {
RECT RC;
GetClientRect(_hWnd, &RC);
// 1 - Creación de un buffer para el pintado
HDC Buffer = CreateCompatibleDC(hDC);
HBITMAP Bmp = CreateCompatibleBitmap(hDC, RC.right, RC.bottom);
HBITMAP Viejo = static_cast<HBITMAP>(SelectObject(Buffer, Bmp));
HRGN Region = CreateRoundRectRgn(0, 0, RC.right, RC.bottom, REDONDEAMIENTO, REDONDEAMIENTO);
HFONT VFuente = NULL;
RECT Degradado = { RC.left + 2, RC.top +2, RC.right -4, RC.bottom -4 };
float Parte = 0.0f;
bool EsVertical = (RC.right < RC.bottom);
// 2 -Calculamos los pixeles necesarios por cada parte
float TotalValores = 0.0f;
if (EsVertical == true) {
// (RC.bottom - 4) = Alto utilizable en pixeles del control
// (_Maximo - _Minimo) = Total de valores a recorrer
// (Alto / Total varlores) = Parte por valor
float AltoU = static_cast<float>(RC.bottom - 4);
TotalValores = (_Maximo - _Minimo);
if (TotalValores > AltoU) Parte = TotalValores / AltoU;
else Parte = AltoU / TotalValores;
Degradado.top = Degradado.bottom - static_cast<int>(Parte * (_Valor - _Minimo));
}
else {
// (RC.right - 4) = Ancho utilizable en pixeles del control
// (_Maximo - _Minimo) = Total de valores a recorrer
// (Ancho / Total varlores) = Parte por valor
float AnchoU = static_cast<float>(RC.right - 4);
TotalValores = (_Maximo - _Minimo);
if (TotalValores > AnchoU) Parte = TotalValores / AnchoU;
else Parte = AnchoU / TotalValores;
Degradado.right = static_cast<int>(Parte * (_Valor - _Minimo));
}
// 3 - Pintamos el fondo
HBRUSH Brocha = CreateSolidBrush(_Color_Fondo);
FillRect(Buffer, &RC, Brocha);
DeleteObject(Brocha);
// 4 - Pintamos la barra de progreso con un degradado
TRIVERTEX GCVertex[2];
GRADIENT_RECT tGRect;
GCVertex[0].Red = RGB_OBTENER_R(_Color_DegradadoSuperior);
GCVertex[0].Green = RGB_OBTENER_G(_Color_DegradadoSuperior);
GCVertex[0].Blue = RGB_OBTENER_B(_Color_DegradadoSuperior);
GCVertex[0].x = Degradado.left;
GCVertex[0].y = Degradado.top;
GCVertex[1].Red = RGB_OBTENER_R(_Color_DegradadoInferior);
GCVertex[1].Green = RGB_OBTENER_G(_Color_DegradadoInferior);
GCVertex[1].Blue = RGB_OBTENER_B(_Color_DegradadoInferior);
GCVertex[1].x = Degradado.right + 2;
GCVertex[1].y = Degradado.bottom + 2;
tGRect.UpperLeft = 0;
tGRect.LowerRight = 1;
GradientFill(Buffer, GCVertex, 2, &tGRect, 1, (EsVertical) ? GRADIENT_FILL_RECT_H : GRADIENT_FILL_RECT_V);
// 5 - Pintamos el borde
Brocha = CreateSolidBrush(_Color_BordeInterno);
FrameRgn(Buffer, Region, Brocha, 2, 2);
DeleteObject(Brocha);
Brocha = CreateSolidBrush(_Color_BordeExterno);
FrameRgn(Buffer, Region, Brocha, 1, 1);
DeleteObject(Brocha);
// 6 - Pintamos el Buffer en el DC de la barra de progreso
BitBlt(hDC, 0, 0, RC.right, RC.bottom, Buffer, 0, 0, SRCCOPY);
// 7 - Selecciono los objetos originales del Buffer y elimino objetos gdi de la memoria
SelectObject(Buffer, VFuente);
SelectObject(Buffer, Viejo);
DeleteObject(Region);
DeleteObject(Bmp);
DeleteDC(Buffer);
return 0;
}

Veamos la función en 7 pasos :

Con esto ya tenemos un control al que le podemos especificar mínimo, máximo y valor para que nos pinte una barra.

Aunque no viene a cuento para el instalador, pensad que podríamos crear un ObjetoBarraDesplazamiento que herede de este control, y incluya eventos del mouse para que el usuario pudiera posicionar la barra manualmente.

Llegados a este punto ya podemos pasar al siguiente tutorial 3.2 Common Dialogs.