Versión 3.0
800x600 mínimo
En esta lección:

El contexto de dispositivo
-----
La función TextOut( )
-----
Barras de desplazamiento
-----
Descargas
-----


Otras secciones:

Conceptos básicos
-----
Programando en C
-----
Programando en C++
-----
Programando Windows 9x.
-----
Teoría electrónica
-----
Circuitos electrónicos
-----
Actividades adicionales
-----
Hipervínculos
-----


Contácteme:

Dudas y comentarios
-----


Hola mundo

La interfaz para dispositivos gráficos.

     En la lección anterior analizamos un programa muy sencillo que demostraba la manera de generar una ventana para el entorno Windows 9x. Aunque éste programa no hace otra cosa que desplegar un simple mensaje no podemos dejar de considerarle como un programa Windows, elemental pero con toda la funcionalidad que hasta éste momento nos interesa saber, se trata de una ventana para nuestra aplicación que incluye su respectiva área cliente, ésta es en pocas palabras el espacio del que podemos disponer para que nuestra aplicación despliegue la información que deseamos dar a conocer al usuario de nuestro programa.

     Es muy probable que Usted haya dado un vistazo al tutorial de C/C++ en éste mismo sitio en donde todos los programas de ejemplo se desarrollan para el entorno DOS en donde simple y sencillamente el programa en ejecución ocupa la totalidad de la pantalla y de los recursos del sistema, así se trate de mostrar una sóla línea de texto. Usted lo sabe, Windows es diferente, éste sistema operativo genera una ó varias ventanas permitiendo de ésta manera la carácterística denominada multitárea que tanto éxito le ha valido a Windows. Las ventanas podemos utilizarlas no sólo para desplegar texto, también se utilizan para representar todo tipo de gráficos. Como ya se explicó en la lección anterior, Windows es un sistema operativo basado en mensajes, como no se puede garantizar que la información presentada en el área cliente de una ventana esté ahí indefinidamente, como es el caso cuando un cuadro de diálogo se posiciona encima del área cliente, se necesita de un mecanismo que informe del momento en que se debe redibujar la información presentada, ésta es la función del mensaje WM_PAINT. En ésta lección estudiaremos diferentes situaciones en las que se produce el mensaje WM_PAINT.

     Para dibujar en el área cliente de una ventana se utilizan las funciones llamadas GDI (Graphics Device Interface), o sea dispositivo de interfaz gráfica que es el subsistema de Windows responsable de gestionar gráficos (incluyendo texto) tanto a pantalla como a la impresora. Una función GDI muy popular es TextOut( ) definida así:


TextOut (hdc, x, y, psCadena, iLongitud);

     Como es fácil deducir, sirve para dibujar texto, tiene cuatro parámetros, hdc es el manejador para el contexto de dispositivo (handle to a device context), x e y son las coordenadas de la posición de inicio de la cadena de caracteres, psCadena es un puntero que señala a la cadena de caracteres, y por último iLongitud es la cantidad de caracteres a desplegar. Lo primero que interesa estudiar es cómo obtener el primer parámetro de la función, el contexto de dispositivo, pieza fundamental para la gran mayoría de las funciones GDI.

Volver al principio

Hola mundo

El contexto de dispositivo 

     Para empezar, un manejador (handle) es un número entero que Windows utiliza para saber con quién se está comunicando en un momento dado, para definirlo con mayor precisión, se trata de una estructura que GDI mantiene internamente y está asociada directamente con algún dispositivo de visualización, sea tarjeta de gráficos, impresora, graficadora, etc. Algunos de los miembros de la estructura son atributos propios que determinan por ejemplo, el color del texto, el color del fondo del texto, la forma de interpretar las coordenadas, la fuente que se utiliza, etc. Una forma de obtener un contexto de dispositivo se utiliza al procesar un mensaje WM_PAINT, para ésto nos valemos de un par de funciones: BeginPaint ( ) y su necesaria compañera EndPaint ( ). Para utilizarlas necesitamos dos cosas, el manejador de ventana (hwnd) que pasamos como parámetro a la función de procedimiento de ventana y la dirección de una variable de estructura de tipo PAINTSTRUCT muy comunmente llamada ps. Veamos el código de un procedimiento de ventana que nos permita dibujar en el área cliente:


LRESULT CALLBACK Procedimiento_de_ventana (HWND hwnd, UINT iMsg,
  WPARAM wParam, LPARAM lParam)
{
    HDC		hdc;
    PAINTSTRUCT	ps;

    switch (iMsg)
    {
        case WM_PAINT:
        hdc = BeginPaint (hwnd, &ps);
        TextOut(hdc, 10, 10, "Programando Windows", 19);
        EndPaint (hwnd, &ps);
        return 0;

        case WM_DESTROY:
        PostQuitMessage (0);
        return 0;
    }
    return DefWindowProc (hwnd, iMsg, wParam, lParam);
}

     Observe que se trata del procedimiento de ventana del programa "ventana.c" de la lección anterior, modificandolo de la manera mostrada y compilando, el programa despliega la cadena de caracteres "Programando Windows" situado a 10 pixeles a la derecha (posición x) y 10 pixeles abajo (posición y) con respecto a la esquina superior izquierda del área cliente, la cadena contiene, incluyendo el espacio en blanco, un total de 19 caracteres. Compare la manera de utilizar la función TextOut ( ) en el código con su definición dada anteriormente.

     Como ya vimos, una manera de obtener un manejador a un contexto de dispositivo es utilizando las funciones BeginPaint( ) y EndPaint( ) en respuesta a un mensaje WM_PAINT. Cuando se necesita dibujar en el área cliente como consecuencia de otros mensajes diferentes de WM_PAINT se utilizan las funciones GetDC( ) y su compañera ReleaseDC( ). Por lo general utilizamos éstas funciones en respuesta a mensajes generados por el teclado ó de mensajes del ratón permitiendo la actualización del área cliente sin invalidar parte de la misma para generar mensajes WM_PAINT. En el siguiente segmento de código he modificado nuevamente el procedimiento de ventana para escribir en el área cliente como respuesta a un mensaje WM_KEYDOWN generado al momento en que se presiona una tecla cualquiera, naturalmente, se utilizan las funciones GetDC( ) y ReleaseDC( ) para obtener el manejador de contexto de dispositivo hdc.


LRESULT CALLBACK Procedimiento_de_ventana (HWND hwnd, UINT iMsg,
  WPARAM wParam, LPARAM lParam)

{
    HDC         hdc;

    switch (iMsg)
    {
        case WM_KEYDOWN:
        hdc = GetDC(hwnd);
        TextOut(hdc, 20, 20, "Programando Windows", 19);
        ReleaseDC(hwnd, hdc);
        return 0;

        case WM_DESTROY:
        PostQuitMessage (0);
        return 0;
    }

    return DefWindowProc (hwnd, iMsg, wParam, lParam);
}

Volver al principio

Hola mundo

La función TextOut( ) 

     Ahora que ya sabemos cómo obtener el manejador del contexto de dispositivo es importante analizar algunos detalles relacionados con la forma de representar texto en un programa Windows. Al obtener el manejador de contexto de dispositivo, Windows rellena la estructura interna del contexto de dispositivo con los valores por defecto, por supuesto que éstos valores se pueden cambiar utilizando diferentes funciones GDI. Los atributos del contexto de dispositivo controlan las carácterísticas del texto visualizado, por ejemplo, el color del texto cuyo valor por defecto es negro, el color de fondo, blanco por defecto. Cuando un programa escribe texto en la ventana utiliza el color de fondo para rellenar la llamada caja de carácter que es el espacio alrededor de cada carácter. Éste color de fondo no es el mismo que el color especificado para el fondo del área cliente de la ventana.
El contexto de dispositivo también define una región de recorte (clipping region) que dependiendo de la función utilizada para obtener el manejador de contexto de dispositivo puede ser toda el área cliente de la ventana, valor por defecto si utilizamos la función GetDC( ) ó bién la región no válida para un manejador de contexto de dispositivo obtenido a partir de una función BeginPaint( ). En ámbos casos, Windows sólo dibujará dentro de la región de recorte.

     En éste momento nuestro punto de interés es analizar la mecánica para desplegar texto en el área cliente de nuestra ventana, un aspecto importante es conocer el tamaño de los caracteres, para ésto, el contexto de dispositivo define una fuente o tipo de letra por defecto llamada fuente de sistema (system font) definida en los archivos de cabecera de Windows con el identificador SYSTEM_FONT, ésta fuente es de tipo "raster", es decir, que los caracteres se definen como bloques de puntos. La fuente de sistema tiene que ser diseñada para que al menos quepan en pantalla 25 renglones de 80 caracteres. Si deseamos visualizar múltiples líneas de texto utilizando la función TextOut( ) se necesita determinar previamente el tamaño de los caracteres de la fuente, ésto se consigue utilizando la función GetTextMetrics( ) que devuelve información sobre la fuente actualmente seleccionada en el contexto de dispositivo. Windows copia los diferentes valores relativos a la fuente en una estructura de tipo TEXTMETRIC. Para usar la función GetTextMetrics se necesita definir una variable de tipo struct TEXTMETRIC, los programadores Windows suelen llamar a ésta variable tm:


TEXTMETRIC	tm;

     En seguida se obtiene un manejador para un contexto de dispositivo y se llama a la función GetTextMetrics( ):


hdc = GetDC(hwnd);
GetTextMetrics(hdc, &tm);
ReleaseDC(hwnd, hdc);

     Después de ésto los valores relativos a la fuente seleccionada en el contexto de dispositivo quedan almacenados en la estructura TEXTMETRIC definida en los archivos de cabecera de Windows de la siguiente manera:


typedef struct _TEXTMETRIC { // tm  

    LONG tmHeight;
    LONG tmAscent;
    LONG tmDescent;
    LONG tmInternalLeading;
    LONG tmExternalLeading;
    LONG tmAveCharWidth;
    LONG tmMaxCharWidth;
    LONG tmWeight;
    LONG tmOverhang;
    LONG tmDigitizedAspectX;
    LONG tmDigitizedAspectY;
    BCHAR tmFirstChar;
    BCHAR tmLastChar;
    BCHAR tmDefaultChar;
    BCHAR tmBreakChar;
    BYTE tmItalic;
    BYTE tmUnderlined;
    BYTE tmStruckOut;
    BYTE tmPitchAndFamily;
    BYTE tmCharSet;

} TEXTMETRIC;

     Cinco son los valores que determinan el tamaño vertical de un carácter: tmInternalLeading es el espacio para colocar acentos; tmExternalLeading es la distancia que el diseñador de la fuente sugiere para espaciar diferentes líneas de texto; tmHeight es la altura total del carácter; tmAscent es la distancia que el carácter se eleva por encima de la línea base, y tmDescent es la distancia que un carácter desciende de la línea base. Las distancias mencionadas están representadas en el siguiente diagrama:

Dimensiones verticales de un carácter

     En la estructura TEXTMETRIC existen dos campos que definen uno la anchura media del carácter en letras minúsculas, tmAveCharWidth y el otro la anchura del carácter más ancho de la fuente utilizada, tmMaxCharWidth. Para una fuente de tamaño fijo, éstos dos valores son iguales. Cuando se necesite conocer la anchura media de un carácter para letras mayúsculas, se considera éste valor como un 150% de tmAveCharWidth. Durante una sesión Windows las dimensiones de la fuente de sistema no cambian por lo que solo es necesario llamar una vez a GetTextMetrics( ) y por lo general ésto se hace en respuesta a un mensaje WM_CREATE, éste lo envía el sistema operativo a su procedimiento de ventana como consecuencia de utilizar la función CreateWindow( ) dentro de la función principal de Windows llamada WinMain( ). Podemos utilizar dos variables de tipo static int para almacenar los valores respectivos para la anchura media del carácter, cxChar y la altura total del carácter, cyChar. De ésta manera nuestro código que responderá al mensaje WM_CREATE puede ser el siguiente:


case WM_CREATE:
hdc = GetDC(hwnd);
GetTextMetrics(hdc, &tm);
cxChar = tm.tmAveCharWidth;
cyChar = tm.tmHeight + tm.tmExternalLeading;
ReleaseDC(hwnd, hdc);
return 0;

     Con éstos elementos podemos utiizar el valor almacenado en cxChar para la coordenada x en la función TextOut( ) y el valor cyChar*(1+i) para la coordenada y donde i representa el número de línea, valor almacenado en una variable de tipo int. Hasta éste punto ya sabemos cómo obtener tres de los cinco parámetros que requiere la función TextOut( ), veamos los últimos dos parámetros antes de escribir un programa que despliegue múltiples líneas de texto en el área cliente de la ventana. Usted estará familiarizado con la función de la librería estándar de C llamada printf( ). En programación para Windows no podemos utilizar ésta función porque Windows es un entorno con independencia de dispositivo, pero sí es posible utilizar la función sprintf( ) que es similar a printf( ) excepto que sprintf( ) escribe los caracteres en un array en lugar de hacerlo al dispositivo estándar de salida, para suerte de la función TextOut( ) el valor devuelto por sprintf( ) es la longitud de la cadena de caracteres, en otras palabras, mataremos dos pájaros con un solo tiro:


iLongitud = sprintf(szBuffer, "El texto deseado aquí");
TextOut(hdc, x, y, szBuffer, iLongitud);

     De acuerdo a la definición dada arriba para la función TextOut( ), iLongitud es la cantidad de caracteres contenidos en el array szBuffer, por lo tanto ya tenemos toda la información necesaria para utilizar la función TextOut( ) en un programa que despliegue múltiples líneas de texto:


//**************************************************
//  besos1.c
//  Despliega múltiples líneas de texto
//  (c)1998, Virgilio Gómez Negrete
//**************************************************

#include <windows.h>
#include <string.h>

#define NUMLINEAS ((int)(sizeof poesia / sizeof poesia[0]))

struct
{
    char *szPoema;
}
poesia[] =
{
    "BESOS (Gabriela Mistral).",
    " ",
    "Hay besos que pronuncian por si solos",
    "la sentencia de amor condenatoria,",
    "hay besos que se dan con la mirada",
    "hay besos que se dan con la memoria.",
    " ",
    "Hay besos silenciosos, besos nobles",
    "hay besos enigmáticos, sinceros",
    "hay besos que se dan solo las almas",
    "hay besos por prohibidos, verdaderos.",
    " ",
    "Hay besos que calcinan y que hieren,",
    "hay besos que arrebatan los sentidos,",
    "hay besos misteriosos que han dejado",
    "mil sueños errantes y perdidos.",
    " ",
    "Hay besos problemáticos que encierran",
    "una clave que nadie a descifrado,",
    "hay besos que engendran la tragedia",
    "cuántas rosas en broche han deshojado.",
    " ",
    "Hay besos perfumados, besos tibios",
    "que palpitan en íntimos anhelos,",
    "hay besos que en los labios dejan huellas",
    "como un campo de sol entre dos hielos.",
    " ",
    "Hay besos que parecen azucenas",
    "por sublimes, ingenuos y por puros,",
    "hay besos traicioneros y cobardes,",
    "hay besos maldecidos y perjuros.",
    " ",
    "Judas besa a Jesus y deja impresa",
    "en su rostro de Dios, la felonía,",
    "mientras la Magdalena con sus besos",
    "fortifica piadosa su agonia.",
    " ",
    "Desde entonces en los besos palpita",
    "el amor, la traición y los dolores,",
    "en las bodas humanas se parecen",
    "a la brisa que juega con las flores.",
    " ",
    "Hay besos que producen desvaríos",
    "de amorosa pasión ardiente y loca,",
    "tú los conoces bien son besos míos",
    "inventados por mi, para tu boca.",
    " ",
    "Besos de llama que en rastro impreso",
    "llevan los surcos de un amor vedado,",
    "besos de tempestad, salvajes besos",
    "que solo nuestros labios han probado.",
    " ",
    "Te acuerdas del primero...? indefinible,",
    "cubrió tu faz de cardenos sonrojos",
    "y en los espasmos de emoción terrible,",
    "llenáronse de lágrimas tus ojos.",
    " ",
    "Te acuerdas que una tarde en loco exceso",
    "te vi celoso imaginando agravios.",
    "te suspendí en mis brazos... vibró un beso,",
    "y que viste despues...? Sangre en mis labios.",
    " ",
    "Yo te enseñé a besar: los besos fríos",
    "son de impasible corazón de roca,",
    "yo te enseñé a besar con besos míos",
    "inventados por mi, para tu boca."
};

LRESULT CALLBACK Procedimiento_de_ventana(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  PSTR szCmdLine, int iCmdShow)
{
    static char   szAppName[] = "Besos";
    HWND          hwnd;
    MSG           msg;
    WNDCLASSEX    clase_de_ventana;

    clase_de_ventana.cbSize        = sizeof (clase_de_ventana);
    clase_de_ventana.style         = CS_HREDRAW | CS_VREDRAW;
    clase_de_ventana.lpfnWndProc   = Procedimiento_de_ventana;
    clase_de_ventana.cbClsExtra    = 0;
    clase_de_ventana.cbWndExtra    = 0;
    clase_de_ventana.hInstance     = hInstance;
    clase_de_ventana.hIcon         = LoadIcon (NULL, IDI_APPLICATION);
    clase_de_ventana.hCursor       = LoadCursor (NULL, IDC_ARROW);
    clase_de_ventana.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    clase_de_ventana.lpszMenuName  = NULL;
    clase_de_ventana.lpszClassName = szAppName;
    clase_de_ventana.hIconSm       = LoadIcon (NULL, IDI_APPLICATION);

    RegisterClassEx (&clase_de_ventana);

    hwnd = CreateWindow (szAppName, "Besos, de Gabriela Mistral",
      WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
      CW_USEDEFAULT, NULL, NULL, hInstance, NULL);

    ShowWindow (hwnd, iCmdShow);
    UpdateWindow (hwnd);

    while (GetMessage (&msg, NULL, 0, 0))
    {
        TranslateMessage (&msg);
        DispatchMessage (&msg);
    }

    return msg.wParam;
}

LRESULT CALLBACK Procedimiento_de_ventana (HWND hwnd, UINT iMsg,
  WPARAM wParam, LPARAM lParam)

{
    static int   cxChar, cyChar;
    HDC          hdc;
    int          i;
    PAINTSTRUCT  ps;
    TEXTMETRIC   tm;

    switch (iMsg)
    {
        case WM_CREATE:
        hdc = GetDC(hwnd);
        GetTextMetrics(hdc, &tm);
        cxChar = tm.tmAveCharWidth;
        cyChar = tm.tmHeight + tm.tmExternalLeading;
        ReleaseDC(hwnd, hdc);
        return 0;

        case WM_PAINT:
        hdc = BeginPaint(hwnd, &ps);
        for(i=0; i<NUMLINEAS; i++)
        TextOut(hdc, cxChar, cyChar*(1+i), poesia[i].szPoema,
          strlen(poesia[i].szPoema));
        EndPaint(hwnd, &ps);
        return 0;

        case WM_DESTROY:
        PostQuitMessage (0);
        return 0;
    }

    return DefWindowProc (hwnd, iMsg, wParam, lParam);
}

     De éste programa prácticamente se ha explicado todo, sin embargo al compilar y ejecutar el código fuente observamos que una ventana normal, incluso maximizada en un monitor de 800x600 pixeles de resolución, no es suficiente para mostrar todo el texto que compone la poesía "Besos" de Gabriela Mistral, en una situación así lo que se requiere es hechar mano de las barras de desplazamiento...

Volver al principio

Hola mundo

Barras de desplazamiento 

     Como el tamaño de una ventana de un programa ejecutandose bajo el sistema operativo Windows 9x no está garantizado a un tamaño predeterminado, es común encontrarse ante la situación en que la información desplegada por el programa no se ajusta al tamaño actual de la ventana. Para solventar éste inconveniente el sistema provee de las llamadas barras de desplazamiento, elementos que Yo estoy seguro, Usted los encuentra ya familiares.

     Implementaremos unas barras de desplazamiento verticales que nos permitan leer el contenido total de la información desplegada por nuestro programa, en primer lugar necesitamos especificar un estilo de ventana dentro de la función CreateWindow( ) que incluya la barra de desplazamiento vertical WS_VSCROLL en conjunción con el estilo WS_OVERLAPPEDWINDOW utilizando el operador OR a nivel de bits:


WS_OVERLAPPEDWINDOW | WS_VSCROLL

     Siguiendo el órden del código fuente llamamos a la función SetScrollRange(hwnd, SB_VERT, 0, NUMLINEAS, FALSE); que sirve para especificar el rango de la barra de desplazamiento, que son un par de números enteros que representan el valor mínimo y máximo que retorna la función. Enseguida llamamos a la función SetScrollPos(hwnd, SB_VERT, iVscrollPos, TRUE); que sitúa la posición del recuadro de desplazamiento dentro de la barra. Cuando el recuadro está en la posición superior de la barra (ó al lado derecho si se trata de una barra horizontal) la posición del recuadro corresponde al valor mínimo del rango de desplazamiento, cuando el recuadro está en la parte inferior (ó a la derecha) de la barra de desplazamiento, la posición del recuadro corresponde al valor máximo del rango. Por defecto, el rango de una barra de desplazamiento es de 0 a 100, pero éste valor se cambia fácilmente con la función SetScrollRange( ). Se necesita conocer además el tamaño vertical del área cliente, éste dato lo podemos obtener en respuesta al mensaje WM_SIZE que Windows envía cada vez que la ventana cambia de tamaño. Específicamente, el tamaño vertical del área cliente lo encontramos en la palabra de orden superior de la variable lParam utilizando la macro definida en Windows HIWORD de ésta manera: cyCliente = HIWORD(lParam).

     Cuando se hace clic con el ratón sobre la barra de desplazamiento o se arrastra el recuadro Windows envía al procedimiento de ventana los mensajes WM_VSCROLL y WM_HSCROLL. Cada acción del ratón sobre la barra de desplazamiento genera al menos dos mensajes, uno cuando se presiona el botón del ratón y otro cuando se libera. La palabra de orden inferior del parámetro wParam que acompaña al mensaje WM_VSCROLL es un número que indica el tipo de acción ejecutada por el ratón y son valores que se corresponden a identificadores definidos que comienzan con SB_ por las palabras en inglés Scroll Bar. Para una mayor información respecto a éstos mensajes conviene consultar la referencia de Windows que por lo general viene incluida en cada compilador capaz de trabajar en la plataforma Windows 9x, para nuestro programa el siguiente es el código del procedimiento de ventana correspondiente al programa llamado barraver.c que procesa los mensajes WM_SIZE y WM_VSCROLL:


LRESULT CALLBACK Procedimiento_de_ventana (HWND hwnd, UINT iMsg,
  WPARAM wParam, LPARAM lParam)

{
    static int   cxChar, cyChar, cyCliente, iVscrollPos;
    HDC          hdc;
    int          i, y;
    PAINTSTRUCT  ps;
    TEXTMETRIC   tm;

    switch (iMsg)
    {
        case WM_CREATE:
        hdc = GetDC(hwnd);
        GetTextMetrics(hdc, &tm);
        cxChar = tm.tmAveCharWidth;
        cyChar = tm.tmHeight + tm.tmExternalLeading;
        ReleaseDC(hwnd, hdc);
        SetScrollRange(hwnd, SB_VERT, 0, NUMLINEAS, FALSE);
        SetScrollPos(hwnd, SB_VERT, iVscrollPos, TRUE);
        return 0;

        case WM_SIZE:
        cyCliente = HIWORD(lParam);
        return 0;

        case WM_VSCROLL:
        switch(LOWORD(wParam))
        {
            case SB_LINEUP:
            iVscrollPos -= 1;
            break;

            case SB_LINEDOWN:
            iVscrollPos += 1;
            break;

            case SB_PAGEUP:
            iVscrollPos -= cyCliente/cyChar;
            break;

            case SB_PAGEDOWN:
            iVscrollPos += cyCliente/cyChar;
            break;

            case SB_THUMBPOSITION:
            iVscrollPos = HIWORD(wParam);
            break;

            default:
            break;
        }
        iVscrollPos = max(0, min(iVscrollPos, NUMLINEAS));
        if(iVscrollPos != GetScrollPos(hwnd, SB_VERT))
        {
            SetScrollPos(hwnd, SB_VERT, iVscrollPos, TRUE);
            InvalidateRect(hwnd, NULL, TRUE);
        }
        return 0;

        case WM_PAINT:
        hdc = BeginPaint(hwnd, &ps);
        for(i=0; i<NUMLINEAS; i++)
        {
            y = cyChar*(1-iVscrollPos+i);
            TextOut(hdc, cxChar, y, poesia[i].szPoema,
              strlen(poesia[i].szPoema));
        }
        EndPaint(hwnd, &ps);
        return 0;

        case WM_DESTROY:
        PostQuitMessage (0);
        return 0;
    }

    return DefWindowProc (hwnd, iMsg, wParam, lParam);
}

     El código completo de los programas mencionados en éste artículo los puede descargar en el hipervínculo al final en formato comprimido *.zip. Al compilar y ejecutar el programa barraver.c encontrará que en efecto, ya estamos posibilitados para leer el contenido total del texto desplegado por el programa, sin embargo el desempeño de la barra de desplazamiento vertical no es del todo eficiente, en primer lugar el texto no se desplaza por la ventana conforme arrastramos el recuadro, solo hasta que soltamos el botón del ratón la ventana actualiza su contenido. En segundo lugar, después de que está visible la última línea de texto el contenido puede ser desplazado hasta la parte superior de la ventana, éste es un efecto indeseable ya que al usuario de su programa no le interesará tener prácticamente toda la ventana vacía.

     Los pequeños pero importantes inconvenientes que presenta el programa barraver.c han sido corregidos en una nueva versión de nuestro programa que despliega la poesía de Gabriela Mistral "Besos", el nuevo código se llama barra2.c y lo puede Usted obtener en el archivo comprimido llamado win02.zip que puede descargar haciendo clic en el hipervínculo que encontrará al final de éste artículo. Se deja al estudiante diligente el análisis de los programas presentados tomando en cuenta que el máximo provecho que se puede obtener de éste artículo es escribiendo nuestros propios programas, los ejemplos presentados servirán, espero, como un buén punto de partida.

Volver al principio

Hola mundo

Descargas 

     Descargue el código fuente de los programas de éste artículo. Archivo comprimido win02.zip (10 kb.)

Volver al principio

Hola mundo

© 1999 Virgilio Gómez Negrete, Derechos Reservados