Sólo Programadores Banner 468x60

<//--tabla3-->

<//!--tabla2-->
<//!--tabla1-->
Este mes en Sólo Programadores
Contenido del CD-ROM
Índice temático
Suscripción
<//!--fin de tabla1-->
<//!--fin tabla2-->

Programación básica en Windows (III)

A lo largo del artículo se explicará detenidamente la forma de programar uno de los recursos más usados en Windows: las barras de desplazamiento, las cuales, además de fáciles de crear, son un elemento muy importante a la hora de realizar aplicaciones capaces de manejar gran cantidad de información.

En el anterior capítulo de este pequeño curso de C quedó explicado a fondo el código fuente de un sencillo ejemplo de programa en C para Windows que poseía todos los elementos básicos. Ahora que se supone el lector ha quedado ya familiarizado con la forma en que se programa bajo este sistema operativo, se va a pasar a detallar cómo funcionan y cómo se programan las llamadas barras de desplazamiento, las cuales, son un recurso muy usado en este sistema operativo y que como se verá, son relativamente fáciles de entender y de aplicar. De esta forma se intentarán asentar los conocimientos adquiridos por el lector en los artículos anteriores.

Las barras de desplazamiento son uno de los recursos más usados de Windows

BARRAS DE DESPLAZAMIENTO

Como casi todos lo usuarios de aplicaciones saben por experiencia propia, son uno de los recursos más utilizados en Windows. Su utilidad reside en que ofrecen al usuario la posibilidad de acceder a gran cantidad de más información de la que cabe en la ventana de la aplicación. Es decir, cuando los datos sobrepasan el límite físico de las dimensiones de la ventana, las barras de desplazamiento permiten el desplazamiento por toda la información almacenada.

Como apreciaremos más adelante, las aplicaciones se pueden programar para que usen de forma individual las barras verticales, las horizontales o hacer que estén presentes ambas simultáneamente.

Como concepto relacionado, decir también que el cuadro de desplazamiento de una barra es el rectángulo que aparece dentro de la propia barra de desplazamiento, y se usa para que el usuario conozca la posición exacta de la ventana virtual que se está viendo respecto a la ventana real imaginaria que contiene toda la información realmente disponible.

CONSTANTE Y COMANDOS

Los comandos y constantes que se utilizan para manejar las barras se encuentran definidos en el fichero winuser.h. Mediante ellos resulta más intuitivo y fácil el desarrollo de aplicaciones, evitando el manejo de valores sin relación alguna con lo que representan. En la tabla 1 se muestra una lista de dichos valores.

RANGO DE DESPLAZAMIENTO

Ccon este término nos estamos refriendo a las posiciones tanto mínima como máxima que son válidas para un cuadro de desplazamiento. El programa es capaz de definirlos mediante enteros, aunque por defecto ya posee los valores predeterminados 0 y 100 respectivamente

TIPOS DE BARRAS

Las barras de desplazamiento se pueden dividir en dos clases: por un lado tenemos las barras de desplazamiento propiamente dichas, y por otro los denominados controles de barra. Normalmente los controles de Windows se comportan como ventanas hijas y separadas que aparecen asociadas a la ventana padre y que además, poseen la propiedad de ser totalmente programables, pudiéndose colocar y dimensionar según la necesidad del desarrollador. La barra de desplazamiento por su parte, tiene un tamaño y posición en la ventana predeterminados según sea el tamaño y ubicación del área cliente de la ventana en la que se utiliza.

FUNCIONES DE LAS BARRAS

Las funciones GetScrollPos() y SetScrollPos() se utilizan para poner u obtener el valor de la posición dentro de una barra de desplazamiento. Ambas envían o reciben un valor de 16 bits.

Existen dos clases de barras: los controles y las propias barras de desplazamiento

Además de las dos mencionadas, en Windows de 32 bits (95/98/NT) existen dos funciones adicionales: GetScrollInfo() y SetScrollInfo(). La primera utiliza tres parámetros: un handle de la ventana, el flag fnBar y un puntero a una estructura. El flag fnBar puede poseer tres valores: SB_CTL (para un control), SB_HORZ (barra de desplazamiento horizontal) y SB_VERT (barra de desplazamiento vertical). La estructura mencionada a la que apunta el tercer parámetro es la siguiente:

typedef struct tagSCROLLINFO
 {
  UINT cbSize
  UINT fMask;
  int nMin;
  int nMax;
  UINT nPage;
  int nPos;
  int nTrackPos;
 } SCROLLINFO, FAR *LPSCROLLINFO
typedef SCROLLINFO CONST FAR *LPSCROLLINFO;

Respecto a la estructura anterior, sólo debemos mencionar que cbSize se refiere al tamaño de la propia estructura, y fMask es una combinación de los valores: SIF_ALL, SIF_DISABLENOSCROLL, SIF_PAGE, SIF_POS y SIF_RANGE.

Por otro lado disponemos de la función SetScrollInfo() donde se requieren cuatro parámetros: los tres de la anterior más un valor de tipo Boolean (TRUE o FALSE). Si se indica el primero de estos valores se dibuja el botón del cuadro de desplazamiento. En caso contrario dicho cuadro no hará su aparición.

EJEMPLO DE UN PROGRAMA

Dentro del listado 1 se ha incluido el código fuente de un programa C para Windows que hace uso de las barras de desplazamiento. De esta manera el lector podrá apreciar cómo se aplican todas las instrucciones relacionadas con esta materia en un ejemplo genérico de su uso.

#include <windows.h>
#include <winuser.h>
#include <stdio.h>
#include <string.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
Char szProgName[]= "ProgName";

Int WINAPI WinMain(HINSTANCE hInst, 
HINSTANCE hPreIns, LPSTR. LpszCmdLine, int nCmdShow)
{
 HWND hWnd;
 MSG lpMsg;
 WNDCLASS wcApp;

 WcApp.lpszClassName  = szProgName;
 WcApp.hInstance = hInst;
 WcApp.lpfnWndProc  = WndProc;
 WcApp.hCursor  = LoadCursor(NULL, IDC_ARROW);
 WcApp.hIcon = 0;
 WcApp.lpszMenuName = 0;
 WcApp.hbrBackground = GetStockObject
(LTGRAY_BRUSH);
 WcApp.style = CS_HREDRAW | CS_VREDRAW;
 WcApp.cbClsExtra = 0;
 WcApp.cbWndExtra = 0;
  If(!RegisterClass (&wcApp))
    Return 0;

 hWnd= CreateWindow(szProgName, 
"Ejemplo 1. Un programa que usa 
barras de desplazamiento", WS_OVERLAPPEDWINDOW, 
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 
CW_USEDEFAULT, (HWND) NULL,  (HMENU) NULL, 
(HANDLE) hInst, (LPSTR) NULL);

 ShowWindow(hWnd, nCmDShow);
 UpdateWindow(hWnd);
 While (GetMessage(&lpMsg, NULL, 0, 0)) 
      { 
         TranslateMessage(&lpMsg); 
         DispatchMessage(&lpMsg);
      }
  return(lpMsg.wParam);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT messg, 
WPARAM wParam, LPARAM lParam)
 {
  HDC hdc;
  PAINTSTRUCT ps;
  TEXTMETRIC tm;
  char szbuffer[160] = "  ";
  static int charwt, charht, HOldPos, 
HNewPos, VOldPos, VNewPos, nDelta;
  FILE *fp;
  int i,t,ch;
  SCROLLINFO si;
  
  switch (messg)
    {
     case WM_CREATE:
     hdc= GetDC (hWnd);
     GetTextMetrics( hdc, &tm);
     charwt = tm.tmAveCharWidth;
     charht = tm.tmHeight + tm.
     tmExternalLeading;
     ReleaseDC( hWnd, hdc);
     break;
     
     case WM_HSCROLL;
     si.cbSize = sizeof(si);
     si.fMask = SIF_ALL;
     si.nMin = 0;
     si.nMax = 100;
     si.npage = 10;
     si.nPos = HNewPos;
     SetScrollInfo(hWnd, SB_HORZ, &si, FALSE);
     
     HOldPos = si.nPos;
     
     switch (LOWORD(wParam))
      {
       case SB_LINERIGHT:
          nDelta = 1;
          break;
       case SB_LINELEFT:
          nDelta = -1;
          break;
       case SB_PAGERIGHT:
          nDelta = 15;
          break;
       case SB_PAGELEFT:
          nDelta = -15;
          break;
       case SB_THUMBPOSITION
          nDelta = ( HIWORD(wParam)) - 
         HOldPos;
          break;
       default:
          nDelta = 0;
          break;
     }

   if(nDelta)
    {
     HNewPos = HOldPos + nDelta;
     if(HOldPos < si.nMin)
         {
          nDelta - = HOldPos - si.nMin;
          HNewPos = si.nMin;
         }
     if (HOldPos > si.Max)
        { 
         nDelta = - HOldPos - si.nMax;
         HNewPos = si.nMax;
        }   
     }
   if(nDelta)
    {
      SetScrollPos(hWnd, SB_HORZ, HNewPos, TRUE);
      si.nPos = HNewPos;
      SetScrollInfo( hWnd, SB_HORZ; &si, FALSE);
     }
   InvalidateRect(hWnd, NULL, TRUE);
   break;  

   case WM_VSCROLL:
      si.cbSize = sizeof(si);
      si.fMask = SIF_ALL;
      si.nMin = 0;  
      si.nMax = 100;
      si.nPage = 10;
      si.nPos = VNewPos;
      SetScrollInfo( hWnd, SB_VERT, 
&si, FALSE);
      
      VOldPos = si.nPos;
      
      switch( LOWORD( wParam))
         {
          case SB_LINEDOWN:
             nDelta = 1;
             break;
          case SB_LINEUP:
             nDelta = -1;
             break;
          case SB_PAGEDOWN:
             nDelta = 15;
             break;
          case SB_PAGEUP:
             nDelta = -15;
             break;
          case SB_THUMBPOSITION:
             nDelta = (HIWORD( wParam)) - VOldPos;
             break ;         
          default:
             nDelta = 0; 
             break;
         }

     if(nDelta)
        {
         VNewPos = VOldPos + nDelta;
         if(VOlPos < si.nMin)
             { 
              nDelta - = VOldPos - si.nMin;
              VNewPos = si.nMin;
             }
         if(VOlPos > si.nMax)
             { 
              nDelta - = VOldPos - si.nMax;
              VNewPos = si.nMax;
             }
          }
      
     if(nDelta)
          {
            SetScrollPos( hWnd, SB_VERT, VNewPos,
            TRUE);
            si.nPos = VNewPos;
            SetScrollInfo( hWnd, SB_VERT, &si,
            FALSE);
          }
     InvalidateRect( hWnd, NULL, TRUE);
     break;

     case WM_PAINT:
          hdc = BeginPaint ( hWnd, &ps);

          // Funciones CGI
          t = 0;
          if (( fp= fopen("c:/texto.doc", "r")) 
          != NULL)
             {
              while(!feof(fp)) 
                 {
                  ch = fgetc(fp);
                  i = 0;
                 while((ch!='\n') && (ch!= EOF)) 
                     {
                      szBuffer[i] = (char)ch;
                       ch = fgetc(fp);
                       i++;
                     }
                  textOut( hdc, -charwt *(HNewPos), 
                                charht *(t - VNewPos),
                   szBuffer,i);
                  t++;
                }
           }
        fclose( fp);

       // Fuciones de CGI antes:
       ValidateRect( hWnd, NULL);
       EndPaint( hWnd, &ps);
       break;
   
       case WM_DESTROY:
       PostQuitMessage(0);
       break;
 
       default:
          return( DefWindowProc( hWnd, messg, 
          wParam, lParam));
     }
     return(0);
  }

ANÁLISIS DEL EJEMPLO

Como se puede observar en el código fuente con el que estamos trabajando, este ejemplo necesita para funcionar correctamente un fichero de texto denominado texto.doc que el programa se encargará de abrir y cuyo contenido podrá ser visualizado mediante las barras de desplazamiento que previamente han sido programadas para la ventana.

El código correspondiente a la carga del fichero no supone ningún problema de entender ya que no incluye ninguno de los conceptos específicos de la programación bajo Windows y básicamente es código C típico del que cualquier programador medio ya ha usado en alguna ocasión.

La apertura del fichero de texto se hace de forma normal, o sea, se indica el path u filename del mismo, de forma que se obtiene un handle al mismo. A partir de aquí podemos ya leer su contenido.

Un control normalmente aparece como una ventana hija dentro de una ventana padre

Para poder acceder a su contenido se ha creado un bucle bidimensional donde se leen los caracteres del fichero por líneas (al final de cada una de las cuales ésta se escribe en el búffer de pantalla) y dura infinitamente hasta que se lea el carácter de fin de fichero (OEF), momento en que el bucle se da por finalizado.

Realizada la lectura del fichero, se cierra.

Otro aspecto que se puede observar consiste en la aparición de una función nueva denominada GetTextmetrix() que no había sido explicada hasta ahora. Se utiliza para consultar y manejar todos los valores relacionados con los tipos de fuentes empleados por el programa, lo cual, debido a la extensión del tema, se tratará en el próximo artículo con mayor profundidad.

WM_HSCROLL y WM_VSCROLL se utilizan en el programa para que se puedan procesar los mensajes generados por Windows relacionados con las barras de desplazamiento. Como se puede comprobar, los dos segmentos de código que tratan las dos barras, tanto la horizontal como la vertical, son muy parecidos.

El código necesario para gestionar la barra horizontal y vertical es prácticamente el mismo

Una vez que se ejecuta el programa, si el usuario pulsa sobre una de las flechas de desplazamiento de la barra vertical, Windows mandará a la aplicación un mensaje SB_LINEUP o SB_LINEDOWN. Por otro lado, si el usuario pulsa en algún punto de la barra que no sea el cuadro de desplazamiento, se generará un mensaje de la clase SB_PAGEDOWN o SB_PAGEUP, que el programa ejecutará como un desplazamiento de 15 líneas del texto ya sea hacia abajo o hacia arriba.

En todos los casos de desplazamiento sobre alguna de las barras, el mensaje se interpreta, se cambia el valor de nDelta y se actualizan todas aquellas posiciones de los cuadros de desplazamiento.

MÁS PRUEBAS

Como se dijo al final del artículo anterior de esta serie, una vez se comprende el funcionamiento de cada parte del código fuente dado de ejemplo, el usuario puede empezar a practicar la inserción de líneas de código para practicar funciones gráficas. Se caracterizan por su sencillez de uso, aunque es necesario disponer de la información técnica sobre el número y función de los parámetros utilizados en cada una de ellas.

Finalizamos con algunos ejemplos con los que podreis practicar y que detallamos a lo largo del listado 2.

1. Dibujar un rectángulo:
Rectangle(hdc, 25,300,130,375);
TextOut(hdc, 50, 325, "Rectángulo", 16);

2. Dibujar un círculo:
Ellipse(hdc, 375, 75, 525, 225);
TextOut(hdc, 435, 190, "Círculo", 16);

3. Dibujar una elipse:
Ellipse(hdc, 275, 300, 200, 250);
TextOut(hdc, 450,190, "Elipse",16);

4.Dibujar una línea diagonal y un texto:
MoveToEx(hdc, 20, 20 ,NULL);
LineTo(hdc, 80, 80);
TextOut (hdc, 50, 25, "<-línea diagonal",16);

<//!--fin tabla3-->


Banner 468x60
Explorer 4.0, Netscape 4.0. Resolución 800 x 600.
©Tower Communications 1.998.
Diseño: GRUPO ALBERTINA DE COMUNICACION.