Aplicación GUI con API de Windows y clases

#include <Windows.h> #include <string> using namespace std; // Ventana principal #define V_ALTO 160 #define V_ANCHO 245 #define V_TITULO "Primera Victima GUI" #define V_CLASE "PrimeraVictimaGUI" #define V_COLOR static_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)); // Colores del texto #define CL_BLANCO RGB(255, 255, 255) #define CL_NEGRO RGB(0, 0, 0) #define CL_ROJO RGB(255, 0, 0) #define CL_VERDE RGB(0, 255, 0) #define CL_AZUL RGB(0, 0, 255) // Fuentes #define FONT_SIZE 20 #define FONT_NAME "Comic Sans MS" // Controles #define NO_CTRLS 1 #define C_LABEL "STATIC" #define C_BUTTON "BUTTON" #define L1_ALTO 20 #define L1_ANCHO 210 #define L1_X 10 #define L1_Y 50 #define L1_ID 0 #define L1_TEXT "HOLA" #define L1_ESTILO ES_CENTER | WS_CHILD | WS_VISIBLE // Estructura que guarda los datos de // los controles de la ventana typedef struct { LPSTR Tipo; LPSTR Texto; HANDLE CtrlHWND; DWORD ID; INT Alto; INT Ancho; INT PosX; INT PosY; DWORD Estilo; } CONTROL, *PCONTROL; // Clase de la ventana principal class Window { private: HWND hwnd; // handle de ventana HINSTANCE hInstance; // Instancia de la aplicación WNDCLASSEX wincl; // Clase de ventana PCONTROL Control; // Controles de la ventana HFONT hfComicSans; // Fuente de los controles HBRUSH PincelStatic; // Pincel de colores void CentrarVentana(); // Ubicar la ventana en el centro void Inicializar(); // Inicializar todos los datos void CrearControles(); // Crear controles de la ventana // Procedimiento dinámico de ventana LRESULT WndProc(HWND, UINT, WPARAM, LPARAM); /* ----PARTE IMPORTANTE---- LA API DE WINDOWS NECESITA REFERENCIAS ESTÁTICAS EN SUS FUNCIONES ENTONCES, NO PODEMOS USAR UN PROCEDIMIENTO DE HILO, DIÁLOGO O VENTANA EN UNA CLASE PORQUE DEBE SER ESTÁTICO Y POR ENDE, NO SE PUEDEN HACER REFERENCIAS A MIEMBROS DINÁMICOS DESDE UN PRODEDIMIENTO ESTÁTICO, POR EJEMPLO: EL PUNTERO this NO PUEDE SER USADO DESDE UN MIEMBRO ESTÁTICO. PARA SOLUCIONAR ESTE INCONVENIENTE, TENEMOS QUE HACER UNAS CUANTAS COSAS. EN EL CASO DE LOS HILOS, DEBEMOS PASAR EL PUNTERO this COMO PARÁMETRO, ESTO ES PARA PODER DECLARAR UNA CLASE QUE TENGA ESA DIRECCIÓN Y PODER USAR LOS MIEMBROS DINÁMICOS, PERO DE MANERA ESTÁTICA. EN EL CASO DEL PROCEDIMIENTO DE VENTANA, LA COSA SE COMPLICA AUNQUE LA LÓGICA ES LA MISMA, DEBEMOS PASAR EL PUNTERO this COMO ÚLTIMO PARÁMETRO Y USARLO EN EL EVENTO "WM_NCCREATE" Y GUARDARLO EN LA SECCIÓN USERDATA QUE ALMACENA UN DWORD. LUEGO CAMBIAMOS EL PUNTERO AL PROCEDIMIENTO ESTÁTICO A OTRO SIMILAR PERO MÁS LIGERO. ESTE PROCEDIMIENTO LIGERO, LO QUE HACE ES RECUPERAR EL PUNTERO this, LO CONVIERTE EN UNA CLASE Y LLAMA AL PROCEDIMIENTO DINÁMICO. */ // Procedimiento de ventana inicial, para inicializaciones static LRESULT CALLBACK WinProcInicial(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { if (Msg == WM_NCCREATE) { // Lparam contiene una referencia a una estructura de tipo: LPCREATESTRUCT CreateStruct = reinterpret_cast<LPCREATESTRUCT>(lParam); // El puntero this se encuentra en el campo lpCreateParams void * lpCreateParam = CreateStruct->lpCreateParams; // Armamos una referencia a la clase que apunta this Window * EstaVentana = reinterpret_cast<Window*>(lpCreateParam); // Guardamos el puntero this en la sección USERDATA SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(EstaVentana)); // Cambiamos la dirección del procedimiento de ventana SetWindowLongPtr(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(&Window::WinProcRedir)); } // Si no es el evento NCCREATE o si ya terminamos... return DefWindowProc(hWnd, Msg, wParam, lParam); } static LRESULT CALLBACK WinProcRedir(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { // Recuperamos el puntero this LONG_PTR UserData = GetWindowLongPtr(hWnd, GWLP_USERDATA); // Armamos la clase Window * EstaVentana = reinterpret_cast<Window*>(UserData); // Llamamos al procedimiento dinámico return EstaVentana->WndProc(hWnd, Msg, wParam, lParam); } public: Window(HINSTANCE hInst); void Correr(); // Iniciar la aplicación }; // DEFINICION DE LA CLASE............ Window::Window(HINSTANCE hInst) { hInstance = hInst; Inicializar(); } void Window::Inicializar() { // Datos de la ventana wincl.hInstance = hInstance; wincl.lpszClassName = V_CLASE; wincl.hbrBackground = V_COLOR; wincl.lpfnWndProc = &Window::WinProcInicial; wincl.style = CS_DBLCLKS; wincl.cbSize = sizeof(WNDCLASSEX); wincl.hIcon = LoadIcon(NULL, IDI_APPLICATION); wincl.hIconSm = LoadIcon(NULL, IDI_APPLICATION); wincl.hCursor = LoadCursor(NULL, IDC_ARROW); wincl.lpszMenuName = NULL; wincl.cbClsExtra = NULL; wincl.cbWndExtra = NULL; // Registrar la clase RegisterClassEx(&wincl); // Crear la Ventana hwnd = CreateWindowEx(NULL, V_CLASE, V_TITULO, WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU, CW_USEDEFAULT, CW_USEDEFAULT, V_ANCHO, V_ALTO, NULL, (HMENU) NULL, hInstance, (LPVOID)this); // Crear controles de la ventana CrearControles(); } void Window::CentrarVentana() { // Obtener coordenadas horizontales centrales int posX = (GetSystemMetrics(SM_CXSCREEN) / 2) - (V_ANCHO / 2); // Obtener coordenadas verticales centrales int posY = (GetSystemMetrics(SM_CYSCREEN) / 2) - (V_ALTO / 2); // Centrar la ventana en pantalla SetWindowPos(hwnd, NULL, posX, posY, NULL, NULL, SWP_NOSIZE); } void Window::CrearControles() { // Crear tantos controles como indique NO_CTRLS Control = new CONTROL[NO_CTRLS]; // Llenar los datos de los controles.... Control[L1_ID].Alto = L1_ALTO; Control[L1_ID].Ancho = L1_ANCHO; Control[L1_ID].PosX = L1_X; Control[L1_ID].PosY = L1_Y; Control[L1_ID].Tipo = C_LABEL; Control[L1_ID].Estilo = L1_ESTILO; Control[L1_ID].Texto = L1_TEXT; Control[L1_ID].ID = L1_ID; // Crear la fuente que usarán los controles hfComicSans = CreateFont(FONT_SIZE, NULL, NULL, NULL, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, FONT_NAME); // El pincel de fondo de los controles PincelStatic = CreateSolidBrush(CL_NEGRO); // Crear los controles y asignarle el texto a cada uno for (int i = 0; i < NO_CTRLS; i++) { Control[i].CtrlHWND = CreateWindowEx(NULL, Control[i].Tipo, NULL, Control[i].Estilo, Control[i].PosX, Control[i].PosY, Control[i].Ancho, Control[i].Alto, hwnd, (HMENU)Control[i].ID, NULL, NULL); SetDlgItemText(hwnd, Control[i].ID, Control[i].Texto); SendMessage(GetDlgItem(hwnd, i), WM_SETFONT, reinterpret_cast<WPARAM>(hfComicSans), TRUE); } } LRESULT Window::WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { switch (Msg) { case WM_DESTROY: // Si el usuario pulsa la "X", nos vamos PostQuitMessage(0); break; // Asignar los colores a los controles case WM_CTLCOLORSTATIC: SetBkColor((HDC)wParam, CL_NEGRO); if (((HWND)lParam == Control[L1_ID].CtrlHWND)) { SetTextColor((HDC)wParam, CL_ROJO); } else { SetTextColor((HDC)wParam, CL_VERDE); } return (LRESULT)PincelStatic; default: return DefWindowProc(hWnd, Msg, wParam, lParam); } return 0; } // Ciclo principal del programa. void Window::Correr() { MSG mensaje; CentrarVentana(); ShowWindow(hwnd, SW_SHOWDEFAULT); UpdateWindow(hwnd); while (GetMessage(&mensaje, hwnd, NULL, NULL) == TRUE) { TranslateMessage(&mensaje); DispatchMessage(&mensaje); } } // El main de nuestro programa int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { // Creamos la ventana. Window *Ventana = new Window(hInstance); // Abrimos la ventana Ventana->Correr(); delete Ventana; return EXIT_SUCCESS; }
Programa que crea una interfaz GUI con la API de Windows e introduce los procedimientos de ventana dentro de una clase...

Be the first to comment

You can use [html][/html], [css][/css], [php][/php] and more to embed the code. Urls are automatically hyperlinked. Line breaks and paragraphs are automatically generated.