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:
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 ""
|
|