Esqueleto aplicación.
Segundo tutorial en el que crearemos la estructura básica de nuestra aplicación que nos servirá para los siguientes tutoriales.
Como podemos ver en la imagen superior, hemos organizado los directorios separando el código fuente (src) de los proyectos en los diferentes entornos (prj). Aunque en este tutorial, todavía no hemos llegado a desarrollar para Linux, os muestro la jerarquía completa de cómo serán el resto de tutoriales.
- graphicapplication.h: Nuestra aplicación.
- graphicapplication.cpp: Implementación de la aplicación.
- common.h: Definiciones de uso común.
- system.h: Funciones específicas del sistema.
- winsystem.cpp: Implementación de las funciones específicas del sistema.
- win-main.cpp: Programa principal.
- rc/appicon.ico: Icono de la aplicación.
- rc/resource.h: Definiciones de recursos.
- rc/resources.rc: Fichero con los recursos gráficos.
El cuerpo principal del programa cambia un poco, simplemente, la función gestora de mensajes invoca a los métodos de nuestra aplicación cada vez que se produce un evento.
Y en el caso de que no se produzca un evento, se ejecuta la función principal de nuestra aplicación: g_OpenGLApplication.OnIdle();
Y en el caso de que no se produzca un evento, se ejecuta la función principal de nuestra aplicación: g_OpenGLApplication.OnIdle();
#include
#include
#include "common.h"
#include "system.h"
#include "resource.h"
#include "graphicapplication.h"
#define WINDOW_WIDTH 640
#define WINDOW_HEIGHT 480
#define BPP 32 // Bits por pixel.
#define WINDOW_CLASS_NAME "MY_WINDOWS_CLASS"
#ifdef _DEBUG
#define __CONSOLE__ // En depuración aparece la consola.
#endif
// -----------------------------------------------------------------------------
// Creamos nuestro objeto aplicación de ámbito global para que sea accesible
// por la función gestora de mensajes de la ventana.
PROGRAMACION_GRAFICA::GraphicApplication g_GraphicApplication;
// -----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
/// WindowProc: Procedimiento gestor de mensajes de la ventana.
///
/// @param HWND hWnd: Handle de la ventana.
/// @param UINT msg: Mensaje recibido por la ventana.
/// @param WPARAM wParam: Parte alta del parámtro recibido.
/// @param LPARAM lParam: Parte baja del parámtro recibido.
///
/// @return LRESULT CALLBACK: Valor retornado en función del mensaje procesado.
///////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK WindowProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_KEYDOWN:
g_GraphicApplication.OnKeyDown( wParam );
return 0;
case WM_KEYUP:
g_GraphicApplication.OnKeyUp ( wParam );
return 0;
case WM_MOVE:
g_GraphicApplication.SetScreenPosition( LOWORD(lParam), HIWORD(lParam) );
return 0;
case WM_SIZE:
g_GraphicApplication.OnResize ( LOWORD(lParam), HIWORD(lParam) );
return 0;
case WM_MOUSEMOVE:
g_GraphicApplication.OnMouseMove( LOWORD(lParam), HIWORD(lParam) );
return 0;
case WM_LBUTTONDOWN:
g_GraphicApplication.OnLButtonDown( LOWORD(lParam), HIWORD(lParam) );
return 0;
case WM_LBUTTONUP:
g_GraphicApplication.OnLButtonUp( LOWORD(lParam), HIWORD(lParam) );
return 0;
case WM_RBUTTONDOWN:
g_GraphicApplication.OnRButtonDown( LOWORD(lParam), HIWORD(lParam) );
return 0;
case WM_RBUTTONUP:
g_GraphicApplication.OnRButtonUp( LOWORD(lParam), HIWORD(lParam) );
return 0;
case WM_SYSCOMMAND:
switch (wParam)
{
case SC_SCREENSAVE:
case SC_MONITORPOWER:
if ( g_GraphicApplication.IsFullScreen() )
return 0; // No permitimos que salte el salvapantallas, ni el ahorro de energía.
default:
return DefWindowProc (hWnd, msg, wParam, lParam);
}
break;
case WM_CLOSE:
DestroyWindow( hWnd ); // Enviamos un mensaje WM_DESTROY
return 0;
case WM_DESTROY:
// Si estaba a pantalla completa, hay restaurar la resolución del escritorio.
if ( g_GraphicApplication.IsFullScreen() )
ChangeDisplaySettings(NULL,0);
PostQuitMessage(0); // Enviamos un mensaje WM_QUIT
return 0;
default:
return DefWindowProc( hWnd, msg, wParam, lParam );
}
return 0;
}
#ifdef __CONSOLE__
#pragma comment ( linker, "/subsystem:console" )
///////////////////////////////////////////////////////////////////////////////
/// main: Punto de entrada de la aplicación.
///
/// @param int argc: Número de argumentos.
/// @param char * argv[]: Parámetros de la línea de comando.
///
/// @return int: código devuelto por msg.wParam.
///////////////////////////////////////////////////////////////////////////////
int main(int argc, char * argv[])
{
int nCmdShow = SW_SHOWNORMAL;
HINSTANCE hInstance= GetModuleHandle( argv[0] );
#else
#pragma comment ( linker, "/subsystem:windows" )
///////////////////////////////////////////////////////////////////////////////
/// WinMain: Punto de entrada de la aplicación.
///
/// @param HINSTANCE hInstance: Instancia.
/// @param HINSTANCE hPrevInstance: Instancia anterior.
/// @param LPSTR lpCmdLine: Línea de comandos.
/// @param int nCmdShow: Cómo se mostrar la ventana (minimizada, maximizada...)
///
/// @return int WINAPI: código devuelto por msg.wParam.
///////////////////////////////////////////////////////////////////////////////
int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
#endif
WNDCLASSEX winClass;
MSG msg = {0};
int codError = 0;
DWORD dwExStyle, dwStyle;
PROGRAMACION_GRAFICA::WindowProps windowProps;
try
{
// ¿FullScreen?
if ( MessageBox( NULL, "¿Deseas ejecutar a pantalla completa?",
"PREGUNTA:", MB_ICONQUESTION | MB_YESNO) == IDYES)
windowProps.bFullScreen= true;
else
windowProps.bFullScreen= false;
windowProps.position.x = 0;
windowProps.position.y = 0;
windowProps.width = WINDOW_WIDTH;
windowProps.height = WINDOW_HEIGHT;
windowProps.bpp = BPP;
// Inicialización de nuestra aplicación.
g_GraphicApplication.OnInit( windowProps );
// Registramos la clase de ventana
winClass.lpszClassName = WINDOW_CLASS_NAME;
winClass.cbSize = sizeof(WNDCLASSEX);
winClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
winClass.lpfnWndProc = WindowProc;
winClass.hInstance = hInstance;
winClass.hIcon = LoadIcon ( hInstance, MAKEINTRESOURCE(IDI_APP_ICON) );
winClass.hIconSm = LoadIcon ( hInstance, MAKEINTRESOURCE(IDI_APP_ICON) );
winClass.hCursor = LoadCursor( NULL, IDC_ARROW );
winClass.hbrBackground = (HBRUSH)GetStockObject( WHITE_BRUSH );
winClass.lpszMenuName = NULL;
winClass.cbClsExtra = 0;
winClass.cbWndExtra = 0;
if( !RegisterClassEx(&winClass) )
throw PROGRAMACION_GRAFICA::System::GetSystemError();
RECT desktopRect;
GetWindowRect( GetDesktopWindow(), &desktopRect );
if ( windowProps.bFullScreen )
{
dwExStyle= WS_EX_TOPMOST;
dwStyle = WS_POPUP | WS_VISIBLE;
g_GraphicApplication.SetScreenPosition(0,0);
}
else
{
dwExStyle= WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dwStyle = WS_OVERLAPPEDWINDOW;
g_GraphicApplication.SetScreenPosition( (desktopRect.right - windowProps.width )/2 ,
(desktopRect.bottom - windowProps.height)/2 );
}
// Creamos la ventana
windowProps.hWnd = CreateWindowEx( dwExStyle, WINDOW_CLASS_NAME, WINDOW_TITLE,
dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
(int)g_GraphicApplication.GetScreenPosition().x,
(int)g_GraphicApplication.GetScreenPosition().y,
windowProps.width, windowProps.height,
NULL, NULL, hInstance, NULL );
if( windowProps.hWnd == NULL )
throw PROGRAMACION_GRAFICA::System::GetSystemError();
// Mostramos la ventana.
ShowWindow( windowProps.hWnd, nCmdShow );
// Forzamos el repintado.
UpdateWindow( windowProps.hWnd );
// si es a pantalla completa, hay que cambiar la resolución del escritorio
if ( windowProps.bFullScreen )
{
DEVMODE dmScreenSettings;
memset(&dmScreenSettings,0,sizeof(dmScreenSettings));
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = windowProps.width;
dmScreenSettings.dmPelsHeight = windowProps.height;
dmScreenSettings.dmBitsPerPel = windowProps.bpp;
dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
if ( ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL )
throw PROGRAMACION_GRAFICA::System::GetSystemError();
SetForegroundWindow(windowProps.hWnd); // Situamos la ventana en primer plano
}
SetFocus(windowProps.hWnd); // Obtenemos el foco
g_GraphicApplication.OnCreateWindow( windowProps );
g_GraphicApplication.OnResize( windowProps.width, windowProps.height );
// Bucle principal
while( msg.message != WM_QUIT && !g_GraphicApplication.IsEnded() )
{
if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage ( &msg );
}
else
{
g_GraphicApplication.OnIdle(); // Proceso principal de la aplicación.
SetWindowText(windowProps.hWnd, g_GraphicApplication.GetMsgTitle() );
}
}
codError= msg.wParam;
}
catch (int errorCode)
{
PROGRAMACION_GRAFICA::System::ShowError( errorCode );
codError= errorCode;
}
// Finalizamos la aplicación
g_GraphicApplication.OnEnd();
// Desregistramos la clase de ventana.
UnregisterClass( WINDOW_CLASS_NAME, winClass.hInstance );
return codError;
}
Comentarios