Manual de Programación


Este manual contiene las reglas para el desarrollo de sistemas dentro del DDS basados en la plataforma MS Windows / MS Visual Basic 5.0, debe seguirse hasta donde sea posible tratando de evitar las excepciones; no es completamente rígido puesto que es susceptible de cambiar y de crecer, pero en cualquier caso deben justificarse y plantearse concretamente las alteraciones.

Estructura a nivel de módulos


Todo sistema debe dividirse en módulos que deben estructurarse basándose en reglas propuestas por éste apartado; pero dependerá de cada sistema específico el número y tipo de ellos. A pesar de ello se describe a continuación la plantilla mínima a cubrir.

Partes de un sistema

Puede considerarse que toda una aplicación que esta formada por un conjunto de elementos y que generalmente se asocian con módulos, si se trata de aplicaciones que acceden a Bases de Datos, entonces el número de ellos aumenta para proporcionar múltiples facilidades al usuario, en nuestro caso definiremos los elementos mínimos que tendrán nuestras aplicaciones para dar como resultado un producto útil y poderoso.

  • Interfaz gráfica
  • Seguridad de la información
  • Control de acceso a usuarios
  • Información del sistema

La interfaz gráfica

Las partes de la interfaz gráfica están definidas mas adelante en Partes de la interfaz gráfica

Seguridad de la información

Esto implica varios procesos y elementos del sistema:

  • Herramientas de respaldo y restauración de información
  • Registro de datos de control de información (campos de control)
  • Uso de tablas históricas para los movimientos de información

Control de acceso a usuarios

  • Manejo de sesiones de usuarios en el sistema
  • Control de acceso a usuarios
  • Administración de privilegios y tipos de usuarios
  • Registro de los movimientos de cada usuarios

Información del Sistema

Datos legales y de autoría del sistema donde se especifique:

  • Nombre del sistema
  • Empresa que desarrolla
  • Versión (Opcionalmente SubVersión y revisión)
  • Condiciones legales de uso

Módulos

ModLib.Bas Descripción: Contiene la biblioteca de funciones estándar para los sistemas, conformada por 40 funciones aproximadamente y que se describe a detalle en el apartado "Biblioteca de Funciones y Subrutinas
  Restricciones: Ningún programador está autorizado a modificar este módulo. En caso de requerir una adición y/o modificación, deberá presentarse una propuesta justificada al equipo líder quien evaluará la propuesta y en su caso incluirá o modificará la función requerida.
  Dependencias: FrmLib.Frm Forma de Menús desplegables
COMCTL32.OCX Microsoft Common Controls 5.0
MSFLXGRD.OCX Microsoft FexGrid Control 5.0
ModDef.Bas Descripción: Contiene las definiciones de:
– Estructuras de datos y
– Constantes globales
– Mensajes
  Restricciones: Se pueden agregar todas las definiciones necesarias por el sistema, pero no es posible eliminar las definiciones iniciales del módulo
  Dependencias: Ninguna
ModSis.Bas Descripción: Contiene:
– Todas las funciones y subrutinas del sistema
– Funciones y subrutinas de inicialización y de ambiente
– El conjunto de subrutinas de las opciones del menu
– La definición de las variables globales
– Instancias de las clases
– Instancias de las estructuras de datos del sistema
– La subrutina Main que es el punto de arranque a la aplicación
  Restricciones: Se pueden agregar todas las definiciones de variables e instancias globales necesarias por el sistema, pero no es posible eliminar las definiciones iniciales del módulo.
  Dependencias: FrmCatSel.Frm Forma de Selección de Catálogos
FrmLog.Frm Forma de Inicio de sesión
FrmIni.Frm Forma de inicio y presentación
FrmAce.Frm Forma de acerca de...
ModDef.Bas Módulo de definiciones
ModLib.Bas Módulo de la biblioteca estándar
ClaMsg.Cla Clase Mensaje
ClaMsg.Cla Descripción: La definición de la clase que atiende el manejo de mensajes entre formas.
  Restricciones: Ningún programador está autorizado a modificar este módulo.
  Dependencias: Ninguna
MdiApl.Frm Descripción: Contiene la ventana principal del sistema. Es una forma MDI que contiene:
– Menú estandar para la mayoría de las aplicaciones
– Barra de herramientas
– Barra de mensajes
–El código necesario para llamar a las subrutinas que manejan las opciones del menú y barra de herramientas
  Restricciones: Ninguna.
  Dependencias: ModSis.Bas Módulo de Funciones y Subrutinas del sistema
ModDef.Bas Módulo de Definiciones
ClaMsg.Cla Clase Mensaje
Bsens.Ocx Botón sensible al mouse
FrmAce.Frm Descripción: Información del sistema, créditos, condiciones legales de uso e información de ambiente
  Restricciones: Ningún programador está autorizado a modificar este módulo.
  Dependencias: ModSis.Bas Módulo de Funciones y Subrutinas del sistema
ModDef.Bas Módulo de Definiciones
ClaMsg.Cla Clase Mensaje
FrmIni.Frm Descripción: Muestra información del sistema, permisos de uso legal, logotipo del departamento y mensajes de la carga del sistema.
  Restricciones: Ningún programador está autorizado a modificar este módulo.
  Dependencias: ModSis.Bas Módulo de Funciones y Subrutinas del sistema
ModLib.Bas Módulo de la biblioteca estándar
ModDef.Bas Módulo de Definiciones
ClaMsg.Cla Clase Mensaje
FrmLib.Frm Descripción: Contiene el menú usado por la función gF_MnuOpcObt()
  Restricciones: Ningún programador está autorizado a modificar este módulo.
  Dependencias: ModSis.Bas Módulo de Funciones y Subrutinas del sistema
ModLib.Bas Módulo de la biblioteca estándar
ModDef.Bas Módulo de Definiciones
ClaMsg.Cla Clase Mensaje
FrmCatSel.Frm Descripción: Muestra el contenido de una tabla de BD de acuerdo a un criterio de selección llamada desde gF_CatSel()
  Restricciones: Ningún programador está autorizado a modificar este módulo.
  Dependencias ModSis.Bas Módulo de Funciones y Subrutinas del sistema
ModLib.Bas Módulo de la biblioteca estándar
ModDef.Bas Módulo de Definiciones
ClaMsg.Cla Clase Mensaje

Estructura interna de los Módulos

Formas

La estructura lógica de toda forma se da de acuerdo al siguiente esquema:

(General) / (Declaraciones)

  • Establecer opciones del ambiente
  • Declarar variables locales (Publicas y Privadas)
    • Mensaje local
    • Bandera de modificación
    • Bandera de tipo de acceso a datos (Lectura / Escritura)
    • Clave asignada a la forma
    • Tipo de forma

(General) / Ejecutar

  • Public Sub Ejecutar(pclMsg As ClaMsg)
  • ' Hacer una copia local del mensaje
  • ' Seleccionar el mensaje
  • ' procesar cada caso
  • End Sub

    Form_Load

  • Private Sub Form_Load()
  • ‘ Agregar la forma a la colección global de Formas MDICHild
  • ‘ (Solo para las Ventanas con propiedad MDIChild = True)
  • End Sub

Form_QueryUnload

  • Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
  • ‘ Si la bandera de modificación esta activada...
  • ‘ preguntar al usuario si realmente desea cerrar sin guardar cambios
  • End Sub

Form_Unload

  • Private Sub Form_Unload(Cancel As Integer)
  • ‘ Eliminar la forma de la colección global de Formas MDIChild
  • ‘ (Solo para las Ventanas con propiedad MDIChild = True)
  • End Sub

Módulos de Código

No debe ser necesario (en la mayoría de los casos) la adición de nuevos módulos de código, pero si así fuera, se recomienda una estructura integrada, es decir, que declare las variables globales que necesite, así como sus propias constantes, de igual forma, podrá hacer uso de variables, constantes y funciones de otros módulos y formas pero debe tratar de mantener independencia de los controles, instancias y objetos de la aplicación.

Para tratar de aplicar estas reglas se proponen las siguientes recomendaciones:

  • Construir funciones que actúen como átomos, es decir, con tareas muy específicas y sencillas
  • Definir funciones abiertas para que puedan ser utilizadas no solo por la entidad para la que fue diseñada
  • Usar parámetros opcionales en donde sea posible, esto incrementa el grado de apertura de la función
  • Usar el modo de paso de parámetros por valor (donde sea posible) para poder usar funciones con parámetros de tipo inmediato
  • Evitar la implementación de funciones que modifican un parámetro (paso por referencia), en su lugar hacer funciones que regresen el mismo tipo de valor que el parámetro recibido
  • Pasar controles y/o formas como parámetros y no sus índices o propiedades, esto permite reutilizar funciones, agrega poder a la función e independiza el código de la aplicación
  • Hacer uso intensivo de comentarios, y donde sea posible usarlos estructuralmente
  • Subdividir funciones de gran complejidad hasta que cada parte alcance el grado de átomo
  • Independizar al máximo el código de las funciones de las variables globales y de entorno

Código fuente


Nomenclatura

Si lo que se pretende es estandarizar el desarrollo de aplicaciones, se debe empezar por los identificadores de las entidades del sistema, que van desde la variable que se usa como contador hasta la Base de Datos principal.

La estrategia a seguir consiste en la implementación de 3 tendencias usadas en la actualidad.

  • La primera es la nomenclatura basado en la notación Húngara, basada en el uso de prefijos de identificación. Esta notación es usada ampliamente entre los desarrolladores de aplicaciones comerciales y en una gran cantidad de bibliografía de referencia.
  • Por otra parte hacemos uso de la Notación Polaca, la cual establece el uso de identificadores de 3 letras y que permite abreviar conjuntos de identificadores.
  • Por último aprovecharemos la forma como se desenvuelve la Programación Orientada a Objetos al describir una entidad desde la parte más general hasta la más específica.

Variables e Instancias

Asignación de un identificador para una variable o instancia

Sintaxis

[cobertura] [arreglo] {tipo} Id_General [Id_Específico] [Id_Específico]

La sintaxis del identificador de variables e instancias tiene las siguientes partes:

Parte Descripción
cobertura Visibilidad o cobertura de la variable con una letra en minúscula (g: Global; si es local no se indica)
arreglo Indica si es un arreglo con la letra 'a' en minúscula (a: Arreglo)
tipo Prefijo que indica el tipo de dato de acuerdo a la tabla Tipos de Datos
Id_General Identificador general (principal) de la variable compuesto por 3 letras (Aaa)
Id_Específico Identificador secundario o específico compuesto por 3 letras (Aaa)
Tipos de Datos
Prefijo Tipo
b Boolean
i Integer
l Long
sg Single
d Double
c Currency
d Date
o Object
s String
  Variant
t Type(Definido por el usuario)
cl Clase
p Parámetro (caso especial para funciones y subrutinas)
Objetos
Prefijo Objeto
db Database
rs RecordSet
ws WorkSpace
Frm Forma
Mdi FormaMDI
ct Control

Los identificadores se componen con 3 letras, la primera de las cuales es mayúscula y siguen una estructura similar a la de la Programación Orientada a Objetos:

Objeto.Subobjeto.Propiedad ObjSubPro

Es ampliamante recomendado que se siga esta notación que, aunque es dificil al principio, a mediano plazo representa una grán ayuda en la localización de identificadores.

Una forma rápida de comprobar si un identificador esta bien asignado es descomponerlopara integrar el objeto y sus propiedades como en la POO, Ejemplo:

UsuCve Usuario.Clave PolEncGua Poliza.Encabezado.Guardar
UsuNomVld Usuario.Nombre.Validar FrmDetAct Forma.Detalle.Actualizar

Por último se presentan algunos ejemplos que aplican todas las partes de un identificador y si significado

gaFrmTmp Arreglo global de formas denominado Tmp
sArcNom Variable local de tipo string para: Archivo.Nombre
piArcNum Parámetro de tipo Integer para: Archivo.Numero
aLstNom Arreglo de ListBox para: Nombre

Controles y Formas

Asignación de un identificador para una Función o Subrutina

Sintaxis

{Tipo} Id_General [Id_Específico] [Id_Específico]...

La sintaxis del identificador de Función y Subrutina tiene las siguientes partes:

Parte Descripción
tipo Tipo de control o forma como se especifica en la sección Tipos de Controles
Id_General Identificador general (principal) de la variable compuesto por 3 letras ('Aaa' )
Id_Específico Identificador secundario o específico compuesto por 3 letras ( 'Aaa' )
Id_Específico Identificador terciario o específico compuesto por 3 letras ( 'Aaa' )
Tipos de Controles
Icono Abreviatura Nombre Icono Abreviatura Nombre

Arc DriveList

Lst ListBox

Btn Command / ButtonSens

LsV ListView

Clp PictureClip

Ole Ole

Cmb ComboBox

Opc OptionButton

Chk CheckBox

Pic PictureBox

Dat DataControl

Prg ProgressBar

Dir DirList

Scr ScrollBar

Dlg CommonDialog

Shp Shape

Drv DriveList

Sld Slider

Fra Frame

Spn UpDown

Grd MSFlexGrid

Stb StatusBar

Img Image

Tab SSTab / TabStrip

ImgLst ImageList

Tmr Timer

Lbl Label

Tlb ToolBar

Lin Line

Tre TreeView
     

Txt TextBox
     

Rpt Crystal Report

Funciones y Procedimientos

Asignación de un identificador para una Función o Subrutina

Sintaxis

[cobertura] { F | M | S } { _ } Id_General [Id_Específico] [Id_Específico]...

La sintaxis del identificador de Función y Subrutina tiene las siguientes partes:

Parte Descripción
tipo Visibilidad o cobertura de la variable (g: Global, l: Local)
F, M, S Indica el tipo de función (F: Function, S: Sub, M: Sub para opciones de menú)
_ Subguión ( _ )
Id_General Identificador general (principal) de la variable compueston por 3 letras ( 'Aaa' ) (Casi siempre es un sustantivo)
Id_Específico Identificador secundario o específico compuesto por 3 letras ( 'Aaa' ) (Casi siempre es un sustantivo)
Id_Específico Identificador terciario o específico compuesto por 3 letras ( 'Aaa' ) (Casi siempre es un verbo)

Los identificadores se componen con 3 letras, la primera de las cuales es mayúscula y siguen una estructura similar a la de la Programación Orientada a Objetos:

Objeto.Subobjeto.Propiedad ObjSubPro

Una forma rápida de comprobar si un identificador esta bien asignado es descomponerlo para integrar el objeto y sus propiedades como en la POO, Ejemplo:

UsuCveObt Usuario.Clave.Obtener PolEncGua Poliza.Encabezado.Guardar
UsuNomVld Usuario.Nombre.Validar FrmDetAct Forma.Detalle.Actualizar

Por último se presentan algunos ejemplos que aplican todas las partes de un identificador y si significado

gM_ArcAbr Opción del menú (Sub) asociada a Archivo\Abrir
lS_FrmIni Subrutina local para inicializar una forma (Forma.Inicializar)
lF_FrmVld Función local para validar una forma (Forma.Validar)
gF_StrElmObt Función global: String.Elemento.Obtener

Constantes

Asignación de identificadores a constantes

Sintaxis

{GRUPO } { _ } Id_General [Id_Específico] [Id_Específico]...

La sintaxis del identificador de Constantes tiene las siguientes partes:

Parte Descripción
GRUPO Determina el uso o grupo al que corresponde la constante (de 2 a 4 caracteres en MAYÚSCULAS)
_ Subguión ( _ )
Id_General Identificador primario de la constante (puede ser un verbo o un sustantivo con la primera letra MAYÚSCULA )
Id_Específico Identificador secundario o complementario (puede ser un sustantivo o verbo con la primera letra MAYÚSCULA )

Los identificadores no tienen límite en el número de letras porque pueden contener palabras completas, la primera de las cuales es mayúscula y no es necesario que cumplan la notación de objetos:

Tipo = Poliza TPO_Poliza

Una forma rápida de comprobar si un identificador esta bien asignado es descomponerlo en grupo e identificador como se muestro (GRUPO = Identificador)

EDO_Nuevo ESTADO = Nuevo MSG_MostrarAlFrente MENSAJE = Mostrar al Frente
USU_Adminisrador USUARIO = Administrador OPC_ArcAbr OPCION = Archivo.Abrir

Por último se presentan algunos ejemplos que aplican todas las partes de un identificador y si significado

DOC_A Documento: A
EDO_Modificado Estado: Modificado
TPO_Presupuestado Tipo: Presupuestado
OPC_VerCatUsu Opción: Ver\Catálogo\Usuarios

Uso de comentarios

La estandarización en el estilo de programación incluye la forma en que se usarán los comentarios, y aunque no es tan rigurosa como la nomenclatura de variables si sugiere algunos estilos:

Líneas de código

El comentario se hace al final de la línea tratando de conservar un márgen uniforme al menos en toda la función (lo ideal es que fuera el mismo márgen en todas las funciones y declaraciones)

i = i + 1 ' Incrementar contador
TxtNom.Text = sUsuNom ' Cargar Nombre del usuario
rsCat.Close ' Cerrar el RecordSet
' Todo RecordSet abierto en cada función
' debe cerrarse antes de finalizar la función

El texto descriptivo del comentario se hará iniciando (casi siempre) con un verbo en tiempo infinitivo seguido con una breve descripción de la línea de código, si se desea es posible hacer anotaciones referentes a la misma línea usando más renglones pero siempre conservando el mismo márgen e insertando líneas vacías de código

Bloques de código

Cuando se trata de bloques de código en los que no es práctico el uso de comentarios individuales a nivel de línea de código se pueden agrupar con comentarios indicadores inicial y final que indican la cobertura del texto descriptivo agrupando el bloque de código:

' Cargar datos de la Base de Datos >  
Do Until rsCat.EOF  
__LstCat.AddItem rsCat("NomEntUsu") ' Cargar Nombre
__LstCat.ItemData(LstCat.NewIndex) = rsCat("CveEntUsu") ' Cargar Clave
__rsCat.MoveNext ' Avanzar registro
Loop  
'< Cargar datos de la Base de Datos  

Observese que se han usado para este ejemplo dos tipos de comentarios (de Bloques y de Línea), de igual forma se pueden anidar comentarios de Bloque siempre y cuando estén alineados con la identación del código al que corresponden.

Alternativamente se pueden usar comentarios de bloque sin indicadores de inicio y fin pero para éste caso las líneas dentro del código deben estar necesariamente juntas, es decir sin líneas de código vacías, de este forma sabremos que el fin del bloque es un salto de línea adicional.

' Definición de variables para usuarios----
Dim asUsuNom (1 To 10) As String
Dim iUsuNum As Integer
Dim lUsuCve As Long

' Definición de Mensajes Globales ---------  
Global Const MSG_Nuevo% = 1 ' Nuevo elemento
Global Const MSG_MostrarNormal% = 2 ' Abrir Forma MDI Child o Normal
Global Const MSG_MostrarAlFrente% = 3 ' Abrir una Forma de tipo Siempre-al-frente

Como puede observarse es posible mezclar diferentes formatos para cometarios sin romper las reglas de cada uno. Los comentarios de bloque-no-separado no contienen verbos al inicio, a diferencia de los anteriores.

Estructuras de control

A pesar de que se pudiera utilizar la notación de comentarios de Bloque, la notación de cometarios para Estructuras de control puede ser más descriptiva, por el momento solo esta disponible para If ... Then, pero mientras se puede seguir haciendo uso de la de Bloques.

If Not rsCat.EOF Then. ' Si no es fin de archivo...
__TxtNom.Text = rsCat("NomEntUsu") ' Cargar nombre de usuario
ElseIf rsCat.BOF Then ' Si es el primer registro...
__TxtNom.Text = "[ No Disponible]" ' Enviar mensaje
End If ' Fin de Bloque

Como puede observarse es posible mezclar diferentes formatos para cometarios sin romper las reglas de cada uno. Los comentarios para If ... Then inician con ' Si seguido por la condición descrita en lenguaje natural y finalizada por los 3 puntos ...

Comentarios aislados

Cuando es necesario hacer observaciones o anotaciones dentro del código fuente, éstos se harán identados al nivél del bloque al que corresponden sin ninguna restricción especial, eso si, tratando que cada línea de comentario alcance en una sola pantalla sin necesidad de hacer scroll

' Todas las variables deben declararse en la sección correspondiente,
' para ayudar se debe incluir la directiva:
' Option Explicit
' En la sección [General]\Declaraciones

Identación

Para aumentar la legibilidad y claridad del código fuente se deben seguir las reglas de identación propuestas de acuerdo a cada sección del código.

Declaraciones

Todas las declaraciones (variables, constantes, instancias, ...) y las directivas (Option ...) se hacen al márgen izquierdo sin espacios intermedios.

Para el caso de las variables se deberán agrupar en una sola línea de declaraciones de variablesque se refieran al mismo contexto, de forma que cada línea funcionartá como un grupo.

Option Explicit
Dim
lUsuCve As Long, sUsuNom As String
Dim
dFec As Double, sFecExt As String
Dim
i As Integer, j As Integer, iItmInd As Integer

' Opciones del Sistema------------------------
Constant
OPC_Nvo% = 1
Constant
OPC_Gua% = 2
Constant
OPC_Imp% = 3

Constant
MSG_Abrir% = 1
Constant MSG_Cerrar% = 2
Constant MSG_Guardar% = 3

' Datos del usuario
' Manejo de Fechas
' Indices


' Nuevo
' Guardar
' Imprimir

' Mensaje: Abrir
' Mensaje: Cerrar
' Mensaje: Guardar

Es posible dejar espacios intermedios entre bloques para agrupar declaraciones, de igual forma se puede hacer uso de comentarios de acuerdo a la notación descrita en Uso de Comentarios.

Estructuras de Control

La línea de código con que da inicio una estructura de control debe estar alineada a la identación actual, si es la primera declaración de la función entonces deberá tener 2 espacios de separación del márgen izquierdo al igual que la línea que marca su fin.

Dentro de la cobertura de la estructura el márgen activo aumenta en 2 espacios de forma que si existen otras estructuras dentro del bloque aplicarán recursivamente la regla de identación.

Private Sub BtnAce_Click ()
Dim sArcNom As string, iArcNum As Integer
Dim i As Integer
Dim sMsg As String

--Screen.MosePointer = 11
__sArcNom = App.Path & "Modelo.Ini"
--iArcNum = FreeFile
--On Local Error Resume Next
--Open ..
--If Err > 0 Then
__--MsgBox sMsg
____Screen.MosePointer = 0
____Exit Sub
__End If
__Screen.MosePointer = 0
End Sub




' Separador
' Cursor: Reloj de Arena






' Cursor Normal
' Abandonar proceso

' Cursor Normal

Pueden utilizarse saltos de línea para indicar con mayor claridad la separación entre las declaraciones y el código de instrucciones, pero es opcional.

Para el caso de estructuras compuestas, se siguen las mismas reglas (Incluso para el Select Case)

Select Case clMsgLoc.Mensaje
--Case MSG_MostrarModal
__--lS_FrmIni
____If Not Me.Visible Then
____--Me.Show 1
____End If
__Case MSG_MostrarNormal
__--lS_FrmIni
____If Not Me.Visible Then Me.Show
__Case MSG_Cerrar
__--Unload Me
End Select

Interfase gráfica


Partes de una interfaz gráfica

  • Ventana Principal
  • Barra de herramientas
  • Barra de mensajes al usuario
  • Menú de persianas desplegables
  • Apertura de documentos
  • Presentación del sistema
  • Información del sistema
  • Ventana(s) de trabajo
  • Catálogos
  • Ventana para el acceso al sistema
  • Selección de elementos desde tablas de BD
  • Ayuda en línea
  • Soporte para teclado en todas las funciones
  • Controles estandarizados

Estructura de menús

Colores y fuentes tipográficas

Uso de gráficos

Leyendas

Consideraciones especiales

Plantillas modelo


Rutinas modelo

Aqui se agrupa un conjunto de reglas aplicables a partes despecíficas del sistema, por el momento no se han agrupado bajo algún criterio, pero conforme el número de ellas crezca las agruparemos como debe ser.

 

Captura de Fechas

Se asume que se tiene un TextBox para la captura de fechas con Name = TxtFec

Private Sub TxtFec_GotFocus ()
Dim dFec As Double
__dFec = Val(TxtFec.Tag)

__TxtFec.Text = Format(dFec, "Short Date")
__gS_TxtSel TxtFec
End Sub

' Contenedor temporal de Fecha
' Obtener la fecha contenida en el Tag
' contenida en forma de Double
' Obtener la fecha en formato corto
' Seleccionar el contenido del TextBox
Private Sub TxtFec_LostFocus()
Dim dFec As Double
__dFec = gF_StrFecVld(TxtFec.Text)

__If dFec = 0 Then
____dFec = Now
__End If
__TxtFec.Tag = dFec
__TxtFec.Text = gF_FecExt(Format(dFec, "Short Date"))
End Sub

' Contenedor temporal para la Fecha
' Obtener la Fecha capturada
' en formato Double
' Si no es es válida...
' Tomar la Fecha actual

' Actualizar la Fecha en el Tag
' Mostrar la Fecha Extendida

Adicionalmente se recomienda inicializar el campo para que al mostrarse la forma por primera vez tenga un valor default (Fecha Actual)

Private Sub lS_FrmIni()
' Declaraciones---------------------------------
.....
__
TxtFec_LostFocus
.....
End Sub



' Llamar al evento LostFocus

 

Captura de Campos de Catálogos

Este tipo de captura se aplica sobre controles TextBox que entán ligados a un catálogo (Ej.: Nombre de Usuario, Centro de costo, ...) y se define de acuardo al siguiente algoritmo:

- Inicializar el control con Tag = "0" y Text = "" (Pude haber excepciones)

- Al obtener el foco seleccionar todo el texto

- Si se presiona F3 o hay un DobleClick llamar a la función para seleccionar desde catálogo y...

- Asignar la clave el Tag y el contenido en Text

- Si la selección fue inválida o cancelada abandonar el proceso (Evento)

-Al perder el foco tratar de obtener una clave numérica de la propiedad Text

- Si hay una clave válida y es diferente de la que tiene Tag entonces

- Actualizar Text y Tag de acuerdo a la nueva clave

- En otro caso

- Volver a obtener el contenido de acuerdo a la clave contenida en Tag

- Si la clave en Tag es inválida dejar Text = "" y Tag = "0"

Los siguientes ejemplos de código corresponden al control TxtCec para el catálogo TblCenCos

Private Sub lS_FrmIni()
' Declaraciones---------------------------------
.....
__
TxtCec.Tag = "0"
__TxtCec.Text = ""
.....
End Sub



' Inicializar la clave
' Limpiar contenido
Private Sub TxtCec_GotFocus ()
__gS_TxtSel TxtCec
End Sub

' Seleccionar el contenido
Private Sub TxtFec_LostFocus()

__gS_CmpCveVld "TblCenCos",TxtCec,"CveCenCos",...
__"NomCenCos"
End Sub


' Llamar a la función...
' que hace el proceso
Private Sub TxtCec_KeyUp(KeyCode As Integer,...
__Shift As Integer)

__If KeyCode <> vbKeyF3 Then Exit Sub
__TxtCec_DblClick
End Sub



' Si no es F3 abandonar el evento
' Llamar al evento DobleClick
Private Sub TxtCec_DblClick()
__Dim sCenCos As String, bDbsCer As Boolean

__Screen.MousePointer = 11

__' Abrir la Base de Datos --------------------
__If Not gF_DbsAbr() Then
____MsgBox Aplicacion.ERR_AbrirDB, ...
____vbExclamation,_App.Title
____Screen.MousePointer = 0
____Exit Sub
__End If

__' Construir Query----------------------------
__sCenCos = "SELECT CveCenCos, NomCenCos "
__sCenCos = sCenCos & "FROM TblCenCos"

__' Llama a la forma de catalogos---------------
__sCenCos = gF_CatSel(sCenCos, TxtCveCenCos, ...
__Aplicacion.DB_DataBase, TxtCveCenCos)
__If sCenCos <> "" Then
____TxtCec.Text = gF_StrPrmObt(sCenCos, "NomCenCos")
____TxtCec.Tag = gF_StrPrmObt(sCenCos, "CveCenCos")
__End If

__' Cerrar Base de Datos ----------------------
__bDbsCer = gF_DbsCer()
__Screen.MousePointer = 0
End Sub



' Cursor: Reloj de Arena





' Cursor: Normal
' Abandonar Proceso















' Cerrar la Base de Datos
' Cursor: Normal

Acceso a Base de Datos

INTRODUCCIÓN: Un DBMS (Data Base Manger System) maneja el concepto de licencias de uso/acceso, cada una se usa cuando un cliente abre una Base de Datos, eso implica que se mantiene abierta desde el arranque de la aplicación hasta que termina, incluso si no la esta usando. Además si se mantiene abierta es muy probable que falle en cualquier momento debido a la conexión física, caida del DBMS, caida del servidor, fallo en la energía eléctrica, etc.

Las aplicaciones deben estar preparadas para soportar este tipo de fallas y por eso se diseño el siguiente algoritmo para acceder a la Base de Datos:

- Inicio de Función / Evento

- Abrir Base de Datos

- Si Fallo en la apertura entonces abandonar el proceso (Evento)

- Construir cadena de comandos para el DBMS

- Ejecutar comando [ Opcionalmente sería obtener RecordSet / Cursor ]

- [ Acceder a los datos ]

- [ Cerrar RecordSet/Cursor]

- Cerrar la Base de Datos

- Fin de Función / Evento

Puede observarse que todo el proceso ocurre dentro de una sola función, y debe ser así para asegurar el cierre de RecordSet's/Cursores y de la Base de Datos, además la validación en cada intento de apertura previene el uso de objetos no inicializados. A continuación se muestra el código modelo usado en una función de carga de datos:

Private Sub lS_FrmCrg()
__Dim bDbsCer As Boolean, rsCat As RecordSet
__Dim sCenCos As String

__Screen.MousePointer = 11 'Cursor: Reloj de Arena

__' Abrir la Base de Datos ------------------
__If Not gF_DbsAbr() Then
____MsgBox Aplicacion.ERR_AbrirDB, vbExclamation,_App.Title
____Screen.MousePointer = 0 'Cursor: Normal
____Exit Sub
__End If

__' Construir Query--------------------------
__sCenCos = "SELECT CveCenCos, NomCenCos "
__sCenCos = sCenCos & "FROM TblCenCos"

__' Ejecutar Query---------------------------
__Set rsCat = Aplicacion.DB_DataBase.OpenRecordSet(sCenCos, dbOpenForwardOnly)

__' Cargar Datos-----------------------------
__If Not rsCat.EOF Then
____TxtCec.Text = gF_StrNomVld(rsCat("NomCenCos") & "", TxtCec.MaxLenght)
____TxtCec.Tag = rsCat("CveCenCos") & ""
__End If

__' Cerrar Base de Datos --------------------
__rsCat.Close
__bDbsCer = gF_DbsCer()
__Screen.MousePointer = 0 'Cursor: Normal
End Sub

gF_DbsAbr trata de abrir la Base de Datos con los parámetros contenidos en Aplicacion.Parametros, si el acceso es exitoso entonces se asume que la referencia a la base de datos queda en el objeto Aplicacion.DB_DataBase que es usado para abrir posteriormente el RecordSet; la función gF_DbsCer no necestia parámetros porque asume la misma instancia como referencia a la Base de Datos.

La lectura de datos de la DB se hace a través de funciones de validación de la Biblioteca de Funciones y se concatena una cadena vacía ("") para prevenir la lectura de datos NULL y por lo tanto el error: Invalid Use of NULL

Para una referencia más completa de funciones de validarión, refierase a la Biblioteca de Funciones.

Abrir una Ventana

Este proceso es de los más comunes, pero de acuerdo al nuevo esquema basado en mensajes se recomienda ver primero la sección Uso de Mensajes, el algoritmo es el siguiente:

- Crear una nueva instancia de Mensajes

- Enviar Mensaje deseado a la forma deseada [ Enviar parámetros opcionales ]

- [ Procesar valores de retorno ]

Sub gM_ArcAbr()
__Dim clMsg As New ClaMsg
__
__
clMsg.EnviarFrm FrmAbr, MSG_MostrarModal

__lCve = clMsg.Clave
__iTpo = gF_StrPrmObt(clMsg.Parametros,"TIPO")
End Sub




' Enviar mensaje
' (Ejecución Sincrona)

Hay 2 tipos de lanzamiento de ventanas:

NORMAL: Son aquellas ventanas MDI Child, y ventanas que se activan al hacer click sobre ellas y que pueden perder el foco al activar alguna otra.

MODALES: Son las que se muestran activas frente a todas las demás y que no pueden perder el foco hasta que sean cerradas o descargadas.

Estos conceptos son importantes porque al abrir la ventana pueden suceder 2 cosas dependiendo del tipo.

- Si es una ventana modal hará una pausa justo en el evío de mensajes hasta que se cierre o descargue, después es posible acceder a los valores de retorno contenidos en la misma instancia de mensaje. (Ejecución Sincrona)

- Se es una ventana Normal no hará pausa y continuará la ejecución en paralelo de los dos procesos, por lo tanto no se puede asumir que se obtendrán valores de retorno. (Ejecución Asíncrona)

Sub gM_EdiBus()
__Dim clMsg As New ClaMsg
__
__
clMsg.EnviarFrm FrmBus, MSG_MostrarNormal
End Sub



' Enviar mensaje
' (Ejecución Asíncrona)

Mensajes

Los mensajes son uno de los soportes más fuertes para la integración de módulos y comunicación entre ventanas de un sistema. Los mensajes aplicados al desarrollo de aplicaciones no son un concepto nuevo, de hecho los usan los sistemas operativos gráficos multitareas e incluso los sistemas en tiempo real.

El uso de mensajes tiene el objetivo de estandarizar cada módulo como una caja negra similar a un objeto, con una sola entrada y una salida y que además hace una acción muy específica. Si los puntos de comunicación de todos los módulos son los mismos es muy fácil hacer conecciones entre ellos y aprovechar las características de cada uno más allá de su objetivo inicial.

¿Que se necesita para adoptar la arquitectura basada en mensajes?
- Incluir el módulo ClaMsg.Cla
- Cada ventana debe contener una función pública para la recepción de mensajes
- El diseño interno de cada ventana debe ser muy modular (Cada función realiza una función específica)
- Cada ventana define que mensajes puede atender y que parámetros necesita
- Cada ventana debe declarar una variable de tipo
ClaMsg para hacer una copia local del mensaje recibido

(General)/[Declaraciones]
' Declaraciones Obligatorias-----

Option Explicit


Dim
clMsgLoc As ClaMsg


' Indica que toda variable...
' debe declararse antes de usarse

' Contiene una copia local a la forma...
' del Mensaje que recibe la forma

 

Public Sub Ejecutar(pclMsg As ClaMsg)
__Set clMsgLoc = pclMsg

__Select Case clMsgLoc.Mensaje
____Case MSG_Nuevo
______lS_FrmIni
______Clave = 0
______Tipo = Val(gF_StrPrmObt(...
______clMsgLoc.Parametros, "Tipo"))
______If Not Me.Visible Then Me.Show
____Case MSG_Abrir
______lS_FrmIni
______Clave = clMsgLoc.Clave
______Tipo = Val(gF_StrPrmObt(...
______clMsgLoc.Parametros, "Tipo"))
______lS_FrmCrg
______If Not Me.Visible Then Me.Show
____Case MSG_Guardar
______lS_FrmGua
__End Select
End Sub


' Hacer una copia local del Mensaje
' A partir de aqui...
' solo se usa la copia local

Debe considerarse que la función ejecutar es el punto de entrada a la forma, esto es, se puede asumir que ahora no será el evento Form_Load el primero en ejecutarse, de hecho junto con el esquema de mensaje se propone un conjunto mínimo de funciones para las formas:

Public Sub Ejecutar(pclMsg As ClaMsg)

Private Sub lS_FrmIni()

Private Sub lS_FrmCrg()

Private Sub lS_FrmGua()

Private Function lF_FrmVld() As Boolean

' Recepción y selección de Mensajes

' Inicialización de controles y variables

' Carga de datos a controles y variables

' Guardar datos

' Validación de datos

El envío de mensajes es muy sencillo, pero hay que tener en consideración una cosa, si la ventana destino es MDI o no porque el proceso es diferente. Primeramente se muestra un ejemplo de envío de mensaje a una ventana No-MDI (Modal o Normal)

Sub gM_AyuAce()
__Dim clMsg As New ClaMsg
__
__
clMsg.EnviarFrm FrmAce, MSG_MostrarNormal
End Sub

' Crear una nueva instancia de mensaje

' Enviar mensaje a una forma No-MDI

Para el caso de ventanas MDI se usa otro método de la clase (EnviarMDI) y los parámetros son los mismos que para EnviarFrm

Sub Main()
__Dim clMsg As New ClaMsg
__
__
clMsg.EnviarMDI MDIApl, MSG_Cargar
End Sub

' Crear una nueva instancia de mensaje

' Enviar mensaje a una forma MDI

La lista completa de propiedades y métodos es la siguiente:

- Cadena
- Clave
- Control
- FormaDestino
- FormaOrigen
- MdiDestino
- Mensaje
- Parametros
- SQL
String
Long
Control
Form
Form
MDIForm
Integer
String
String
  - Enviar

- EnviarFrm

- EnviarMDI

- Limpiar
Envía el mensaje asumiendo
los valores de las propiedades
Envía un mensaje a una forma No-MDI...
con los valores pasados como parámetro
Envía un mensaje a una forma MDI...
con los valores pasados como parámetro
Limpia el contenido de todas las propiedades

Pantallas estándar

Directorio de trabajo

  • Módulos del sistema
  • Archivos auxiliares
  • Base de Datos
  • Control de versiones

Biblioteca de gráficos

Iconos

Bitmaps

Vectores

Biblioteca de Funciones y Subrutinas


A continuación se lista la mayoría de las funciones contenidas en el módulo ModLib.Bas junto con una breve descripción, para una referencia completa se puede referir a los anexos en la sección Biblioteca de Funciones, donde encontrará ejemplos de uso y la definición de los parámetros de cada una

Strings

gS_StrElmAct Sustituye el Elemento número Indice dentro de una Cadena separada por Separador. (Indice >= 1)

gF_StrElmNum Obtiene el número de elementos dentro de Cadena que se encuentra separada por Separador con el formato: "Elemento_1 Separador Elemento_2 Separador ... Separador Elemento_n [Separador]". Donde Separador puede estar compuesto por 1 o mas caracteres.

gF_StrElmObt Obtiene el elemento número Indice (Iniciando en 1) dentro de la Cadena que se encuentra separada por Separador con el formato: "Elemento_1 Separador Elemento_2 Separador ... Separador Elemento_n [Separador]", si el elemento no existe regresa ""

gF_StrNomCap Capitaliza un nombre (string) con la primera letra de cada palabra en mayúscula y las restantes en minúscula. No importa el estado inicial de la cadena (Todas mayusculas, todas minusculas o intercaladas)

gF_StrNomVld Valida un Nombre y lo trunca si excede la Longitud
Quita espacios en blanco al principio y al final
Quita los caracteres entre
Chr(0) y Chr(31)
Quita el apostrofe (‘) y la pipa (|)

gF_StrObtLng Convierte una cadena con un valor numerico a un long. Encuentra valores numéricos insertos en la cadena aún si inician con caracteres alfabéticos Si el número excede el rango de los Longs devuelve 0 Ignora todos los caracteres después del siguiente carácter no numérico que siga al número

gF_StrPrmAct Actualiza el valor de un parametro existente en una lista de parametros con el formato:
"
Parametro_1= Valor Parametro_2= Valor ... Parametro_n=Valor".
Regresa la nueva cadena (Lista de parámetros)
Si el parametro no existe lo agrega.
Es indistinto si los parámetros estan en mayúsculas o minúsculas.
Entre el parámetro y el signo de igual (=) no debe haber espacios en blanco
Entre el parámetro y el valor de un parámetro anterior debe haber al menos un espacio en blanco

gF_StrPrmObt Obtiene el valor de un parametro de una lista de parametros con el formato:
"
Parametro_1= Valor Parametro_2= Valor ... Parametro_n=Valor".
Si el parametro no existe regresa una cadena vacía ("")
Es indistinto si los parámetros estan en mayúsculas o minúsculas.
Entre el parámetro y el signo de igual (=) no debe haber espacios en blanco
Entre el parámetro y el valor de un parámetro anterior debe haber al menos un espacio en blanco

gF_StrQuiCar Quita Caracteres contenidos en Cadena y regresa la nueva cadena

gF_StrSinEsp Regresa una cadena sin espacios al principio ni al final y quita caracteres no imprimibles si es que estan contenidos en la cadena

Validación y conversión

gF_StrCurVld Valida un valor numérico Currency contenido en un string. Rango: <-922,337,203,685,477.5808 a 922,337,203,685,477.5807 > (8 bytes ). Si el valor es incorrecto o fuera de rango regresa 0

gF_StrDblVld Valida un valor numérico Double contenido en un string. Rango: <-3.402823E38 a -1.401298E-45 para valores negativos; 1.401298E-45 a 3.402823E38 para valores positivos. Si el valor es incorrecto o fuera de rango regresa 0

gF_StrIntVld Valida un valor numérico Integer contenido en un string de: -32,768 hasta 32,768. Si el valor es incorrecto o fuera de rango regresa 0

gF_StrLngVld Validar un valor Long contenido en un string desde -2,147,483,648 hasta 2,147,483,647. Si el valor es incorrecto o fuera de rango regresa 0

gF_StrSglVld Valida un valor numérico Single contenido en un string desde -3.402823E38 hasta -1.401298E-45 para valores negativos; 1.401298E-45 a 3.402823E38 para valores positivos
Si el valor es incorrecto o fuera de rango regresa 0

Fechas

gF_FecExt Obtiene la fecha extendida en idioma español en el formato: Dia de Mes de Año; Si el formato de fecha no fuera correcto, regresa una cadena vacia (""

gF_FecVld Valida una Fecha contenida en un string la regresa en el formato interno de VisualBasic (tipo Double), si no es válida regresa 0.

Listas

gS_LstBusQry Busca una cadena de texto dentro de todas las columnas de un Lista (ListBox) y si la encuentra, selecciona el Item, en otro caso no selecciona ninguno (ListIndex = -1), permite búsquedas compuestas separando cada campo con coma.
(ej. :
"Depart,Sistem,10722"
Son indistintas las mayúsculas y minúsculas.
Para que se seleccione un elemento debe encontrarse todo el Criterio compuesto

gS_LstItmInv Invierte dos Items dentro de Lista incluyendo su propiedad ItemData.
NOTA: No aplica para listas con la propiedad
Sorted=True

gS_LstSelMov Mueve los elementos seleccionados de ListaOrigen a ListaDestino incluyendo la propiedad ItemData.
NOTA: El movimiento se hace en orden inverso

gS_LstTab Tabula un ListBox de acuerdo a las tabulaciones de Tabs separados por comas con el siguiente formato : "0,10,30,45"
Las columnas deben estar separadas por tabuladores (
Chr(9)) o por su equivalente: la constante sTAB

gS_LstTodMov Mueve todos los elementos de ListaOrigen a ListaDestino incluyendo la propiedad ItemData.
NOTA: El movimiento se hace en orden inverso

gS_LsVBusQry Busca una cadena de texto dentro de los elementos de un ListView y si la encuentra, selecciona el Item, en otro caso no selecciona ninguno, permite búsquedas compuestas separando cada campo con coma.
(ej. :
"Depart,Sistem,10722".
Son indistintas las mayúsculas y minúsculas. Para que se seleccione un elemento debe encontrarse todo el criterio compuesto

gF_LstBusItm Busca dentro de una Lista el elemento cuya propiedad Item sea igual a Item, si lo encuentra regresa su Indice, de lo contrario regresa -1

Grids

gS_GrdColOpr Realiza operaciónes (suma "+",resta "-",multiplicación "*", división "/") sobre dos columnas completas de un grid dejando el resultado en otra columna del mismo grid, haciendo la operación renglon por renglón.

gS_GrdRenOpr Realiza operaciones (suma "+",resta "-",multiplicación "*", división "/") sobre dos celdas de un mismo renglón de un grid dejando el resultado en una celda ‘que este en el mismo renglón sobre el cual se hizo la operación.

gS_GrdRenTot Obtiene los totales de columnas de un grid, indicando como parámetros los renglones iniciales y finales, asi como el renglon donde se ‘vizualizara el total de cada una de las columnas especificadas.

gF_GrdCelSum Suma un rango de celdas de un grid especificado por el renglón y columna inicial y el renglón y columna final

De todo

gF_CalRfc Regresa una primera aproximación del RFC mandando como parámetros el nombre, apellidos y fecha de nacimiento de alguna persona.

gF_MnuOpcObt Muestra una persiana de menú en la posición actual del cursor del mouse, las Opciones mostradas se envían con el formato: "[&]Opción_1,[&]Opción_2, ... , [&]Opción_n" (Todavía no regresa ningún valor). Soporta el uso de separadores ("–"). No soporta atajos ( Ctl + A, Shift + Ctl + i, etc.). Los separadores ("-") se consideran una opción más

gF_MouCurPos Obtiene las coordenadas actuales del cursor del mouse en pixels en coordenadas de pantalla.

gF_PntCorCnv Convierte las coordenadas de Punto referidas al pControl a coordenadas de pantalla, en ambos casos están en Twips

gS_FrmSieFre Establece una Forma como Siempre_al_Frente. La ventana ya debe estar visible antes de llamar a la función. No se puede aplicar a ventanas modales. No se puede aplicar a ventanas MDI ni MDI Hijas

gS_PicBrd3D Dibuja un borde bajo_relieve en un PictureBox usando los colores del sistema. Se usa para dibujar bordes alrededor de controles

gS_TxtSel Selecciona el texto contenido en un TextBox

Archivos de Inicialización

gF_IniObtInt Obtiene un entero de un archivo Ini, si no se encuentra regresa 0.

gF_IniObtStr Obtener un String de un archivo Ini, si no se encuentra regresa "".

gS_IniRegInt Registra un número entero en un archivo Ini.

gS_IniRegStr Registra una cadena en un archivo Ini.

gF_WinObtStr Obtiene un string del archivo Win.Ini del sistema, si no se encuentra regresa ""