1. #1

    Talking Cómo hacer una aplicación Win32 con Visual Studio 6 y Visual C++

    Seguro que estáis cansados del típico ejemplo del “Hola Mundo” cada vez que empezáis a usar un lenguaje de programación, pero eso sí, siempre con la típica y sosa ventana de comandos…

    :namespace prefix = o />

    Pues bien, eso es lo que vamos a hacer aquí, pero de forma un poco más interesante: vamos a hacer una aplicación Win32 con ventanas paso a paso.

    Requisitos: poca cosa, tener un mínimo conocimiento de C++ y el Visual Studio :namespace prefix = st1 />6 a mano…

    Pasos: esto es un poco más largo que el apartado de requisitos, así que vallamos por partes…

    1-. Creación del proyecto

    Lo primero es crear el proyecto, si queréis crear un workspace o no me trae sin cuidado, no tiene importancia…

    Pues eso: archivo -> nuevo -> proyecto; elegimos aplicación Win32, ponemos el nombre “Aplicacion Win32” y OK. Después seleccionamos la aplicación hola mundo y finalizamos.

    2-. Revisando los recursos

    Ya tenemos el proyecto creado, si damos a ejecutar vemos la ventanita con la aplicación inicial:

    :namespace prefix = v />

    Que queda bastante curiosa, salvo por el hecho de que tenemos un menú en inglés (porque mi visual esta en inglés, sino no), así que vamos a ver cómo lo ponemos en español, y ya de camino le damos un vistazo a la los recursos:



    Bueno, no os asustéis que en realidad es poca cosa. Tenemos los siguientes apartados:

    - Acelerator: aceleradores de teclado



    Donde tenemos el id del elemento que se “acelera” (por ejemplo una opción del menú) y la combinación de teclas a usar.

    - Dialog: cuadros de diálogo que tenemos en el proyecto



    Son los cuadros de diálogo que tenemos en la aplicación. Inicialmente tenemos el cuadro de acerca de… que viene por defecto, aunque es bastante soso

    -Icon: iconos de la aplicación



    Iconos de la aplicación, inicialmente vienen los que tendrá el ejecutable.

    -Menu: los menús de la aplicación



    Tenemos el menú actual, en inglés, pero si vemos las propiedades (segundo botón sobre el elemento o doble clic) de cada elemento podemos cambiar el texto que aparece en el campo caption (el & indica la letra que sale subrayada).

    Cambiamos los textos y tenemos nuestro menú:



    -String Table: tabla de cadenas



    Tenemos las cadenas que se usan por ejemplo como nombre externo de la aplicación, tipo de aplicación o cadenas simplemente para mensajes de error, mostrarlas en pantalla… lo que se os ocurra

    3-. Personalizando Acerca de…

    Ya hemos visto que el cuadro de Acerca de… queda bastante soso así como está, ¿por qué no le damos un toque personal? Además, ya de camino podemos ver cómo crear otros cuadros de diálogo y cómo capturar los eventos.

    Para hacer esto tenemos que saber que un cuadro de diálogo se compone de una serie de elementos de distintos tipos, como pueden ser etiquetas, imágenes, botones, barras de desplazamiento, etc… que podemos insertar haciendo uso de la barra de herramientas que sale al abrir el cuadro de diálogo:



    Cada uno de los elementos puede tener o no utilidad para nosotros y cada uno de los elementos tiene unas propiedades diferentes, aunque realmente todos o casi todos son los típicos elementos que tenemos en cualquier cuadro de diálogo de cualquier aplicación.

    El sistema consiste en insertar un elemento y mediante las propiedades modificar la forma y estilo que tiene, la cuestión es ir probando hasta que quede a nuestro gusto, el código que pueda necesitar (por ejemplo al pulsar un botón) vendrá después.

    Bien, comencemos:

    - Primer paso:

    Lo primero que vamos a hacer es borrar todos los controles y cambiar el estilo de visualización para que no tengamos barra de control (en la pestaña estilo de las propiedades ponemos estilo a popup borde a ninguno). Queda así:



    - Segundo paso:

    Si os habéis fijado, hay dos reglas en la parte superior y en la parte izquierda, valen para delimitar el espacio dentro del cuadro de diálogo en el que vamos a poder incluir controles. Vamos a delimitarlo para que en los bordes no quede nada.

    También vamos a incluir un texto estático (tercer icono de la barra de controles), pinchando en el icono y dentro del cuadro de diálogo. Ponemos cualquier texto y personalizamos dentro de propiedades todo lo que nos parezca bien.



    Un detalle a tener en cuenta: ya habréis visto que el control tiene un id con un valor por defecto, en este caso no importa mucho porque normalmente un texto estático no se modifica, pero tened en cuenta a la hora de insertar controles que mediante los id´s posteriormente vais a poder acceder a ellos, así que poned un id adecuado.

    - Tercer paso:

    Ya el cuado está algo más original que el inicial, pero tenemos un problema, ¿cómo salimos? (ya se que está lo típico de alt+f4 o esc, pero no tenemos nada en lo que dar con el ratón). Vamos a insertar un botón (por supuesto personalizado):



    Fijaos en que ya sí hemos puesto un identificador más aclarativo, que nos servirá para hacer que la ventana se cierre.

    Antes de dar funcionalidad al botón veamos algo. En el archivo .cpp tenemos el método

    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

    que es el que se encarga de controlar los eventos de la pantalla principal, es decir, las acciones que se han de realizar, como por ejemplo

    . Controlar los eventos del usuario, con el código que está dentro de

    case WM_COMMAND:

    . Redibujar la pantalla, con el código que está dentro de

    case WM_PAINT:

    . “Destruir” la aplicación, con el código que está dentro de

    case WM_DESTROY:

    Pues bien, si miramos el código que se encarga de controlar los eventos de usuario:

    wmId = LOWORD(wParam);

    wmEvent = HIWORD(wParam);

    // Parse the menu selections:

    switch (wmId)

    {

    case IDM_ABOUT:

    DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);

    break;

    case IDM_EXIT:

    DestroyWindow(hWnd);

    break;

    default:

    return DefWindowProc(hWnd, message, wParam, lParam);

    }

    veremos el identificador IDM_ABOUT y el identificador IDM_EXIT, que son ambos de acciones del menú, es decir, cuando pulsamos una acción del menú es dentro de este switch donde vemos qué acción es la pulsada y decidimos qué hacer:

    . con IDM_EXIT cerramos la aplicación (el método DestroyWindow)

    . con IDM_ABOUT abrimos el cuadro de diálogo acerca de…

    Para abrir el cuadro de diálogo el método usado es

    DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About)

    y lo que nos interesa es:

    . segundo parámetro IDD_ABOUTBOX, que dice cuál es el identificador del cuadro de diálogo que se ha de abrir

    . cuarto parámetro About, que dice cuál es el método que se va a encargar de controlar los eventos del cuadro de diálogo que vamos a abrir (este método está más abajo)

    Visto esto, vamos a pasar a dar funcionalidad al botón.

    Si miramos el código del método About:

    // Mesage handler for about box.

    LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)

    {

    switch (message)

    {

    case WM_INITDIALOG:

    return TRUE;

    case WM_COMMAND:

    if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)

    {

    EndDialog(hDlg, LOWORD(wParam));

    return TRUE;

    }

    break;

    }

    return FALSE;

    }

    vemos que es similar al que acabamos de ver, y que también tiene un fragmento de código dentro de:

    case WM_COMMAND:

    que es el que se encarga de llevar a cabo las acciones para los eventos de IDOK (botón OK que tenía el cuadro de diálogo) y de IDCANCEL (botón Cancel que tenía el cuadro de diálogo). Como los botones los hemos quitado, podemos borrar ese código, y podemos incluir el siguiente para que el cuadro de diálogo se cierre al pulsar nuestro nuevo botón:

    if (LOWORD(wParam) == IDC_SALIR_ACERCA)

    {

    EndDialog(hDlg, LOWORD(wParam));

    return TRUE;

    }

    Probad y veréis como el cuadro se cierra al pulsar el botón.

    - Cuarto paso

    Vamos ahora a “integrar” la ventana de acerca de en la ventana principal, para ello lo que vamos a hacer es poner la ventana transparente y centrarla en pantalla.

    Pues venga, hacedlo; lo único es entrar en las propiedades y seleccionar lo apropiado. Una vez hecho probad la aplicación… a que ya queda más curioso?... el único problema es que cuando desplazamos la ventana principal hacia un lado y volvemos a dar a la ayuda el cuadro sigue estando centrado en pantalla y queda feo, pero ya lo arreglaremos.



    Es el momento de solucionar este problema, y de camino vamos a ver cómo en la creación de un cuadro de diálogo se puede modificar al propio cuadro que lo ha creado, aunque resulte raro…

    La idea es mover y redimensionar la ventana principal de forma que el cuadro de diálogo de acerca de… quede totalmente dentro, pero eso sí, cuando cerremos el cuadro de diálogo la ventana principal tiene que quedar como estaba.

    Como queremos mantener la disposición y el tamaño necesitamos una variable global donde almacenemos temporalmente esos valores, es la siguiente:

    WINDOWPLACEMENT localizacionPrincipal;

    el tipo es una estructura que almacena posición y tamaño (entre otros valores), ya veremos como la usamos, ahora pasemos a redimensionar la ventana principal.

    Para hacer esto nos fijamos en el manejador de eventos para el cuadro de diálogo, el mencionado método About.

    . en case WM_INITDIALOG: podemos meter el código que se ejecuta antes de mostrar el cuadro de diálogo, ponemos lo siguiente:

    GetWindowPlacement(GetParent(hDlg), &localizacionPrincipal);

    /* hDlg es el manejador de nuestro cuadro de diálogo; con GetParent(hDlg) optenemos el manejador de la ventana padre, es decir, la ventana principal.

    GetWindowPlacement(GetParent(hDlg), &localizacionPrincipal); lo que hace es almacenar en localizacionPrincipal la localización y el tamaño de la ventana cuyo manejador le pasamos, en este caso de la ventana principal*/

    WINDOWPLACEMENT localizacion;

    RECT posicion;

    /* en la variable localizacion para almacenar la localización de nuestro cuadro de diálogo acerca de; pero como hemos dicho que realmente esta estructura tiene más parámetros necesitamos otra que sólo tenga los que necesitamos (localización y tamaño), esta es RECT, así que creamos la variable posicion*/

    GetWindowPlacement(hDlg, &localizacion);

    posicion = localizacion.rcNormalPosition;

    /* extraemos la información que queremos de nuestro cuadro de diálogo y colocamos la posición y el tamaño del mismo en la variable posicion*/

    SetWindowPos(

    GetParent(hDlg),

    HWND_TOP,

    posicion.left-50,

    posicion.top-50,

    posicion.right-posicion.left+100,

    posicion.bottom-posicion.top+100,

    SWP_SHOWWINDOW);

    /* SetWindowPos asigna una posición y un tamaño a una ventana; hacemos la llamada con la ventana principal, y las coordenadas necesarias para que su posición sea centrada al cuadro de diálogo pero su tamaño algo mayor, para que este quede contenido dentro. Los otros dos parámetros no tienen importancia, el primero es para que la ventana quede en lo “alto” del resto de ventanas y el segundo para que la muestre*/

    return TRUE;

    .en case WM_COMMAND: es donde cerrramos la ventana tras pulsar nuestro botón, lo modificamos de la siguiente forma:

    if (LOWORD(wParam) == IDC_SALIR_ACERCA)

    {

    SetWindowPlacement(GetParent(hDlg), &localizacionPrincipal);

    /* con esto restablecemos la ventana principal a como estaba inicialmente*/

    EndDialog(hDlg, LOWORD(wParam));

    return TRUE;

    }

    break;

    Ya lo tenemos… Eso sí, supongo que tanta función rara no será de mucho agrado, es normal… Os recomiendo que le deis un vistazo a la ayuda de esas funciones hasta que os quede claro lo que hacen (seleccionando el texto de la función y dando a f1 del tirón tenemos la ayuda de la función).

    Si ejecutáis la aplicación y probáis veréis que la cosa funciona, salvo en un caso: si tenemos la ventana maximizada y abrimos el cuadro, al cerrarla no queda del todo bien L…

    Pero eso tiene fácil solución: quitamos el cuadro de maximizar, que es una solución cutre (a un problema realmente de la implementación interna de las librerías, pero bueno), pero que nos sirve para ver cómo hacerlo.

    Pues venga, en el método InitInstance es donde se crea por primera (y única vez) la ventana principal, y es en la creación de la ventana donde podemos quitar el botón de maximizar. Tenemos la línea siguiente, que es dicha creación:

    hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,

    CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

    si después de la mala impresión que causa tanta cosa rara conseguimos mirar la ayuda de la función, veremos que el parámetro que hemos de cambiar para alcanzar nuestro fin es WS_OVERLAPPEDWINDOW, que literalmente, dice que es como

    WS_OVERLAPPED + WS_CAPTION + WS_SYSMENU + WS_THICKFRAME + WS_MINIMIZEBOX + WS_MAXIMIZEBOX

    siendo cada uno de estos algo más o menos raro, pero se ve claramente que WS_MAXIMIZEBOX es el que indica que la ventana tenga cuadro de maximizar. Pues bueno, lo ponemos todo menos ese, de la siguiente forma:

    hWnd = CreateWindow(szWindowClass, szTitle,

    WS_OVERLAPPED |

    WS_CAPTION |

    WS_SYSMENU |

    WS_THICKFRAME |

    WS_MINIMIZEBOX,

    CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

    Y listo, ahora si que todo funciona a la perfección.



    - Quinto paso

    Por último vamos a insertar una imagen. Vamos a la parte de recursos, damos a nueva imagen y dibujamos cualquier cosa…



    Eso mismo… joer que buen dibujante soy…

    Ahora insertamos una imagen en el cuadro de diálogo y seleccionamos el bitmap que hemos creado:



    Y este es el resultado de lo que hemos creado:



    Que no es una gran maravilla, pero nos ha costado nuestro trabajo.

    FIN???

    Bueno, por ahora aquí queda la cosa, para empezar no está mal si habéis conseguido hacerlo.

    De todas formas esto no tiene porqué acabar aquí… sólo hemos visto cómo empezar a hacer algo en una aplicación win32 y le hemos dado un rápido vistazo a algunos controles.

    Si tenéis interés en ver otros controles o no sabéis cómo hacer alguna cosa me ponéis un comentario aquí abajo o me mandáis algún correito a [email protected] y veremos que se puede hacer.

    Por supuesto si algo no queda claro lo mismo, que ya que hago algo que se entienda…

    Bueno, pues espero que tanta letra os sirva de algo… hasta otra…

  2. #2

    Gracias
    Citar Citar  

  3. #3

    Gracias por el aporte.-
    Citar Citar  

  4. #4

    Gracias
    Citar Citar  

  5. #5

    se agradece !"#
    Citar Citar