martes, 26 de marzo de 2013

Declaración de variables en VBA para Excel (II)


Si el lector ya está familiarizado con el concepto de variable en el primer artículo de la serie ¿Qué es una variable en VBA para Excel?  y también ha entendido el artículo Declaración de variables en VBA para Excel (I) , podría disponerse a leer este artículo que a buen seguro, le resultará interesante.

En el anterior post hablábamos de variables que representaban a valores (ya sean fechas, números enteros, decimales, etc.). En este artículo veremos las variables que representan a objetos (debemos saber que en VBA llamamos objetos a cualquier elemento de Excel como hojas, celdas, gráficos, formas, tablas, etc.).



Declarar variables de objeto está, si cabe, más justificado que declarar variables de valores, puesto que el ahorro en tiempo de escritura de código, en tiempo de ejecución del mismo, así como la organización y orden conseguidos en la estructura del procedimiento o macro, son espectaculares.

¿Cómo declarar una variable de objeto?

La declaración de una variable de objeto sería:

Dim Variable As TipoObjeto

Que significa:

Establecer Variable como TipoDeObjeto

Una vez declarada la variable, se le puede asignar un tipo de objeto, pero en este caso (a diferencia de las variables asignadas a valores) debemos comenzar la línea con la palabra Set , como en esta macro:

Sub VariableObjeto()

     Dim MiCelda As Range

     Set MiCelda = Worksheets("Hoja1").Range("A1")

     MiCelda.Value = 4560
     MiCelda.Interior.Color = RGB(166, 210, 241)
     MiCelda.Font.Italic = True
     MiCelda.Font.Bold = True

End Sub

La macro anterior declara la variable "MiCelda" como un rango, después asigna la variable a la celda A1 y posteriormente (en las últimas líneas) realiza varias acciones con la celda, nombrándola en todas las líneas siempre con el nombre de variable declarado al principio (en una línea inserta el valor 4560, en otra línea proporciona el color azul claro, en otra aplica cursiva y en la última aplica negrita).

Si no hubiéramos utilizado una variable de objeto , el código de las 3 líneas que modifican la celda A1 podría  haber sido así de largo:

Sub VariableObjeto()

     Worksheets("Hoja1").Range("A1")4560
     Worksheets("Hoja1").Range("A1").Interior.Color = RGB(166, 210, 241)
     Worksheets("Hoja1").Range("A1").Font.Italic = True
     Worksheets("Hoja1").Range("A1").Font.Bold= True

End Sub

El primer código se ejecuta de forma más rápida que este último, porque Visual Basic no tiene que buscar una y otra vez la ruta de la celda A1. Aunque aun podríamos perfeccionarlo (en cuanto a eficiencia) de la siguiente forma:

Sub VariableObjeto()

     Dim MiCelda As Range

     Set MiCelda = Worksheets("Hoja1").Range("A1")

     With MiCelda

          .Value = 4560
          .Interior.Color = RGB(166, 210, 241)
          .Font.Italic = True
          .Font.Bold = True

     End With

End Sub

Siendo este el código más corto y rápido de todos.

¿Qué tipos de objetos pueden establecerse como variables?

En el ejemplo anterior, el tipo de objeto era Range, puesto que se quería asignar la variable a una celda. También sería Range si quisiéramos asignarla a columnas, filas, etc.

En el caso de querer asignar variables a un tipo de objeto "Hoja", deberíamos poner Worksheet . Otro ejemplo podría ser ListObject para referirnos a objetos tipo "Tabla de Excel". El usuario puede elegir el tipo de objeto al que refererirse en la lista que el editor de VBA ofrece mientras se escribre:


Otras utilidades

Declarar variables de objeto no sirve únicamente para acortar el código y hacerlo más eficiente, un ejemplo lo tenemos en el siguiente código, que utiliza una variable de objeto para que Excel vaya recorriendo una serie de hojas hasta que encuentra una que se llama "HojaClave" y la seleccione.

Sub VariableObjeto()

     Dim MiHoja As Worksheet

     For Each MiHoja In Worksheets

          If MiHoja.Name = "HojaClave" Then
               MiHoja.Select
          End If

     Next MiHoja

End Sub

Después de declarar la variable de objeto, utilizamos un bucle For Each - Next y dentro de él, utilizamos un condicional If - End If. Declarar una variable nos ha evitado tener que nombrar mediante código cada una de todas las hojas que tengamos para buscar la que deseamos.

Si tradujéramos el código a lenguaje castellano, sería:

Iniciamos Subrutina VariableObjeto()

     Establezco MiHoja como TipoDeObjetoHojaDeExcel

     Por Cada MiHoja En LaColecciónDeHojasDeMiLibro

          Si MiHoja.Nombre = "HojaClave" Entonces
               MiHoja.Seleccionada
          FinalDelCondicionalSI

     ExaminarSiguiente MiHoja

End Sub


Recorrer hojas o celdas en busca de una que cumpla con una condición, es una de las utilidades mayores de la declaración de variables de objeto, puesto que permite utilizarse con bucles y condicionales que detectan si se cumple la condición que queremos y pueden actuar.

Si desea llevar a la práctica todo lo que le hemos ofrecido en este artículo, puede asistir a nuestros cursos prácticos de Excel o puede solicitarlos in company:








21 comentarios:

  1. Muchísimas gracias... me sirvió de mucho... estaba buscando esto por largo rato

    ResponderEliminar
  2. Excelente; necesito una variación ... Si esta variable proviene de otro libro diferente, no del mismo libro?

    ResponderEliminar
    Respuestas
    1. Se puede declarar en cualquier momento, pero a la hora de asignarle un valor, si el libro donde está el valor que nos interesa no es el libro que está activo (para VBA), debemos hacer referencia completa a dicho libro. Por ejemplo, la siguiente sería una asignación de un valor que está en un libro NO activo, en una variable llamada LastRowColA :
      LastRowColA = Workbooks(BalName).Sheets(1).Cells(65536, 1).End(xlUp).Row

      Saludos.

      Eliminar
  3. Muchas gracias, me ha servido para enriquecer mi aprendizaje.
    Un saludo

    ResponderEliminar
  4. Muchas gracias, me ha servido para aprender este tipo de variables.
    Un saludo

    ResponderEliminar
  5. Buenas noches,

    Ya he creado un programita en exel si declarar las variables, lo intente, pero no me funciono, podrías poner ejercicios prácticos donde también se muestre la hoja de calculo en cuestion.

    Mi correro: edwin.vargas.javier@hotmail.com

    ResponderEliminar
  6. hola
    siquiero que el valor que le estoy dando a la celda esté en una variable. Ejemplo: MiCelda.Interior.Color = RGB(166, 210, 241)
    var = Worksheets("Hoja1").Range("A11").Value
    Selection.Interior.Color = var.Value

    ResponderEliminar
  7. Hola

    No se de macros en excel y quiero hacer algo sencillo,pero no he podido. ¿me podrías ayudar? el inconveniente es que quiero asignar el valor del color de la celda desde otra celda que tiene el RGB, pero al pasar el value al Selection.Interior.Color se genera un error.
    var = Worksheets("Hoja1").Range("A11").Value
    Selection.Interior.Color = var.Value

    Gracias por tu ayuda.

    Saludos.

    ResponderEliminar
    Respuestas
    1. En la variable "var" de la primera línea de código estás introduciendo el valor de una celda (no el código RGB del color de la celda).
      Después, en la segunda línea estas intentando que el código de color de la celda seleccionada sea el valor de una celda (valor de la variable "var") y eso no es posible, puesto que debería ser ...=RGB(x,y,z)

      Eliminar
  8. Una pregunta esto es correcto?
    Sub LIMPIAR()
    Application.ScreenUpdating = False

    Dim wb As Workbook: Set wb = ThisWorkbook
    Dim Res As Worksheet: Set Res = wb.Sheets("RESUMEN")

    wb.Sheets(Res).Range(Range("A4"), Range("A4").End(xlToRight)).Copy
    wb.sheets(Res).Range("A47511").PasteSpecial Paste:=xlPasteValues

    ResponderEliminar
    Respuestas
    1. No es correcto porque a la variable de objeto Res le asignas una ruta (wb.Sheets("RESUMEN")) y luego vuelves a utilizar parte de la ruta.
      Debería ser:
      Res.Range(Range("A4"), Range("A4").End(xlToRight)).Copy
      Res.Range("A47511").PasteSpecial Paste:=xlPasteValues
      Saludos

      Eliminar
  9. Hola qué tal disculpa una pregunta, aprovechando que el tema es sobre ahí similar que necesito hacer.
    Lo que quiero hacer es que sea más rápido y eficiente un proyecto, para ello por ejemplo puedo declarar variables públicas en un módulo y así utilizarlos en todos los procedimientos que haga, estoy en lo correcto? ( Te pregunto porque soy nuevo en esto?
    Ahora, si declaro por ejemplo como variable objeto "C", para luego referenciarlo como una hoja con la instrucción "Set", mi pregunta es cómo puedo hacer una sola referencia del tipo "Set C=Sheets("Hoja1")" para todos los procedimientos sin tener que escribirlo en cada uno? Se entiende?
    Desde ya muchas gracias!!!

    ResponderEliminar
    Respuestas
    1. Este comentario ha sido eliminado por el autor.

      Eliminar
    2. Podrías establecer el valor de una "variable objeto pública" haciendo que la instrucción Set esté en un procedimiento que se ejecute nada más abrir el libro (Thisworkbook / Open).
      En teoría y en principio esto funciona, pero vas a tener muchos problemas, porque la variable se "vacía" cada vez que hay alguna interrupción (error en tiempo de ejecución, por ejemplo) de código en cualquier parte del programa.
      También puedes tener problemas porque a veces, el valor necesitas establecerlo en un momento dado de la ejecución de tu aplicación... y no al prinicipio mediante Thisworkbook / Open.
      Yo lo he intentado a veces y en la práctica es problemático y he optado finalmente por dimensionarlas y establecerles el valor justo antes de necesitarlas.
      Saludos.

      Eliminar
    3. Ah ok entendí! Estuve probando algo similar a lo que me sugeris y la verdad que se complica osea creo que no es lo más conveniente cómo decís, muchas gracias por responder!! Saludos!!

      Eliminar
  10. Un pregunta es posible referenciar con variables tanto libro así como sus hoja(s) ejemplo:
    Sub copiarlibrosabiertos()

    Dim L1 As Workbook: Set L1 = Workbooks("06 MACRO DE EGRESOS DIVERSOS ATITALAQUIA 2017.XLS")
    Dim h1 As Sheets:Set h1 = Sheets("FACTURAS")

    Dim L2 As Workbook: Set L2 = Workbooks("DESTINO.xlsm")
    Dim h2 As Worksheet: Set h2 = Sheets("HOJA1")


    L1.h1.Range("a1:j100").Copy
    L2.h2.Range("a1").PasteSpecial xlPasteValues

    End Sub
    se puede establecer variable tanto para libro como para hoja al mismo tiempo o solo puedo establecer una variable ya sea para libro u Hoja?
    Gracias

    ResponderEliminar
    Respuestas
    1. Buenos días.
      Se puede hacer, pero es más conveniente dividirlo como lo haces tu.
      Saludos.

      Eliminar
  11. Lo probé pero no me funciona solo me funciona de la siguiente manera:
    L1.sheets("Facturas").Range("a1:j100").Copy

    o bien
    Workbooks("06 MACRO DE EGRESOS DIVERSOS ATITALAQUIA 2017.XLS").h1.range("a1:j100").copy
    pero asi me marca error:
    L1.h1.Range("a1:j100").Copy y no entiendo por que, Saludos y Muchas gracias por su valioso tiempo

    ResponderEliminar