Curso Básico de Programación
en Visual Basic

 

Entrega Veintiséis: 6/Dic/98
por Guillermo "guille" Som

Si quieres linkar con las otras entregas, desde el índice lo puedes hacer

 

La entrega de hoy, para quitarnos un poco la resaca de la "celebración" de la anterior, se basará en consejos y observaciones sobre las declaraciones de variables y otras cosillas que deberás tener muy en cuenta para no meter la pata hasta el cuello, ya que en ocasiones "nos equivocamos" por no permitir que el Visual Basic tenga en cuenta algunas cosillas de las que "intentamos" hacer, con buena intención, pero que en ocasiones no son todo lo correctas que debieran. No soy el único que te dará o que ha dado estos consejos, ya que todos los programadores que llevamos algún tiempo con el VB solemos hacerlo, entre otras cosas porque nos da algo de "rabia" que los programadores de otros lenguajes, (léase Pascal/Delphi y C/C++), se rian de que el Visual Basic es muy propenso a errores tipográficos... realmente no lo dicen de esta forma, pero el caso es que se quejan de que este lenguaje no "obligue" a declarar las variables, lo malo que tienen "esos" programadores es que realmente no conocen el Visual Basic, al menos no lo habrán visto a fondo o no lo han tocado desde la versión 2... pero para eso estamos aquí los que si lo hemos "estudiado" y lo seguimos haciendo, para que los menos "expertos" aprendan lo más rápido posible y sobre todo lo mejor posible...

Como te comentaba muchos de los errores tipográficos se solucionan usando una instrucción, que ya te he comentado en otras ocasiones a lo largo de este curso, interminable, de Visual Basic y no es otra que:

Option Explicit.

Cuando insertamos esta instrucción al principio de un módulo, ya sea del código de un formulario, módulos BAS o de cualquier otro, el VB nos obliga a declarar las variables que usemos. Algunos pueden ver eso de no tener que declarar las variables como una ventaja del VB, pero a la larga tener que declarar las variables antes de usarlas, es algo que se agradece... cosa que comprobarás en cuanto leas un poco más de esta entrega.
De todas formas, no tienes porqué estar incluyendo esta instrucción en cada módulo, el Visual Basic puede hacerlo por tí de forma automática cada vez que añadas un nuevo módulo o formulario en tu aplicación. Este automatismo no es un valor por defecto en las versiones anteriores al VB6, (en esta versión ya lo es y se agradece, al menos para que los que empecéis lo tengáis por defecto), pero puedes hacer que lo sea, para ello tendrás que marcar la opción que para ello tiene el IDE del VB en el menú Herramientas/Opciones en la solapa Editor estará "Require variable declaration" (al menos así se llama en la versión inglesa del VB, que es la que uso últimamente)

¿Que ventajas tiene esto?

Que si te equivocas al escribir el nombre de una variable, el VB te avisará de este eerror y así será más fácil solucionar problemas, te puedo asegurar que "muchos problemas".

Vamos a comprobarlo, crea un nuevo proyecto, te añadirá un nuevo formulario (Form1), muestra la ventana de código y si tiene insertado Option Explicit, bórralo. Muestra el form y añade un CommandButton, añade el siguiente código al evento Click de este botón:

Private Sub Command1_Click()
    '
    Dim SumaActual As Long
    Dim i As Long

    SumaActual = 0
    For i = 1 To 5000
    SumaActual = SumActual + 1
    Next

    MsgBox "El contenido de SumaActual es " & SumaActual
End Sub

Pulsa F5, haz click en el Command1 y verás que no hace lo que se espera...
Ya que si analizas el código, el valor mostrado debería ser 5000, pero, no es así...
Vamos a dejar que el VB descubra el error por nosotros; para ello vamos a ejecutar de nuevo el programa, pero esta vez añade Option Explicit al principio del módulo, es decir en la parte de las declaraciones generales del formulario, vuelve a ejecutar de nuevo el programa, nada ocurre... pulsa en el botón Command1 y verás que si que había un error tipográfico.

Seguramente dirás que tampoco es para tanto... total, si se escriben bien los nombres de las variables... pues sí, pero cuando tengas proyectos con varios formularios y algunos módulos de otro tipo... entonces ya me contarás si no es mejor contar con "detector de errores tipográficos".

Seguramente te habrás fijado que al ejecutar el programa, (usando F5 o pulsando en el botón de la barra de herramientas), el Visual Basic no te ha avisado del fallo, sólo lo ha hecho cuando has hecho click en el botón, esto está bien, pero no ayuda mucho cuando el proyecto es grande y tiene varios formularios y varios/muchos procedimientos, ya que hasta que no se ejecute el código que hay en ellos no nos avisará del "fallo".

Pero, por suerte, esto se puede evitar... y además de dos formas distintas.
La primera es ejecutando la aplicación con Ctrl+F5, es decir pulsando la tecla control y al mismo tiempo F5, de esta forma se analiza todo el código antes de iniciar el programa y si el Visual Basic encuentra algún error, te avisará.
La otra forma es indicarle al VB que "siempre" analice el código antes de ejecutarlo, de esta forma es como si siempre pulsáramos Ctrl+F5 aunque sólo se pulse F5. Para que esto sea así, muestra el cuadro de diálogo de Herramientas y en la solapa General busca la casilla "Compile on demand" (o como sea en la versión en español), si está marcada esta opción, quítale la marca, esto en proyectos grandes hace que tarde un poquito más al ejecutarse en el IDE, pero es porque se analiza todo el código antes de empezar la ejecución del programa, yo ya me he acostumbrado a que siempre se compile y lo tengo de esta form, ya que no hay nada que más me moleste que se detenga el programa al entrar en un procedimiento por culpa de un error tipográfico, la verdad es que si esta opción hubiese estado en el Basic del MS-DOS nos hubiera evitado algún que otro quebradero de cabeza, por desgracia llegó tarde, con el Visual Basic para DOS, pero más vale tarde que nunca... aunque ahora casi ni se utiliza...

Para terminar con esto de las ventajas de usar Option Explicit, vamos a ver cómo saber si una variable está en uso o no.
Bueno, no es que nos de esa información, pero algo parecido, la verdad es que echo de menos una característica del QuickBasic del MS-DOS y era que al pulsar F1 en una variable, nos indicaba en que módulos se estaba usando dicha variable, pero... aunque no existe esa forma de ver cómo está declarada una variable en el Visual Basic, podemos usar otra forma, que es pulsando Shift+F2; te mostrará la declaración de esa variable... si no te muestra la declaración, es que no está declarada.

A lo que iba, si tenemos declarada una variable, se respeta el "estado" de mayúsculas/minúsculas de ese nombre de variable, por tanto si en el caso del ejemplo anterior, hubiésemos escrito (todo en minúsculas) sumaactual, el VB automáticamente hubiese convertido dicho nombre a SumaActual o como lo hubiésemos escrito al DIMensionarla; esta es una de las formas de saber si ya tenemos la variable declarada... aunque sea en otro procedimiento... el único "fallo" es que el VB recuerda la última forma en que se dimensionó una variable... es decir, si en un procedimiento tenemos esta declaración:
Dim j As Integer y en otra parte de nuestro proyecto esta otra:
Dim J As Integer, el VB convertirá todas las variables "j" al estado de la última declaración que hayamos usado...
Pero al menos sabremos que la tenemos declarada y de esto vamos a ver más cosas...

 

Declarar las variables del tipo adecuado

Ya que estamos en esto de las declaraciones de las variables, voy a darte otro consejo, que si no estan evidente como el anterior, en algunas ocasiones puede hacer que tu aplicación trabaje de forma más eficiente... aunque no te voy a hacer ninguna demostración, ya que la demostración la tuviste en la entrega cuatro.
La recomendación es que declares las variables con el tipo adecuado, es decir, que especifiques el tipo de la variable cada vez que la declares, si no lo haces, el Visual Basic le asignará el tipo por defecto, que normalmente suele ser Variant y aunque ese tipo sirva para todo, no es el recomendable para muchas ocasiones, al menos en lo que a bucles se refiere, por poner un ejemplo.
También puedes especificar el tipo por defecto, esto yo lo hacía siempre en mis programas de MS-DOS, aunque ahora en Visual Basic para Windows no lo suelo hacer, ya que siempre declaro las variable del tipo que quiero que tengan.
Pero para que lo puedas hacer, aunque me imagino que ya sabrás, te recuerdo cómo hacerlo.

Añade justo después del Option Explicit la instrucción DEFxxx a-z, sustituye las xxx por el tipp de tu preferencia, por ejemplo:
DefInt A-Z asignará el tipo Integer a todas las variables declaradas sin un tipo determinado; por otro lado:
DefLng A-Z hará que el tipo predeterminado sea el Long.

Se pueden usar varios de estos DEFxxx usando distintos rangos de letras, ya que el Defxxx funciona de esta forma:
Deftipo rango letras [, rango2 [, rango3, etc]]
dóde tipo es Int para Integer, Lng para Long, Sng para Single, etc. (busca esta palabra en la ayuda para más información)
Los rangos son letras que le indicarán al VB que las variables que empiecen por esas letras sean del tipo indicado, por ejemplo:

DefInt a-c, i, j
DefLng L-N, R

Declarará las variables, siempre que no se especifique el tipo, que empiecen por a, b, c, i y j como variables Integer y las que empiecen por L, m, n y r como Long.
Por ejemplo con estas declaraciones:
Dim Ahora, Nombre As String, Longitud, Resultado As Currency

Ahora será Integer, Longitud será Long y las otras dos, del tipo indicado: Nombre es String y Resultado del tipo Currency.
Pero ya te digo que prefiero declarar las variables del tipo adecuado, es decir especificando el tipo que será:
Dim Ahora As Integer, Nombre As String, Longitud As Long, Resultado As Currency
Yo así lo tengo más claro, pero puedes hacerlo como prefieras.

Lo que si debes hacer es usar el tipo que realmente necesites, por ejemplo si vas a hacer bucles que no supere el valor 32767, puedes usar una variable de tipo Integer, si quieres guardar en sDatos una cadena, declarala como tipo String, etc.
Ya que si siempre als declaras como el valor por defecto y se te olvida añadir el DEFxxx correspondiente, tendrás que las variables será del tipo Variant, que entre otras cosas es más lenta y ocupa más memoria. Además de que en un futuro te será más fácil saber el tipo de datos que esas variables contendrán... cosa que agradecerás cuando veas de nuevo el código unos meses o años después...
Y para que te sea más fácil recordar que debe almacenar cada variable:

Usa nombres descriptivos para las variables

Pues eso, es más fácil saber que la variable "Nombre" guarda un nombre que si sólo usas "n"
Aunque en esto de dar nombre de las variables, coincido con otros programadores, de usar ciertas variables "no descriptivas" para ciertas cosas, no es por nada, sino porque como todos, he aprendido viendo código de otros programadores y siempre se te pega algo del "estilo" que se va generalizando... por ejemplo, en el uso de las variables i, j, k para los bucles.

Otro aspecto es el de usar ciertos "prefijos" para indicar el tipo y la visibilidad de las variables... en esto no todos estamos de acuerdo, pero casi... Seguramente habrás "oido" hablar de la notación "hungara"... no voy a entrar en detalles de que va esto, pero si decirte más o menos como se aplica, al menos en algunos casos, a la hora de declarar las variables.
Para simplificar, y mucho, te diré que el prefijo es la letra o letras (normalmente tres), que se usan delante del nombre de la variable, por ejemplo, las variables del tipo Integer se declararían así:
Dim intContador As Integer, lngContador As Long, strNombre As String, etc...
De esta forma, es fácil saber que strNombre es del tipo String, aunque no tengamos "cerca" la declaración de la variable.
Yo suelo abreviar el tema y suelo declararlas de esta otra forma: (como otros programadores, que no vayas a creer que es invención mia)
Dim iContador As Integer, sNombre As String
Con el tipo Long no siempre uso la "l" (ele minúscula), entre otras cosas porque se confunde con el número "1" y casi siempre suelo declarar las variables Long con "lng".
Para los otros tipos no suelo hacerlo de ninguna forma en particular, aunque el tipo "boolean" las declaro con la letra "b".
En el caso de que las variables sean públicas no suelo añadirle ningún tipo de identificador, ya que en el caso de los formularios se convierten en propiedades, no entro en más detalles en esto de las propiedades, ya que será el tema de la próxima entrega.

Pero esto de los prefijos no sólo se aplican a las variables, también se hace a los controles y formularios.
Por ejemplo:

Prefijo Control Ejemplo
cmd CommandButon cmdSalir
txt TextBoxes txtNombre
lbl Labels lblStatus
chk CheckBoxes chkImpresora
cbo CombosBoxes cboCiudad
lst ListBoxes lstNombres
pic PictureBox picStatus
img Image imgBoton

Para los tipos definidos las declaraciones del tipo suelo empezarlos con "t_" y las variables declaradas a partir de un tipo con "t", las enumeraciones (ya las veremos en su momento), las empiezo por "e" y las constantes con "c"...
En el caso de las variables a nivel de módulo, las que son visibles en todo el módulo actual, ahora veremos más sobre esto, suelo anteponerle el prefijo "m_". Aunque todo hay que decirlo, no tengo un estilo fijo en esto de nombrar a las variables y controles, aunque en la mayoría de los casos, es éste el que suelo aplicar... y cada vez con más "consistencia", ya que a la larga te ayuda el usar algún tipo de recordatorio del tipo/nivel de visibilidad de los controles y variables.

Para ir acabando con las recomendaciones del día, voy a darte la penúltima:

Usa comentarios en tus listados

Y es que los comentarios, entre otras cosas, no ocupan espacio en el programa una vez compilado y a la larga, siempre es a la larga, ya que cuando el código está reciente, nos acordamos de todo... pero cuando se lee después de pasado algunos meses... puede que te ocurra lo que a mi... que al estar revisando listados antiguos, tuve que entender lo que hacia el código y después comentarlo para que la próxima vez que tuviese que modificarlo, me resultara más fácil.
Por tanto, si no quieres verte en este aprieto, usa y abusa de los comentarios, aunque sea un poco "pesado", te repito que se agradece, sobre todo si el código cae en manos de otro programador, por ejemplo en un grupo de trabajo y tiene que entender lo que "pretendías" hacer...

 

La visibilidad o "cobertura" (o si lo prefieres: ámbito) de las variables.

Y para acabar esta entrega "sermonística" y casi de repaso, vamos a ver el tema de la visibilidad de las variables o el "alcance" que estas tienen dentro del módulo e incluso del proyecto completo.

¿De que va esto de la visibilidad?

Esto va de que cuando se declaran las variables, estas no están visibles en toda la aplicación...
¡AH! que lo que no entiendes es lo de "visible"...
Te lo explico con un ejemplo:
Supón que tienes un procedimiento que cuenta el número de veces que una letra está en una cadena, por ejemplo en "Visual Basic" la letra "a" está dos veces, talvez no tenga mucha utilidad este ejemplo, pero...

'
Public Function CuantasVeces(ByVal sCadena As String, _
                             ByVal sLetra As String) As Long

    'Esta función devolverá el número de veces que está
    'la letra sLetra en la cadena sCadena

    Dim i As Long       'Variable para el bucle
    Dim nVeces As Long  'variable temporal para el número de veces

    'bucle para recorrer la cadena completa
    For i = 1 To Len(sCadena)
        'Si el caracter comprobado es la letra buscada
        '(se supone que sLetra es sólo un caracter)
        If Mid$(sCadena, i, 1) = sLetra Then
            'incrementar el número de veces
            nVeces = nVeces + 1
        End If
    Next
    'Devolver el total de veces
    CuantasVeces = nVeces
End Function

En este código hay dos variables declaradas: "i" y "nVeces", pues bien, estas variables sólo son visibles dentro de esta función, es decir, que no tendrán nada que ver con otras variables que tengan el mismo nombre, y estén declaradas en otros sitios.

Talvez este ejemplo "solitario" no esté demasiado claro. Pero es un fallo que muchos "cometemos", (o al menos, algunos hemos cometido, aunque ya lo tengamos superado... o casi.)
He visto más de un listado en el que se declara una variable en un procedimiento y después se "intenta" usar en otro sitio distinto en el cual "no se ve" esa variable... Por supuesto, estos problemas de "visibilidad" se evitan usando Option Explicit... realmente no se evitan... sino que nos "obliga" (el VB) a que lo evitemos... ya que no nos dejará usar el programa si no están las variables "debidamente" declaradas... o al menos declaradas aunque no sea de la forma adecuada... (ver más arriba lo que comento sobre
usar el tipo adecuado).

Vamos a verlo con un ejemplillo... para que te des cuenta de lo que podías haberte evitado si usaras el Option Explicit... y si aún no te ha dado tiempo a comprobarlo, porque eres de los que siguen "las reglas", ahora te darás cuenta de que podía haber sido peor tu aprendizaje...

Para este ejemplo, tendrás que crear un nuevo proyecto, se añade por defecto un formulario (Form1), añade un módulo BAS (Module1) y escribe lo siguiente en el módulo BAS:

'En el módulo BAS
Option Explicit

Public sNombre As String
Public nVeces As Long

Public Sub MostrarNombre()
    'Muestra el nombre y el valor de nVeces
    MsgBox "El nombre es: " & sNombre & vbCrLf & _
           "y se ha pulsado: " & nVeces & " veces"
End Sub

Escribe esto en el formulario (Form1) que tendrá un TextBox (Text1) y botón (Command1):

'En el Form1
Option Explicit

'Esta variable es "privada" y visible sólo en este formulario
Private nVeces As Long

Private Sub Command1_Click()
    'Declaramos una variable "privada",
    'y por tanto sólo es "visible" dentro de este procedimiento
    Dim sNombre As String

    'Asignamos a la variable el contenido del Text1
    sNombre = Text1

    'incrementamos las veces que se ha pulsado en el botón
    nVeces = nVeces + 1

    'mostramos la información
    MostrarNombre
End Sub

Ejecuta el programa y verás que cuando pulses en el Command1, no te muestra el nombre y las veces siempre serán cero... aunque pulses varias veces.

¿Por qué ocurre esto si las variables sNombre y nVeces están declaradas como públicas en el módulo BAS?
Esto es así, porque a pesar de haber declarado esas dos variables como públicas en el módulo BAS, (es decir visible en todo el proyecto), no se ha asignado nada a ellas...
¿Seguro?
Entonces, ¿que pintan las asignaciones: sNombre = Text1 y nVeces = nVeces + 1 que hay en el procedimiento Command1_Click?
Te lo explico:
El caso de sNombre es más fácil de comprender, a saber, cuando el Visual Basic entra en el procedimiento Command1_Click, declara una variable de tipo cadena llamada sNombre, esa variable sólo es visible dentro de este procedimiento, es decir que cuando se use, el VB usará la memoria que ha reservado al encontrarse esa declaración, por tanto el contenido del TextBox se guardará en ese espacio de memoria, osea: la variable sNombre del procedimiento Command1_Click.
En el caso de nVeces es parecido al de sNombre, pero en este caso la "visibilidad" de esta variable es más amplia que la de sNombre, ya que al estar declarada a nivel de módulo, es visible en todo el formulario, pero al ser privada sólo será visible, (o accesible, o disponible, como prefieras), dentro del código que esté en el propio formulario y no fuera de él.
Por tanto, al llamar al procedimiento MostrarNombre, (que está declarado como público en el módulo BAS y por tanto disponible en todo el proyecto), el VB se encuentra con que queremos usar dos variables... comprueba si está debidamente declaradas y usa los valores que contienen... es decir, ninguno; por tanto muestra los valores por defecto... una cadena vacia y un valor cero.

Esto en inglés se llama "scope", ámbito o alcance; si lo entiendes mejor es la "cobertura" que tiene esa variable, como la de los teléfonos móviles (celulares) o emisoras de radio... si no tiene cobertura en una zona, no se escuchará en esa zona...

Vamos a ver las distintas formas de declaración de una variable, para ver el "alcance" que tienen:

-Declaradas en un procedimiento (Sub, Function o Property)
Sólo son visibles en ese procedimiento
-Declaradas Privadas (o con Dim) en un formulario o módulo (BAS, CLS u otro tipo)
Sólo son visibles en ese formulario o módulo, incluidos todos los procedimientos de ese módulo, salvo la restricción anterior.
-Declaradas Públicas (o Globales) en un módulo BAS
Son visibles en todo el proyecto, salvo cuando se encuentren con variables declaradas en los casos anteriores.
-Declaradas Públicas en formularios o módulos de clase
Serán visibles en cualquier sitio, siempre que se preceda con el nombre del formulario o clase... (ya veremos esto en otra ocasión)
O sólo dentro de ese módulo, como si fuesen privadas al propio módulo.

Por tanto, las variables que tengan el mismo nombre, se usarán según la última declaración que tenga esa variable y si está al alcance del procedimiento en el que se está usando... que lio, ¿verdad?

Esta cercanía en la declaración de la variable se puede explicar también así:

  • Primero se usarán las que estén declaradas en el propio procedimiento
  • Después las que estén en el mismo módulo (o formulario o clase o... cuando digo módulo, me refiero al "sitio" en el que escribes el código)
  • Por último, las declaradas como globales o públicas en un módulo BAS

Hay que puntualizar que las variables públicas declaradas en un formulario, módulo de clase o control de usuario, se convierten en propiedades de esos "objetos", y como sabrás para usar una propiedad de un "objeto", debes especificar el nombre del objeto seguido de un punto y después el nombre de la propiedad; aunque cuando se usan en el mismo módulo o formulario, no es necesario usar el nombre del "objeto que las contiene", por tanto, si no se especifica el nombre del módulo, sólo son visibles dentro del mismo módulo en el que se han declarado.

Para que el ejemplo anterior funcionara como debe, tendrás que quitar las declaraciones que hay de las variables sNombre y nVeces en el formulario y sólo dejar las del módulo BAS.
Pruébalo y verás que ahora si que se muestra lo que se debe mostrar.

 

Usar una variable indicando el módulo en el que se han declarado

Ya que he tocado el tema de especificar el nombre del "objeto" delante de las variables, también se pueden usar de esa forma y así evitaríamos el tema este de la visibilidad y alcance de las variables, aunque es algo más "liante"...
Esta forma de usarlo fuera del módulo en el que se ha declarado, sólo es válido si las variables son "públicas".
Para verlo, un ejemplo:
Crea un nuevo proyecto, se creará un formulario (Form1), añade un módulo BAS (se creará Module1, no le cambies el nombre al módulo)
Escribe esto en el módulo BAS y el formulario, según se especifica:

'En el módulo BAS
Option Explicit

Private pVariable As Long
'Esta variable está declarada en el Form1 y en este módulo
Public unaVariable As Long
Public gVariable As Long


'El Form1 escribe:
Option Explicit

Private unaVariable As Long
Public otraVariable As Long

Private Sub Form_Load()
    Show

    'para saber si está declarada,
    'selecciona la variable y pulsa Shift+F2,
    'te mostrará dónde está declarada

    'Esta variable es la declarada en este formulario
    unaVariable = 10

    'Estas variables están declaradas como públicas en el módulo BAS
    otraVariable = 20
    gVariable = 30

    'Esta otra está declarada como pública en el módulo BAS,
    'pero como tiene el mismo nombre que la declarada en el formulario,
    'para poder usarla, hay que especificar el nombre del módulo
    Module1.unaVariable = 40

    'Esta dará error ya que es privada en el módulo BAS
    '(Variable no definida)
    'pVariable = 50

    'si se usa de esta forma:
    'Module1.pVariable = 50
    'se encontrará la declaración al pulsar Shift+F2,
    'pero dará error de que no se encuentra el método

    'Mostrar el contenido de las variables:
    Print "unaVariable="; unaVariable
    Print "otraVariable="; otraVariable
    Print "gVariable ="; gVariable
    Print "Module1.unaVariable ="; Module1.unaVariable

    'Esta no se puede mostrar porque es Privada y por tanto
    'sólo visible dentro del módulo BAS
    'Print "Module1.pVariable ="; Module1.pVariable
End Sub

Creo que los comentarios son aclaradores, así que ejecútalo y verás lo que muestra, prueba a quitar Module1 cuando se use y asigne a "unaVariable" y verás que el primer valor se pierde (como debe ser...).

 

Bueno, aunque he tardado en publicarla... al fin hemos continuado con las entregas del cursillo básico...
La verdad es que el manuscrito era del 30 de Septiembre, empecé a escribirlo en el OutLook Express cuando estaba en Canarias el 29 de Octubre y por fin lo he acabado el 6 de Diciembre... pero más vale tarde que nunca... ¿verdad?
Confío en que haya servido de algo tanta espera... así que
si quieres hacer algún comentario... hazlo pulsando en este link...

Nos vemos.
Guillermo


 
entrega anterior ir al índice siguiente entrega

Ir al índice principal del Guille