lunes, 29 de septiembre de 2014

DISEÑO Y REALIZACIÓN DE SERVICIOS DE PRESENTACIÓN EN ENTORNOS GRÁFICOS UT3

Técnicas profesionales avanzadas

 ¿QUÉ ES MDI?
Visual Basic permite crear aplicaciones empleando una interfaz de múltiples documentos (MDI - Multiple Document Interface), o dicho en términos de Visual Basic, múltiples formularios. En una aplicación MDI, se pueden abrir varias ventanas hijas. Cada una de estas ventanas hijas (formularios) son iguales entre sí. En una aplicación MDI pueden haber varias ventanas hijas, pero solo una ventana padre por aplicación. El formulario padre actúa como contenedor de los formulario hijo. Muchos procesadores de textos bajo Windows son buenos ejemplos de aplicaciones MDI.

Para crear una aplicación MDI se empezará a crear un nuevo proyecto y, se accede a Insert/MDI Form. El nuevo formulario será el formulario padre. Para que un formulario sea un formulario hijo, se deberá cambiar su propiedad MDIChild y establecerla a True.
Cuando se visualizan varios formulario hijos, todos comparten el mismo código, pero cada uno de ellos guarda sus propios datos y reconoce sus propios sucesos. Según ésto, no se podrá utilizar el identificador del formulario para referirse a los controles o a sus propiedades, aunque sí se podrá utilizar la palabra clave Me.

COMPORTAMIENTO DE MENÚS Y BARRAS DE HERRAMIENTAS

Los únicos controles que se pueden incluir en un formulario padre son aquellos que tengan la propiedad Align y, dentro de éstos controles se podrán colocar otros controles. De esta forma se crean las barras de herramientas.

Los menús de cada formulario hijo, son visualizados en el formulario padre. Cada vez que se activa un formulario hijo, su menú sustituye al menú que se esté visualizando en el formulario padre. Ahora bien, si no hay un formulario hijo cargado, o si dicho formulario no tiene menú, entonces se visualiza el del padre, si lo tiene.
Es aconsejable que el formulario padre tenga un menú que permita abrir o crear un nuevo formulario hijo.
EVENTO QUERYUNLOAD
Cuando el usuario ejecuta la orden Cerrar del menú de control del formulario padre, Visual Basic intenta descargar dicho formulario. Esto hace que se dé el suceso QueryUnload primero para el formulario padre y luego para cada uno de los hijos.
Cuando el usuario ejecuta la orden Cerrar del menú de control del formulario hijo también se da el suceso QueryUnload pero solo para este formulario.
La sentencia Unload permite descargar un formulario o un control de la memoria, pero antes de que el formulario sea descargado, se da el suceso QueryUnload, seguido del suceso Unload. El suceso QueryUnload para un formulario MDI va seguido del suceso QueryUnload para cada uno de los formularios hijo.

EJEMPLO:
Vamos a construir una aplicación que permita crear varios formularios hijo. Para ello, se necesitará crear un nuevo proyecto con un formulario MDI y, un formulario hijo, al que se le haya establecido su propiedad Caption a Formulario Hijo y su propiedad Name a frmHijo. Al formulario padre se le añadirá un menú Archivo con los comandos Nuevo y Salir. Se añadirá el menú Ventana con la propiedad Window List activada y, con las opciones Cascada, Mosaico y Organizar iconos. También se le añadirá un control 3D panel, seleccionando Tools/Custom Controls. A dicho control se le modificará las propiedades Align con 2 - Align Bottom, BevelInner con 1 - Inset, BevelWidth con 2 y, BordeWidth con 2. Dentro de este control se añadirán dos etiquetas: lblTexto y lblContador.


Código
    En un nuevo módulo:
Public Contador As Integer
En el formulario padre:
Private Sub mnuArchivoNuevo_Click()
Dim X As New frmHijo
Contador = Contador + 1
X.Show
End Sub
Private Sub mnuArchivoSalir_Click()
End
End Sub
Private Sub mnuVentanaCascada_Click()
MDIForm1.Arrange 0
End Sub
Private Sub mnuVentanaMosaico_Click()
MDIFomr1.Arrange 1
End Sub
Private Sub mnuVentanaOrganizar_Click()
MDIFomr1.Arrange 3
End Sub
Private Sub MDIForm_Initialize()
Contador = 0
lblContador = Str(Contador)
End Sub
En el formulario hijo:
Private Sub Form_Initialize()
Me.Caption = Me.Caption & " #" & Str(Contador)
MDIForm1.lblContador = Str(Contador)
End Sub
Private Sub Form_Unload(Cancel As Integer)
‘Si el valor de Cancel es True, el formulario asociado no se descarga.
‘En otro caso, se van cerrando primero cada hijo y, por último el padre.
Contador = Contador - 1
MDIForm1.lblContador = Str(Contador)
End Sub


¿Qué es el API Win32 ?
Win32 es un conjunto de funciones, tipos y mensajes pre-definidos para poder programar sobre los sistemas operativos de 32 bits de Microsoft. El API Win32, surge para cubrir la necesidad de crear un sistema operativo de 32 bits como es Windows 95, frente al API de 16 bits existente de Windows 3.1. Surge el problema de que Win32, no es compatible con el API de 16 bits, lo que implica que si queremos portar un código de Windows 3.1 a Windows 95, deberemos reescribir el código. Aunque hemos dicho que el API Win32 no es compatible con el API de 16 bits, hay una versión que es Win32s que sirve para la versión 3.1 de Windows. Algunas de las limita- ciones entre ambos API son:

No soportan nombres de ficheros largos, sólo el conocido formato 8.3 de DOS.
No tiene API de comunicaciones.
No soportan las capacidades Plug & Play.

Llamadas a las Funciones del API de Windows

Un programador de aplicaciones Windows además de conocer el entorno de trabajo de Windows debe conocer también su entorno de programación, conocido generalmente como interfaz de programación de aplicaciones de Windows ( Windows Application Programming Interface, abreviadamente Windows API ).
La característica primaria de la API de Windows son las funciones y los mensajes internos/externos de
Windows.

Las funciones Windows son el corazón de las aplicaciones Windows. Hay más de 600 funciones de Windows dispuestas para ser llamadas por cualquier lenguaje, como C o Visual Basic.

A través de estos mecanismos, podemos realizar gran cantidad de funciones que hasta el momento no teníamos ni idea que se podían realizar. La utilización de ésta serie de librerías que contienen las funciones de la API pueden solucionar gran cantidad de problemas en la programación, aunque también no debemos desestimar el gran poder destructivo de las mismas. La depuración de un programa es muy diferente si éste tiene incorporadas llamadas a APIs, ya que el resultado de las mismas en algunos casos puede llegar a ser incomprensible. Cuando se trabaja con éstas funciones siempre es recomendable tener a mano una buena guía o bien tener a mano alguien que sepa, para no encontrarnos con posibles problemas.

Las dos principales ventajas que obtenemos con la utilización de APIs es la gran funcionalidad que podemos darle a nuestra aplicación, y en segundo lugar la gran velocidad de proceso, ya que a menudo es mucho más rápido realizar una función a través de la API adecuada que por medio del lenguaje en si mismo.

Los mensajes son utilizados por Windows para permitir que dos o más aplicaciones se comuniquen entre sí y con el propio sistema Windows. Se dice que las aplicaciones Windows son conducidas por mensajes o sucesos.

Conocer todas las APIs de Windows es imposible, ya que tiene gran similitud con aprenderse la guía de teléfonos.

Lo que debemos hacer es realizar un razonamiento contrario, nosotros tenemos una necesidad a la hora de programar, y debemos pensar que eso tiene una solución con una API.. En la mayoría de los casos es así.


Librerías Dinámicas.

Casi todas las APIs de Windows se unen formando librerías de enlace dinámico.

Una librería dinámica ( Dynamic Link Libraries, abreviadamente DLLs ) permite que las aplicaciones Windows compartan código y recursos. Una DLL es actualmente un fichero ejecutable que contiene    funciones de Windows que pueden ser utilizadas por todas las aplicaciones.

Si bien en DOS estamos acostumbrados a utilizar librerías de enlace estático, es decir, a la hora de compilar incluyen junto con nuestro código, y de esta manera cuando se ejecuta nuestra aplicación, todas las librerías se cargan en memoria esperando a ser invocadas. Sin embargo, cuando trabajamos con DDLs, el enlace con la aplicación es dinámico en tiempo de ejecución.

Una DDL no se incluye dentro de nuestro código, sino que en el momento que realizamos la llamada a la función, la DLL se carga en memoria, se utiliza la API, y a continuación se descarga.

La gran ventaja que posee este método es que no es necesario tener gran cantidad de código cargado en memoria a la hora de ejecutar nuestra aplicación. En contra, es necesario que cuando llevemos nuestro ejecutable a otra instalación, tengamos que llevar las DLLs necesarias.

También tenemos que pensar que si utilizamos las DLLS que nos proporciona Windows, en cualquier máquina con este sistema operativo vamos a encontrar esas mismas DLLs, con lo cual no es necesario que nos las llevemos.

La utilización de librerías dinámicas tiene ventajas. Una ventaja es que como están separadas del programa se pueden actualizar sin tener que modificar los programas que las utilizan. Otra ventaja es el ahorro de memoria principal y de disco ya que como es Windows quien administra la utilización de las DLLs, no existe duplicidad de código cuando varias aplicaciones las utilizan.

También, como todo (jeje) tiene inconvenientes. Uno de ellos es el tiempo que Windows tiene que emplear en leer las funciones que el programa necesita utilizar de una DLL.

 Otra desventaja es que cada programa ejecutable necesita que estén presentes las DLLs que utiliza.  Cuando se utilizan librerías estáticas, las funciones que el programa necesita se incluyen en el mismo, por lo que ni se pierde tiempo en leerlas ni la librería tiene que estar presente.   La mayoría de éstas librerías suelen estar localizadas en el directorio SYSTEM de Windows.  Dentro de Windows tenemos gran cantidad de DLLs, agrupando las APIs en funciones respecto a un mismo tema. Además en cada nueva versión de Windows, posiblemente tengamos más DLLs para utilizar.

Para acceder a las funciones de las librerías dinámicas, lo primero que debemos hacer es declararlas.
Declaración de una Función DLL. Para declarar una función de una librería dinámica, tiene que escribir una sentencia declare en el módulo global de la aplicación, o en la sección de declaraciones de la forma o del módulo correspondiente. Por ejemplo:


Declare Function lopen Lib "kernel" Alias "_lopen" (Byval lpPathname as string, Byval iReadWrite As Integer) as Integer.    La cláusula Lib indica al lenguaje de programación la librería donde puede encontrar la función de la API de Windows declarada. Las DLLs del entorno operativo están en "Kernel", "GDI", "User", o en una de las DLLs correspondientes a un driver de dispositivo tal como "Sound". Para otras DLLs, el nombre incluye el  camino completo. Por ejemplo: "c:windowssystemlzexpand.dll"

La cláusula alias indica que la función tiene otro nombre en la librería dinámica ( DLL ). Esto es útil  cuando el nombre de la función coincide con alguna palabra clave, con alguna variable o constante global, o el nombre de la función DLL, tiene caracteres no reconocidos por el lenguaje de programación. La sentencia declare debe contener asimismo una lista de los parámetros que se pasarán a la función. La mayor parte del trabajo consiste en determinar cuáles serán esos parámetros. Algo muy utilizado dentro de los parámetros son lo que podemos traducir como manejadores ( handles ). Esto es un valor entero único definido por el entorno operativo y utilizado para referirse a objetos tales como formularios, controles, etc. Un handle es un número de identificación. HWnd es un handle para referirse a una ventana, hDC es un handle para referirse al contexto de dispositivo de un objeto ( Device Context ). Cuando una función de una DLL espera recibir como argumento un handle, se debe declarar como ByVal Integer.

        Declare Function IsIconic Lib "User" (ByVal hWnd As Integer) As Integer
        If IsIconic (Form1.hWnd) Then ....

El entorno operativo asigna un handle a cada formulario de una aplicación para posteriormente identificarles.         La propiedad hWnd de un formulario o de un control no gráfico permite acceder a este handle. Por contexto de dispositivo se entiende un conjunto de atributos (color de fondo, tipo de letra, espaciado entre caracteres, posición actual de la pluma, paleta de colores, etc.) que determinan la localización y la apariencia de un objeto. Una aplicación puede modificar estas propiedades a través del hDC del objeto.

Afortunadamente, Microsoft ha pensado en el programador y proporciona una herramienta dentro de  algunos lenguajes de programación de entorno visual como es el API viewer, en Visual Basic versión 4.0.  Con ésta herramienta podemos cargar unos archivos TXT que nos proporcionan las sentencias declare de  gran cantidad de funciones API. Si no poseemos ningún tipo de ayuda respecto a una API específica, es muy Posible que todos nuestros intentos en utilizarla sean inútiles.

Para declarar una función de una librería dinámica, se tiene que escribir en la sección de declaraciones de un formulario o de un módulo de la aplicación en construcción. Una función declarada en un formulario es privada para este formulario, y declarada en un módulo es pública, y por lo tanto puede ser llamada desde cualquier parte de la aplicación.

Si la función no retorna un valor, se declarará como un procedimiento o sub, aunque esta opción no se utiliza casi nunca, pues la mayoría de las APIs retornan un valor, aunque sea una verificación de su realización.

Los argumentos que se pasan a una función pueden ser pasados por valor o por referencia. UN parámetro por valor quiere decir que lo que estamos metiendo dentro de la función es el contenido de la variable, mientras que por referencia se introduce la dirección de memoria donde reside la variable que contiene el valor que queremos pasar.
       
Habitualmente, dentro de nuestro programa trabajamos con variables que se pasan por valor, es decir, no nos interesa la posición de memoria de la variable, sino su contenido. Al trabajar con APIs la cosa cambia. La mayoría de estas funciones están desarrolladas en C, y en este lenguaje se utiliza asiduamente los punteros (direcciones de memoria)

Por defecto, los lenguajes actuales de entorno visual pasa los argumentos por referencia (Utilizando direcciones de 32 bits ).

Para pasar un argumento por valor, se debe de escribir la palabra clave ByVal delante de la declaración del argumento.

Algunas funciones aceptan más de un tipo de datos para un mismo argumento, y esto se indica declarando el argumento como Any.

Declare Function Catch Lib "Kernel" (lpCatchBuf As Any) As Integer

Esta función puede ser llamada con un argumento tipo cadena, de tipo largo, etc.

Algunas Funciones de la API.


API
        - Funciones de direccionamiento de memoria a 32 bits.
                        Recupera el API para aplicaciones que utilizan 32 bits.
        - Funciones de ejecución de aplicaciones.
                        Tiene la función de cargar y ejecutar aplicaciones.
                         ej:   Winhelp
                                Loadmodule
        - Funciones bitmap.
                        Crea y maneja los bitmaps.
                        Createbitmap, crea un bitmap.
                        Getpixel, recupera el color RGB del pixel especificado.
        - Funciones callback o rellamada.
                        Recupera información sobre algo que se está ejecutando, con la                           posibilidad de hacer algún cambio.
                        Abortproc, procesa los trabajos de impresora cancelados.
                        EnumFontFamProc, recupera información sobre las fuentes (tipo de                           letra) disponibles.
        - Funciones de cuadro de diálogo común.
                        Funciones que actúan sobre una caja de diálogo común, cambiando                           su color, texto, etc.
                        Choosecolor, crea una caja de diálogo seleccionando el color.
        - Funciones de comunicación.
                        Funciones que gestionan los dispositivos de comunicaciones.
                        Opencomm, abre un dispositivo de comunicaciones.
        - Funciones de cursor.
                        Gestionan todo lo relacionado con el cursor.
                        Createcursor, crea un cursor con dimensiones especificadas.
        - Funciones DDE (Data Dinamic Exchange ).
                        Gestiona el intercambio de datos dinámico.
                        DdeAccessData, proporciona un acceso a un objeto con memoria                           global.
                        DdeGetdata, copia los datos de un objeto de memoria global a un                           buffer.
        - Funciones de error.
                        Funciones que gestionan los errores de los dispositivos.
                        Debugoutput, envía mensajes al terminal erróneo.
        - Funciones de movimiento y visualización.
                        Isiconic, determina si una ventana está minimizada.
        - Funciones para las propiedades.
                        Informa y modifica el estado de las propiedades.
                       Getprop, devuelve una lista de propiedades de una ventana.
         - Funciones pen.
                        Son las funciones correspondientes al lápiz.
        - Funciones de paleta de colores.
        - Funciones de dibujo y pintura.
        - Grupo de funciones OLE.
                     Funciones que se basan en el manejo de objetos.
                    Olenumobjects, enumera los objetos en un documento.
        - Funciones Toolhelp.
                    Normalmente devuelven información sobre los objetos que hay en                                       memoria.
        - Funciones Drag & Drop
                    Funciones de arratrar y soltar.
                   Tiene información sobre la posición de arrastre de algún elemento, si                      se puede arrastrar, etc.
     - Funciones de controladores instalables.
                    Hacen una gestión de los controladores instalables.
       - Funciones de decodificación LEMPEL-ZIV.
                    Hacen una gestión de los ficheros comprimidos.
       - Funciones para la impresión.
                    Devuelve tamaños de letra, página, etc. y activa o desactiva algunas                       funciones, configura colores, etc.
                    a la hora de imprimir.
        - Funciones SHELL (entorno).
                    Son las funciones que controlan el entorno.
                    FindExecutable: recupera el nombre del ejecutable asociado a un                            fichero especificado.
        - Funciones "Stress"
                    Controla espacio libre y manejadores de ficheros (handles).
                    AllocDiskSpace: crea un fichero del espacio consumido en una                                partición del disco (instalar software).
        - Funciones TrueType
                    Funciones que controlan los fuentes o tipos de letra a utilizar.
                    GetRasterizarCaps: recupera el estado del tipo de letra en un sistema.                       Cuando se hace un cambio de
                    tipo de letra , reestablece el que hay por defecto.
        - Funciones de versión.
                    Función que controla la versión de los ficheros.
                    GetfileVersionInfo: devuelve información sobre un fichero                                       especificado.
        - Funciones GDI.
                    Controla todo lo que se refiere a los gráficos, ya sea tipos de letra,                           manejo de trabajo a la hora de una
                    impresión, prepara la impresora para aceptar datos, etc.
                    StartPage: Prepara un controlador de impresora para aceptar datos.
                    StarDoc: Inicializará un trabajo de impresión.
                    GetRasterizerCaps: recupera el estado del tipo de letra de un sistema.
        - Funciones KERNEL.
                   Lleva a cabo una E/S a ficheros, control de errores,etc.
                    hread: Lee datos de un fichero.
                    hwrite: escribe datos en un fichero.
                    Debugoutput: envía mensajes a un terminal erróneo.
        - Funciones de usuario.
                   Son funciones en las que el usuario realiza alguna acción, como                                activar o desactivar flechas de scrollbar (texto horizontal-vetical),                                       recupera información de mensajes de hardware, etc.
                    GetDriverInfo: recupera datos de un dispositivo instalable.
                    CopyIcon: copia un icono.
                    OpenDriver: abre un dispositivo instalable.

Una de las primeras funciones que vamos a comentar es bastante utilizada.

En muchas ocasiones hemos querido saber qué resolución tiene la pantalla de la pc en el momento que se ejecuta nuestro software. Con ésta información podemos dar un aspecto bastante más profesional a nuestra aplicación si ajustamos el tamaño de nuestros formularios a la resolución de la pantalla. También a través de
la misma API sabemos la cantidad de puntos que nos da la impresora, con lo que podemos ajustar nuestros informes independientemente de la impresora seleccionada. Esta función la tenemos dentro de la librería GDI,
y se denomina GetDeviceCaps. Dependiendo del valor del índice introducido, así nos da la información sobre la cantidad de puntos horizontales de la pantalla, cantidad de puntos verticales de la pantalla, puntos por pulgada horizontalmente en la impresora y puntos por pulgada verticalmente en la impresora.

Código
Declare Function GetDeviceCaps Lib "GDI" ( ByVal HDC As_ Integer, Byval nIndex As Integer) As Integer
Global Const HorRes = 8 ' resolución horizontal en pixels
Global Const VerRes = 10 ' resolución vertical en pixels
Global Const PPPX = 88 ' pixels por pulgada en X
Global Const PPPY = 90 ' pixels por pulgada en Y
Private Sub Command1_click()
    p1 = GetDeviceCaps ( HDC, HorRes )
    p2 = GetDeviceCaps ( HDC, VerRes )
    i1 = GetDeviceCaps ( Printer, HDC, PPPX )
    i2 = GetDeviceCaps ( Printer, HDC, PPPY )
    Label1.Caption = "Pantalla: " & p1 & " x" & p2
    Label2.Caption = "Impresora: " & i1 & " x " & i2
End Sub


En muchas ocasiones necesitamos conocer dónde esta el directorio de Windows y dónde reside el directorio System del mismo. Es muy lógico suponer que todas las instalaciones están en el directorio C:Windows.

Puede ser que se ejecute desde una red, o que el usuario haya cambiado el directorio por omisión. En cualquiera de estos casos no podemos referirnos directamente a estos directorios, sino que debemos conocerlos dinámicamente cuando ejecutamos la aplicación.

Para ello utilizamos dos APIs de la librería Kernel, la primera nos devuelve el directorio de Windows
(GetWindowsDirectory ), mientras que la segunda el directorio de System ( GetSystemDirectory ).

Para hacer funcionar esta API debemos inicializar la variable que nos devuelve la información, con 255 caracteres rellenos con el valor ASCII 0. Si la cadena estuviese vacía, no funcionaría, y su comportamiento sería impredecible.

Código
Declare Function GetWindowsDirectory Lib "Kernel " (ByVal_ lpBuffer As String, ByVal nSize As Integer
Declare Function GetSystemDirectory Lib "Kernel" (ByVal lpBuffer_ As String, ByVal nSize As Integer
Private Sub Command2_Click ()
    Dim Camino As String
    Camino = String( 255, 0 )
    w = GetWindowsDirectory ( Camino, Len(camino))
    Label3.Caption = Camino
    w = GetSystemDirectory ( Camino, Len(Camino))
    Label4.Caption = Camino
End Sub



Algunas Funciones Interesantes y una breve descripcion DDE cada una:


DDE
GetUserName (Devuelve en nombre del usuario)
GetComputerName (Devuelve en nombre del computador)
GetDiskFreeSpace (Devuelve información sobre el disco duro)
GetDiskFreeSpaceEx (Devuelve la capacidad de un disco mayor de 2Mb.)
GetVolumeInformation (Nombre del Disco, tipo de formato y numero de disco)
GetLogicalDriveStrings (Devuelve las unidades disponibles en un ordenador)
GetLocalTime (Devuelve la fecha y hora del ordenador)
GetCursorPos (Devuelve la posición del cursor en la pantalla)
GetDriveType (Devuelve el tipo de Unidad)
SetWindowPos (Formulario Siempre Visible)
GlobalMemoryStatus (Información sobre la memoria fisica disponible)
ShellExecute (Ejecutar)
GetVersionEx (Devuelve la versión del Windows)
SystemParametersInfo (Cambia el fondo de pantalla del Windows)
SHFileOperation (Enviar un archivo a la papelera de reciclaje)
GetWindowsDirectory (Mustra la ruta del Windows)
GetSystemDirectory (Mustra la ruta del directorio System de Windows)
sndPlaySound (Ejecutar sonidos .WAV)
FindExecutable (Busca el archivo ejecutable asociado a un archivo, y muestra el icono)
GetKeyboardStateByString - SetKeyboardStateByString (Seleccionar y Deseleccionar el Bloque Numerico del teclado)
FindWindow (Indica si una aplicación determinada esta en ejecución)
SystemParametersInfo (Activa/Desactiva las teclas de Escape - CTRL+ALT+SUB - ALT+TAB - CRTL+ESC)
GetSysColor (Devuelve los colores del Windows)
GetACP (Determina la página de código ANSI vigente)
SetWindowPos (Esconder y mostrar la barra de tareas del Windows)
ExitWindowsEx (Apaga o Reinicia el Windows 95/98)
GetSystemInfo (Información sobre el Hardware)
SystemParametersInfo (Devuelve y establece parámetros del sistema de Windows)




















No hay comentarios:

Publicar un comentario