Você está na página 1de 11

Para Novatos

y otras cosillas: incluso para VB3, etc.


Actualizado el 11/Ene/2003 (9-Dic-1997) Contenido: Novato = Al_que_empieza Los links:

1. Cuidado al dimensionar varias variables con un solo DIM (11/Ene/2003)

Los links del ao 1997:

1. (24/Ene) Bucles For 2. (24/Ene) Usa siempre Option Explicit 3. (24/Ene) Hacer comparaciones sin importar que sean maysculas o
minsculas 4. (25/Ene) Evitar que un sub entre en un bucle sin fin... 5. (15/Feb) Sobre los argumentos con ByVal y ByRef 6. (15/Feb) Cuidado con las cadenas pasadas al API de Windows con ByVal 7. (22/Feb) Efecto ToolTip para VB 2.0 y superior 8. (5/Mar) Comparaciones ms rpidas con IF...THEN 9. (24/Mar) Los declaraciones de Funciones del API y Tipos definidos en un Form o mdulo de Clase 10. (24/Mar) La visibilidad de las variables 11. (24/Mar) El Tipo de las variables por defecto 12. (8/Abr) Listados de ejemplo para crear un ToolBar, ToolTips y efectos 3D para VB3 13. (6/Jul) Evitar que una aplicacin se cargue por segunda vez (VB2 y posteriores) 14. (9/Jul) Evitar los eventos en cascada... te suena el OUT OF STACK SPACE?

1.- Bucles For Me imagino que sabes hacer un bucle For. Lo que voy a contarte es como hacer que funcione ms rpido. Usa variables enteras para el ndice Procura no hacer clculos dentro del bucle, de valores que no van a cambiar No indiques la variable del bucle despus de Next

No salgas con GOTO, (alguien lo usa todava?), de un bucle For Listado 1 (correcto, pero...)

' Las variables x, y, b sern del tipo por defecto (Variant) Dim x, y, b, a$ a$="Hola Mundo" For x=1 To 10 b = Len(a$) For y = 1 To b If Mid$(a$, y, 1) = Chr$(32) Then GoTo OtraLinea End If Next y OtraLinea: Next x Listado 2 (pues, eso...) Dim x As Integer, y As Integer, b As Integer, a$ a$="Hola Mundo" b = Len(a$) For x=1 To 10 For y = 1 To b If Mid$(a$, y, 1) = Chr$(32) Then Exit For End If Next Next 2.- Usa siempre Option Explicit Acostmbrate a indicar siempre que sea necesario declarar las variables. Esta opcin era una de las pocas cosas que me gustaban de C o Pascal, ya que si no te acostumbras a declarar las variables, al final acabas creando muchas ms de las que necesitas. Antes, (lase Qbasic, GWBASIC, etc.), tena excusa. Ahora no! Ya que puedes obligarte a declarar las variables, si indicas al inicio del cdigo: Option Explicit Visual Basic puede hacerlo por ti, si se lo indicas en las opciones del proyecto... Men Tools, solapa Environment, opcin: Require Variable Declaration La ventaja: que si te equivocas al escribir una variable, a quin no le ha ocurrido?, VB te indicar que no existe. La desventaja: Que tienes que declarar todas las variables con Dim, etc. Ya sabes que si no declaras una variable, y por supuesto no tienes la orden Option Explicit, Visual Basic le asigna por defecto el tipo Variant y la crea si no existe. Con los arrays, crea los valores de 0 a 10. Por tanto puede que incluso ests desperdiciando memoria: 1. Variant ocupa ms espacio de memoria que cualquier otro tipo 2. Puede que slo necesites un array de 5 elementos, el resto que no necesitas, est ocupando memoria que puede ser necesaria para otras cosas: velocidad, ms variables, etc.

3.- Hacer comparaciones sin importar que sean maysculas o minsculas

Es muy fcil creer, sobre todo para el no iniciado, que "Hola" es lo mismo que "HOLA" Para VB, o cualquier otro lenguaje, no es as. Estos trabajan comparando carcter por carcter, y la A (a maysculas, cdigo ASCII 65), no es igual a la a (a minscula, cdigo ASCII 97) Si en a$ esperamos una entrada que sea igual a "Clave", al hacer esta comparacin, puede que pienses que ests comprobndolo correctamente: If a$ = "Clave" Then... Pero el usuario, puede haber escrito "clave" o "CLAVE", (hay mucha gente que todo lo escribe en maysculas...), y la condicin no se cumple. Para "arreglarlo", podemos hacerlo de la siguiente forma: If Ucase$(a$) = "CLAVE" Then... o If LCase$(a$) = "clave" Then... Pero hay otra forma, con la que no tenemos que preocuparnos de cmo se introduzcan los datos, cualquiera de las formas que usemos para comprobarlo, dar un resultado TRUE en la comparacin... Cmo? Indicando OPTION COMPARE TEXT en el inicio del mdulo en el que hagamos la comparacin. OJO, slo a nivel de mdulo y en el mdulo que se especifique. De esta forma, el usuario puede escribir "CLAVE" y esta comparacin se cumplir: If a$ = "Clave" Then...

4.- Evita que al cambiar un ListBox entre en un bucle sin fin. Para hacer esto, yo uso variables estticas mientras cambio un ComboBox o un ListBox... Ya sabes que las variables estticas conservan el valor entre cada llamada. A diferencia de las locales-dinmicas, que se generan cada vez que entras en un Sub. Tambin puedes usar una variable a nivel de mdulo, en lugar de una esttica. Ya que la esttica es visible slo por ese Sub, mientras que la variable a nivel de mdulo, es visible por todo el mdulo, o por toda la aplicacin, si est declarada como Pblica o Global. Sub Combo1_Change() Static YaEstoy as Boolean If YaEstoy Then Exit Sub YaEstoy = True 'El cdigo... YaEstoy = False End Sub 5.- Sobre los argumentos con ByVal y ByRef: Argumentos por Valor o por Referencia (15/Feb) Cuando VB pasa una variable a un procedimiento, lo hace por referencia, es decir, le d al procedimiento la variable, de modo que cualquier cambio que se haga en dicha variable, se reflejar en el contenido de la misma. Lgico? Se supone, ya que estamos acostumbrados a que as sea, (me refiero a los programadores de Basic). Si queremos pasar slo el valor de una variable, debemos ponerla entre parntesis, de esta forma cualquier cambio que el

procedimiento realice en la variable, no ser "actualizado" al contenido de la misma... Esta bien, veamos unos ejemplos... Tenemos un sub que recibe dos variables y le suma a la primera el valor de la segunda: Sub Sumar (A As Integer, B As Integer) A = A + B End Sub Veamos que ocurre con esto del valor y la referencia: 'Parmetros por referencia M = 5 N = 3 Sumar M, N Print M 'Imprimir 8, 5+3 'Parmetros por valor M = 5 N = 3 Sumar (M), N Print M 'Imprimir 5, ya que no se cambia el valor En el segundo ejemplo, la llamada al procedimiento, podramos haberlo puesto tambin de esta forma: Sumar ByVal M, N El valor de la variable M, al pasarse por valor, no se modifica en el suprograma Sumar, ya que lo que recibe este Sub es una copia con el valor de la variable, no una referencia a la direccin de memoria en la que la variable almacena el valor. Todo esto viene a cuento de que en ocasiones, necesitamos manejar una varibale en un procedimiento, pero no nos interesa que se modifique "accidentalmente" el valor. Este no sera el caso del Sub Sumar, ya que la intencin es modificar el valor del primer parmetro. Veamos otro ejemplo, pero esta vez con cadenas de caracteres. (la aclaracin de caracteres es para el que an no se ha enterado que normalmente en basic cuando uno se refiere a cadenas, se hace referencia a las cadenas de caracteres, de nada.) Esta funcin, que de paso puede sernos de utilidad, recibe dos cadenas, y devolver el resultado de "extraer" de la primera, el contenido de la segunda; en caso de que la segunda no est dentro de la primera, se devuelve la primera completa. Por ejemplo: Extrae("Hola mundo","mundo") devolvera "Hola " y Extrae("Hola mundo","gente") devolvera "Hola mundo" Veamos la declaracin de esta funcin ' Listado 1 Public Function Extrae( Cadena As String, Parte As String) As String Dim i As Integer i = Instr(Cadena, Parte) If i Then Extrae = Left$(Cadena, i-1) & Mid$(Cadena, i + Len(Parte)) Else Extrae = Cadena End If End Function

Tal como se manejan los datos en esta declaracin, ni Cadena ni Parte se modifican. Pero podramos tener el cdigo "mal" definido y por "accidente" cambiar estos valores. Vemoslo con una modificacin de la funcin, para que el valor devuelto no tenga espacios delante ni detrs: ' Listado 2 Public Function Extrae( Cadena As String, Parte As String) As String Dim i As Integer Cadena = Trim$(Cadena) i = Instr(Cadena, Parte) If i Then Cadena = Trim$(Left(Cadena, i-1)) & Trim$(Mid$(Cadena, i+Len(Parte))) End If Extrae = Cadena End Function Ahora tanto Cadena, como Extrae devolveran lo mismo. Pero puede que nos interese que Cadena siga teniendo el valor original. Esto podemos solventarlo de dos formas: La primera, usando una variable temporal: ' Listado 3 Public Function Extrae( Cadena As String, Parte As String) As String Dim i As Integer Dim sTmp As String sTmp = Trim$(Cadena) i = Instr(sTmp, Parte) If i Then sTmp = Trim$(Left(sTmp, i-1)) & Trim$(Mid$(sTmp, i+Len(Parte))) End If Extrae = sTmp End Function La segunda, cambiado la definicin del parmetro Cadena para que sea por valor: en el listado 2, cambiar la definicin de la funcin para que est de esta forma: Public Function Extrae( ByVal Cadena As String, Parte As String) As String De esta forma, no se reflejar ningn cambio en Cadena y no tendremos que usar otra variable, para hacer el trabajo. Resumiendo: ByRef (por Referencia) es la forma por defecto y se pasa la variable, o mejor dicho: se pasa la direccin en donde se almacenan los datos de esa variable, despus vers a que viene esta aclaracin. ByVal pasa slo el valor. El siguiente apartado, te muestra las precauciones que debes tener con lo que se ha comentado, cuando se pasan valores a las API de Windows.

6.- Cuidado con las cadenas pasadas al API de Windows con ByVal (15/Feb) Normalmente las llamadas al API, se hacen por valor, que es la forma que tiene el lenguaje C de hacerlo. Segn lo expuesto en el apartado anterior, si se pasan variables por valor, estamos

pasando el valor de la variable y por tanto no se modificar su contenido: PUES NO... Bueno, no cuando al API de Windows se refiere y si se trata de cadenas. En el caso de las cadenas pasadas al API con ByVal, se le est pasando la direccin que apunta a los datos, (puntero o referencia a la variable, segn los seores de C ), por tanto la funcin podr "libremente" modificar el contenido de la "susodicha" cadena. Por tanto: precaucin. Y para ser precavidos, pues eso: mejor prevenir que curar. Cuando pasemos cadenas al API de Windows, u otro API cualquiera que use funciones en formato del lenguaje C, debemos asegurarnos que las cadenas son suficientemente largas, para que almacene el valor que deba almacenar. La precaucin: no ser "roosos" a la hora de declarar la variable. Por ejemplo, si queremos usar una funcin que devuelve una cadena, como sera el caso de GetWindowsDirectory, que devuelve el directorio de Windows: Declare Function GetWindowsDirectory Lib "Kernel32" Alias "GetWindowsDirectoryA" _ (ByVal lpBuffer As String, ByVal nSize As Long) As Long Dim WinDir As String Dim Cadena As String Dim ret As Long Cadena = String$(300, Chr$(0)) ret = GetWindowsDirectory(Cadena, Len(Cadena)) WinDir = Left$(Cadena, ret) 'Esta sera la forma "lgica" de obtener el valor 'Pero podemos "rizar el rizo" y hacerlo de esta otra: WinDir = Left$(Cadena, Instr(Cadena, Chr$(0)) - 1) Fijate en que he puesto dos formas de asignar a WinDir el directorio de Windows. La primera es la que se debera hacer, ya que el valor devuelto por la funcin GetWindowsDirectory es la longitud de la cadena resultante. Mientras que la segunda es una forma genrica de obtener las cadenas cuando es una funcin escrita en C la que la devuelve. Y es por la razn de que las cadenas en C, normalmente, siguen el formato ASCIIZ, es decir una cadena acabada en el carcter de cdigo ASCII 0 (cero) Lo que quiero decir con todo este rollo, es que debemos ser generosos con la longitud de las cadenas pasadas a funciones del API, si sabemos que son directorios o archivos los valores que van a devolver, con una longitud de 260, sera ms que suficiente, ya que este valor es el mximo soportado por los nombres largo. Este valor, est definido en la constante MAX_PATH del SDK del API de Windows. Por cierto en el fichero Win32API.TXT est mal, ya que indica que son 32 caracteres, cualdo deberan ser 260.

7.- Efecto ToolTip para Visual Basic 2.0 y superiores (22/Feb) Este programa es para hacer el efecto ToolTip. Adjunto un listado de ejemplo, vlido para todos los VB a partir de la versin 2 incluida. Si quieres echarle un vistazo al listado de la rutina que se encarga de hacer el efecto, pulsa aqu. Est en formato TXT para que puedas verlo directamente con el browser. Listado de ejemplo en formato zip (tooltip.zip 3.27 KB)

8.- Comparaciones ms rpidas con IF...THEN (5/Mar) Este es un truco "antiguo", pero que an sirve. Lo he sacado de una revista que tena de mis tiempos del VIC-20. El mirar la revista ha sido un poco de aoranza, ya que al comunicarme lvaro Ibaez de que me haba incluido en los recomendados de iWorld, coment que "Es bueno encontrar gente que *tambin* conoci los tiempos del Vic-20 & Co... :-)" Y me puse a hojear las revistas que tena del Commodore World, que por cierto las tengo todas, soy un "forofo" de las colecciones de revistas que me interesan... Bueno, vamos al truco en cuestin: Esto es para cuando se quieren hacer "mltiples" comparaciones usando el AND, por ejemplo: If A=2 AND B=3 Then ... Se puede sustituir por esto otro: If A=2 Then If B=3 Then ... O si lo hacemos estructurado: If A=2 Then If B=3 Then '... End If End If Como vers, haciendo la comparacin con IF en bloques, se entiende mejor el porqu es ms rpido de la segunda forma. Slo se pasa al segundo IF si el primero se cumple, lo mismo que ocurrira con el AND.

9.- Las declaraciones del API y Tipos definidos en un Form o mdulo de Clase (24/Mar) Cuando declaras una funcin del API o de una DLL externa, se suele hacer de la siguiente forma: Declare Nombre_Funcion... Si pretendes usarla de forma local en un Form o un mdulo de Clase, debes ponerle delante Private y as no te dar error. Private Declare Nombre_Funcion... Lo msmo ocurre con los tipos definidos. Antes (VB3 y anteriores), slo se permita en los mdulos BAS, pero ahora se pueden declarar en los Form y CLS, pero si son privados. Por tanto debes hacerlo con Private delante: Private Type El_tipo_que_sea... Por supuesto puedes usar tambin Private en un mdulo BAS, pero slo estarn visibles dentro de ese mdulo.

10.- La "visibilidad" de las variables (24/Mar) Ya que he comentado lo de las declaraciones en el "consejo" anterior, voy a aclarar un poco de que va eso de la visibilidad de las variables. Y viene al caso porque a ms de uno le ha pasado que "se encuentra" atascado porque le da problemas el programilla con cosas "raras". Veamos las posibilidades que podemos tener al declarar las variables:

Globales:

Para usarlas en todo el proyecto. Cuando queramos que una variable sea "visible" a todo el proyecto en el que estamos trabajando, (es decir que podamos usar esa variable en cualquier sitio), debemos declararla como Pblica o Global en las declaraciones generales de un mdulo BAS.

Globales Para usarlas en todo el proyecto, pero poniendo el nombre del (Propiedades) Form en el que se han declarado delante de la variable, si queremos usarla fuera del propio form. A estas variables se las considera Propiedades del Formulario. Esto es parecido a una variable declarada en un mdulo BAS, pero a diferencia de la anterior, debemos especificar el form al que pertenece y la vida de esta variable ser mientras exista el form en el que se ha declarado. Nivel de Mdulo: Para usarlas slo en un mdulo o form determinado. Las variables declaradas en la parte de las declaraciones de un mdulo, (BAS, FRM o CLS) con el atributo de Private o simplemente con DIM, se consideran locales al mdulo y slo sern visibles dentro de ese mdulo. Nivel de Para usarlas slo en un procedimiento. Procedimiento: Las que se declaren dentro de un procedimiento (SUB, FUNCTION o PROPERTY) slo sern visibles dentro de ese procedimiento. Hay que tener en cuenta que cuando se declara una variable en un nivel inferior, esta declaracin "prevalece" sobre cualquier otra, de forma que usar la que tenga ms cercana a donde se usa, al menos as ocurre con los procedimientos, en caso de variables a nivel de mdulo con respecto a las globales, no lo he probado... Veamos un ejemplo: Tenemos un mdulo BAS con esta declaracin: Option Explicit Global sVar1 As String En el Form_Load: sVar1= "en Form_Load" 'Mostramos el contenido de sVar1 MsgBox "El contenido de sVar1 es: " & sVar1 En un procedimiento tenemos: Private Sub Form_Click() Dim sVar1 As String sVar1 = "en Procedimiento" 'Mostramos el contenido de sVar1 MsgBox "El contenido de sVar1 es: " & sVar1 End Sub

Bien prueba este ejemplo y vers lo que ocurre. Para comprobarlo, haz CLICK en el form.

11.- El Tipo de las variables por defecto (24/Mar) En los tiempos del GWBASIC y otros Basics, antes del Visual Basic versin 2.0, las variables que no se definan de un tipo en especial, eran variables tipo Single. A partir de la versin 2.0 de VB se introdujo el tipo Variant y de esta forma si la variable no se declara de un tipo en especial, pues VB entiende que son del tipo Variant. En aquellos tiempos (los del Basic normal), era una costumbre ms o menos extendida, al menos para los que nos gustaba "ahorrar" memoria y ganar en velocidad, poner al principio del mdulo la siguiente instruccin: Defint A-Z, con ella declarabamos todas las variables sin un tipo especfico como variables INTEGER. Pues hoy he recibido un mail de Harvey Triana para que lo recomendara a los "novatos" y as lo hago. Si sueles usar, por regla general, variables de tipo entero, acostumbrate a incluir al principio de cada mdulo (Frm, Bas o Cls) las siguientes declaraciones: Option Explicit Defint A-Z De esta forma te obligar a declarar todas las variables (Option Explicit) y a las que no le des un tipo en particular, las tomar por Integer (Defint A-Z). OJO CON ESTO! si ests acostumbrado a que las variables por defecto sean Variant, sobre todo en las que declares como opcionales, que siempre deben ser Variant, al menos en la versin 4, ya que VB5 permite especificar el tipo.

12.- Listados de ejemplo para crear un ToolBar, ToolTips y efectos 3D para VB3 (8/Abr) Estos listados son un ejemplo para crear un ToolBar, incluye tambin la rutina para hacer el efecto de los ToolTips y hacer el efecto 3D en cualquier control. Estos listados sn vlidos para VB3 (y creo que VB2) Listados de ejemplo para crear el ToolBar, los ToolTips y ejemplo para efectos 3D (tb_vb3.zip 5.67 KB) Aclaracin: El hecho de que est aqu es porque en su da puse en este apartado lo de los ToolTips.

13.- Evitar que una aplicacin se cargue ms de una vez (VB2 y posteriores) (6/Jul) Rectificacin (11/Jul): Por error u omisin... vamos, por despiste, indicaba que el PrevInstance no serva para VB3 y si que funciona; es con el VB2 (y anterior?) con el que hay que usar el API para impedir que una aplicacin se cargue ms de una vez. Gracias a Arturo Tena por la aclaracin en las NEWS, pero es que algunas veces no prueba uno todo lo que dice... Algunas veces nos puede interesar que nuestra aplicacin slo se ejecute una vez, pues bien, con el VB3 y superiores eso es fcil, ya que existe una instruccin que

ahora veremos, pero en VB2, la cosa no es tan sencilla, aqu te muestro cmo hacerlo para todas las versiones. Para VB3 y posteriores usa la propiedad PrevInstance del objeto App. Slo tienes que poner esto en el Form_Load: If App.PrevInstance Then End End If En el caso de VB2, podemos usar unas funciones del API de Windows: GetModuleHandle y GetModuleUsage. Donde dice "nombre.exe" debers usar el nombre que tenga la aplicacin. Un aviso: Esto slo debes usarlo en Win3.x aunque en Win95 funcione... debes usarlo con prudencia... 'Poner estas declaraciones en un mdulo BAS Declare Function GetModuleHandle Lib "Kernel" (ByVal lpModuleName As String) As Integer Declare Function GetModuleUsage Lib "Kernel" (ByVal hModule As Integer) As Integer 'En el Form de inicio, poner esto en el Form_Load: Private Sub Form_Load() Dim hModule As Integer Dim numCopias As Integer hModule = GetModuleHandle("nombre.exe") numCopias = GetModuleUsage(hModule) If numCopias > 1 Then End End If '... End Sub 14.- Evitar los eventos en cascada... te suena OUT OF STACK SPACE? (9/Jul) S que no es cosa nueva, incluso el 4 truco de esta seccin trata de lo mismo, pero al parecer alguno no captasteis la intencin de la solucin all presentada. Aprovecho una de las consultas hechas para poner la respuesta, que de camino sirve un poco de explicacin. All va... Y si an no te enteras... pregunta, pregunta. > una: que es el error "cascada de eventos" Esto es un error que nos suele pasar a todos cuando empezamos con el VB, ya que el Windows est enfocado en los eventos, es decir que si pulsas sobre un TextBox con el ratn, se producen una serie de eventos, si pulsas una tecla en un control se producen otra serie de eventos... total que hasta si te rascas la cabeza se produce un evento... y si mientras ests escribiendo en un TextBox haces algo que obligue a que se produzca ese evento de nuevo... produces una cascada de eventos... Por ejemplo prueba esto: Private Sub Text1_Change() Dim sTmp As String sTmp = Text1.Text

Text1.Text= sTmp & "a" sTmp ="" End Sub Esto te producir un error de que no hay espacio en la pila o algo similar, ya que cada vez que se produce el "evento" Change, haces que cambie el contenido del Text, por lo que vuelve a producirse un nuevo evento change, sin que termine el anterior... y el VB se pone "malo" Solucin: evitar este tipo de cosas... (elemental) Cmo? con trucos y variables estticas, por ejemplo: Private Sub Text1_Change() Dim sTmp As String Static YaEstoy As Integer If YaEstoy Then Exit Sub YaEstoy = TRUE sTmp = Text1.Text Text1.Text= sTmp & "a" sTmp ="" YaEstoy = FALSE End Sub Al crear una variable esttica mantiene el valor entre llamadas. La primera vez que entra en el evento, al valer CERO (FALSE), pasa por alto el IF YAESTOY THEN... Por tanto se pasa al resto del cdigo y se asigna un valor TRUE Ahora al asignar el valor al Text1, se produce el evento change, pero cuando entra por segunda vez, se encuentra con que la condicin es cierta, por tanto se sale sin continuar... Una vez que termina el primer evento, el valor YaEstoy vuelve a ponerse a CERO para que en el siguiente se vuelva a procesar lo que haya que procesar... Novato = Al_que_empieza (24/Ene) Que nadie se mosquee. no es por faltar al respeto; pero el que se inicia, siempre es un novato; aunque algunos que llevamos algunos aos, puede que sepamos menos, pero... as es la vida, los novatos son los que se inician y los veteranos, aunque sepan igual o menos, son lo que llevan ms tiempo... 8-) En fin, esta pgina va dedicada a aquellos que necesitan saberlo todo desde el principio. A ver si os ponis pronto al dia en la programacin en VB. Por qu te das por aludido Manolo? 8-))))

Você também pode gostar