lunes, enero 21, 2013

Una alternativa al control Calendario en Excel 2010 – Monthview

Como mencionamos en el pasado el control Calendar (mscal.ocx) fue removido del paquete Office 2010. Esto genera problemas en aplicaciones y modelos de Excel que fueron desarrollados en versiones anteriores y queremos usarla en Excel 2010.

En la nota mencionada sugerimos tres alternativas posibles: usar el Data Picker, el complemento desarrollado por Sam Radakovitz o descargar e instalar el control. Esta última alternativa implica tener que registrar el control para poder usarlo. El problema con esta última solución es que no podemos registrar el control en Windows 8.

Para los que, como a mí, no les gusta el Data Picker, existe la posibilidad de usar el control Monthview (para las versiones 2007 y 2010 de Excel).

¿Cuándo queremos usar el control? Cuando necesitamos asegurarnos que el usuario ingrese fechas en el rango y en el formato necesarios, librándolo al mismo tiempo de tener que ingresar los separadores (”/” o “-“) de la fecha.

En esta nota mostraré como implementar un modelo sencillo: al elegir una celda determinada aparece el calendario y al elegir una fecha en él, ésta aparece en la celda y el calendario desaparece



Paso 1 – Crear un Userform

En el editor de VB (Alt+F11) creamos un userform que contendrá el control



Cambiamos la propiedad Name a “UfFecha” (no es indispensable pero es una buena práctica) y cambiamos Caption a “Elija una fecha”.

Paso 2 - Insertar el control Monthview

Apuntamos al cuadro ToolBox y abrimos el menú contextual con un clic en el botón derecho del mouse



Elegimos al opción Aditional Controls y marcamos el Microsoft Monthview Control



Este aparecerá ahora en la parte inferior del cuadro ToolBox. Con un clic lo seleccionamos y lo insertamos en el Userform



Paso 3 – Definiciones del control

Al seleccionar el control podemos ver el cuadro de propiedades en el editor. Esto nos permite definir su apariencia y comportamiento. Por ejemplo, definimos la propiedad ShowTodat como True, de manera que al abrirse el control muestre la fecha corriente.



Paso 4 – Códigos de los controles.

Ahora necesitamos escribir los códigos que manejen el uso del control. En nuestro modelo queremos que cuando el usuario seleccione la celda C3 (hemos creado un nombre definido que se refiere a la celda: “clFecha”) aparezca el calendario. Esto lo hacemos usando el evento Worksheet_SelectionChange de la hoja

Private Sub Worksheet_SelectionChange(ByVal Target As Range)

    If Union(Target, Range("clFecha")).Address = Range("clFecha").Address Then
        ufFecha.Show
    End If

End Sub


El código lo ponemos en el módulo de la hoja (abrimos el módulo de la hoja con la opción Ver Código del menú contextual que se abre al hacer clic derecho en la pestaña de la hoja o con un doble clic sobre el icono de la hoja en el editor de Vb)



Ahora necesitamos un código para pasar el valor elegido en el calendario a la celda

Private Sub MonthView1_DateClick(ByVal DateClicked As Date)
    ActiveCell.Value = DateClicked
    Unload ufFecha
End Sub


Este código va en el módulo del Userform que se abre haciendo un doble clic en el Userform (o apretando Ctrl+Tab hasta llegar al módulo)

Para que el control aparezca junto a la celda de la fecha y no en el centro de la hoja, agregamos el evento UserForm_Activate

Private Sub UserForm_Activate()
    With Me
        .Left = ActiveCell.Left + ActiveCell.Width + 25
        .Top = ActiveCell.Top + 150
    End With
End Sub


El modulo del Userform se verá así



Un tip para el final: si hacemos unn clic sobrel el nombre del mes en el control aparecerán unas flechas que nos permiten saltar de año en año



El archivo con el ejemplo puede descargarse aquí.

44 comentarios:

  1. Magaso!nuevamente otro Post de Genial!

    ResponderBorrar
  2. Mi estimado Jorge esto es muy bueno, podemos tambien cambiar de año, pero NO podemos cambiar de mes para seleccionar el dia que necesitamos. Estoy en lo correcto?

    ResponderBorrar
  3. Si se puede. Los meses se cambian con las flechas (triángulos) a los lados de la casilla mes/año.

    ResponderBorrar
  4. Gracias Jorge,
    Una única cuestión:
    ¿Si queremos que el calendario aparezca en todas las celdas de una misma columna cómo deberiamos modificar el código actual?.
    Gracias por adelantado,
    Héctor.

    ResponderBorrar
  5. Hola Héctor,
    en el evento hay que cambiar la referencia. Por ejemplo, podemos cambiar el rango al que se refiere el nombre definido "clFecha" a toda la columna o cambiar la sentencia del evento a

    If Target.Column = 3 Then...

    Esta hace que el evento se dispare cada vez que se elija una celda de la columna C.

    ResponderBorrar
  6. no me aparece el microsoft monthview 6.0 como lo agrego en excel 2010

    ResponderBorrar
  7. Siguiendo las mismas instrucciones que pongo en la nota anterior sobre el uso de calendario. El archivo del control es MSCOMCT2.OCX y lo puedes descargar aquí

    ResponderBorrar
  8. Es posible poder validar la fecha en el calendario, que este no sea menor a cuerta fecha por ejempl

    ResponderBorrar
  9. Se puede hacer estableciendo los valores de las porpiedades MaxDate y MinDate del control.

    ResponderBorrar
  10. hola he visto tu tutorial muy bueno!!

    me gustaria saber si es posible que teniendo dos userform cada uno con un textbox llame al control que esta en un userform independiente e inserte la fecha al textbox desde donde se activo por ejemplo

    en userform1 esta el textbox1 llama al control e inserta la fecha
    pero si desde el userform2 que esta un textbox1 tambien llama al mismo control e inserta la fecha es posible?como se haria?

    ResponderBorrar
  11. Fofo, no me ued clara tu consulta. Veamos, el TextBox está siempre en una UserForm y no al revés.
    Ahora, el calendario es un control que está en un userform, así que tendrías un calendario en Userform1 y otro en Userform2. Lo cual no es inngpun problema ya que todo lo que hacemos con el calendario es determinar la fecha.
    Si querés, podés crear un userform que contiene el control calendario y éste es llamado por los otros dos userform (pero me parece un complicaciónn innecesaria).

    ResponderBorrar
  12. Excelente tutorial,

    Tengo una pregunta, si quiero que el calendario aparezca en un rango de celdas específico, como se modifica el código?

    Muchas gracias!

    ResponderBorrar
  13. Hola Luis,
    fijate en la nota donde muestro el código del evento Worksheet_SelectionChange.
    La sentencia
    Union(Target, Range("clFecha")).Address = Range("clFecha").Address
    determina las celda que al ser activadas disparan el código. El rango Range("clFecha") se refiere al rango definido en el nombre clFecha. En nuestro ejemplo este nombre se refiere a una celda, pero podés definirlo de manera que se refiera a una colección de celdas. También podés poner el rango de celdas en forma explícita, opr ejemplo:

    Union(Target, Range("A2:A100")).Address = Range("A2:A100").Address

    ResponderBorrar
  14. no me funsiona el data pic ni el mont view mi office es 2010 me dice element no found

    que hago

    ResponderBorrar
  15. Tienes que descargar el archivo del control e instalarlo como muestro en esta nota

    ResponderBorrar
  16. Buen día, esto no se aplica a Excel 2013?
    Pues estuve probando y no esta el control ActiveX para habilitarlo.

    ResponderBorrar
  17. esta nota explico cómo usar los controles ActiveX en Excel 2003.

    ResponderBorrar
  18. Buen tarde
    Les solicito de su apoyo, ya que estoy aprendiendo a programar en VBA, estoy haciendo un ejercicioy en el cual estoy creando un formulario de captura de datosen donde en mi primer columna en mi editor de VBA estoy capturando una fecha, pero descubri que puedo usar en Microsoft Monthview para insertar las fechas que estoy capturando, este es mi codigo en mi modulo de trabajo

    Sub Ingresarinformacion()

    Dim n As Long
    Hoja1.Select

    n = 4

    Do While (Cells(n, 1) <> Empty Or Cells(n, 2) <> Empty Or Cells(n, 3) <> Empty Or Cells(n, 4) <> Empty Or Cells(n, 5) <> Empty Or Cells(n, 6) <> Empty Or Cells(n, 7) <> Empty Or Cells(n, 8) <> Empty Or Cells(n, 9) <> Empty Or Cells(n, 10) <> Empty Or Cells(n, 11) <> Empty Or Cells(n, 12) <> Empty)
    n = n + 1
    Loop

    If (frmingresodatos.rbtHombre.Value = True Or frmingresodatos.rbtMujer.Value = True) Then

    Cells(n, 1).Value = frmingresodatos.txtFecha.Text
    Cells(n, 2).Value = frmingresodatos.txtPaterno.Text
    Cells(n, 3).Value = frmingresodatos.txtMaterno.Text
    Cells(n, 4).Value = frmingresodatos.txtNombre.Text
    Cells(n, 5).Value = frmingresodatos.txtEdad.Text
    Cells(n, 6).Value = frmingresodatos.txtDia1.Text
    Cells(n, 7).Value = frmingresodatos.txtTelefono.Text
    Cells(n, 8).Value = frmingresodatos.txtDia2.Text
    Cells(n, 9).Value = frmingresodatos.txtAvisual.Text
    Cells(n, 10).Value = frmingresodatos.txtPio.Text
    Cells(n, 11).Value = frmingresodatos.txtCosto.Text

    If frmingresodatos.rbtHombre.Value = True Then
    Cells(n, 12).Value = "Hombre"
    frmingresodatos.rbtHombre.Value = False
    Else
    If frmingresodatos.rbtMujer.Value = True Then
    Cells(n, 12).Value = "Mujer"
    frmingresodatos.rbtMujer.Value = False
    End If
    End If

    frmingresodatos.txtFecha.Text = ""
    frmingresodatos.txtPaterno.Text = ""
    frmingresodatos.txtMaterno.Text = ""
    frmingresodatos.txtNombre.Text = ""
    frmingresodatos.txtEdad.Text = ""
    frmingresodatos.txtDia1.Text = ""
    frmingresodatos.txtTelefono.Text = ""
    frmingresodatos.txtDia2.Text = ""
    frmingresodatos.txtAvisual = ""
    frmingresodatos.txtPio = ""
    frmingresodatos.txtCosto = ""

    MsgBox "Ingresado un registro con èxito en la fila numero " & n & ".", vbInformation + vbOKOnly, "información de registro."

    frmingresodatos.txtFecha.SetFocus

    Else

    MsgBox "Debe selecionar una opcion." & vbCrLf & "Para el trabajo actual", vbCritical + vbOKOnly, "Alerta..."

    End If










    End Sub
    y quiero dustituir el txtFecha para poder usar el Monthview, agradezco de antemano su ayuda.

    Saludos

    ResponderBorrar
  19. Tienes que crear un segundo Userform que contenga el calendario; este userform es llamado desde el primer Userform (frmingresodatos), el usuario ingresa la fecha, y esta pasa a la celda.

    ResponderBorrar
  20. MUCHAS GRACIAS POR EL TIP Y LA AYUDA!!! SALUDOS

    ResponderBorrar
  21. Un gran tutorial sin duda, lo adapte para usarlo en un UserForm y funciono genial, gracias.
    Solo tengo una pregunta, como hacer para que cada que habra el calendario me aparesca el mes y la fecha actual, por que aun que lo marca con rojo, sigue abriendo con el valor que le pusiste en el mes de julio.

    ResponderBorrar
  22. En el cpodigo del evento UserForm_Activate tienes que agregar la línea en negrita

    Private Sub UserForm_Activate()
    With Me
    .Left = ActiveCell.Left + ActiveCell.Width + 25
    .Top = ActiveCell.Top + 150
    .MonthView1.Value = Date
    End With
    End Sub

    ResponderBorrar
  23. HOLAA SUPER BUENO EL POST, PERO HAY FORMA DE QUE CUANDO SE ABRA, LO HAGA EN EL MES ACTUAL

    ResponderBorrar
  24. Fijate en mi comentario del 28 de agosto

    ResponderBorrar
  25. Hola Jorge,

    funciona perfecto pero tengo un problema. Lo tengo puesto para que me salga en toda una columna. Pero conforme voy bajando filas, la ventana del calendario se me abre cada vez mas abajo hasta terminar por desaparecer de la pantalla y no poder utilizarla. ¿Alguna solución?

    Saludos y gracias.

    ResponderBorrar
  26. Te sugiero eliminar el evento UserForm_Activate y definir la propiedad StartUpPosition del Userform a "Centrar en Pantalla".
    ¿Qué versión de Excel estás usando?

    ResponderBorrar
  27. Al tratar de colocarlo en el form me da un mensaje de "no se encuentra el elemento"

    ResponderBorrar
  28. Fijaate en mi comentario del 5 de marzo. Si no tenés el control se puede descargar e instalar.

    ResponderBorrar
  29. buen día, alguna sugerencia para el sig. error?

    ResponderBorrar
  30. Hola Jorge, tengo una pregunta: en la nota anterior afirmas que este control solo se puede utilizar en la versión de 32 bits de Excel 2010, ¿Hay alguna forma de que funcione en la de 64 bits?
    Gracias!!

    ResponderBorrar
  31. No, hasta donde dan mis conocimientos. Buscando en Google puedes encontrar alguna soluciones como ésta.

    ResponderBorrar
  32. Jorge Buen dia Hace mucho tiempo no compartia con usted pero ahoratengo el siguiente problema

    Si puede ayudarme se lo agradeciria.
    es sobre fechas

    en la celda a1 digito la fecha (cualquiera),año, mes, dia,ejemplo (2015,09,30) necesito que en las celdas a5, (2015,10,31) a10,(2015,11,31), a15, (2015,12,31),a20 (2016,01,31), se continue la secuencia de fechas con el ultimo dia habil, es posible porfa ayudeme, no he podido

    atentamente

    Hector

    ResponderBorrar
  33. Héctor,

    tenés que usar la función FIN.MES. EN la celda A5 usás =FIN.MES(A1,1); en la celda A10 =FIN.MES(A5,1); en la elda A15 =FIN.MES(A10,1) y así sucesivamente.
    No me queda claro si te referís al último día del mes (que es lo que dá la función FIN.MES) o al último día hábil dado que el último día del mes puede ser feriado.

    ResponderBorrar
  34. Hola amigos, hice todo lo que mencionan.
    Si embargo me lleve una copia del archivo en un pendrive a otro pc y no hay nada de lo realizado.

    Pregunto se pierde todo?

    Adicional, intente realizar la operación en el otro PC y cuando intento repetir la operación, cuando hago clic en "Controladores Adicionales" no hace pasa nada.

    Agradecido de antemano,

    Saludos

    ResponderBorrar
  35. Hola, tenés que asegurarte que el control Monthview esté instalado en el PC. Fijate en los comentarios del 04/03/2013 (de Ignacio Javier y mi respuesta).

    ResponderBorrar
  36. Hola, gracias por tu tutorial, me ayudó mucho, pero quisiera saber si es posible colocar en distintas celdas, por ejemplo coloco un calendario en la celda A3 y quiero colocar en la C3 y en la D3 , es posible?, espero me pueda ayudar. Gracias

    ResponderBorrar
  37. Hola, fijate en el paso 4. Allí definimos las celdas que al seleccionarlas aparecerá el calendario. En el ejemplo hay una única celda (definida en el nombre clFecha). Para que aparezca en otras celdas hay que cambiar la definición del nombre "clFecha" para que se refiera también a las otras celdas.

    ResponderBorrar
  38. Hola buen día, estoy aprendiendo y haciendo mi primer trabajo en VBA. Te cuento, debo controlar fechas de documentos, para ello inserte en Excel 3 controles DTPicker asignando que estas fechas son de EMISION, RECEPCION y PROCESO. Y quería consultar como se podría controlar las fechas que se seleccionan del calendario a fin que no existan errores. Por ejemplo:
    i) ninguna fecha puede ser posterior al día de hoy.
    ii) PROCESO no puede ser anterior a RECEPCION.
    iii) RECEPCION y PROCESO no pueden ser anteriores a EMISION

    Espero me puedan aconsejar sobre el mejor modo de hacer este trabajo.
    Saludos

    ResponderBorrar
  39. Hola David, como estás haciendo tus primeros pasos en Vba no puedo orientarte en el marco de un comentario.
    En términos generales puedo decirte que para cada objeto con el DTPicker podés definir uno o más eventos (fijate en mis notas sobre eventos) de manera que al activarlo corra un código que controle los valores aceptables en cada entorno.
    Te invito a ponerte en contacto conmigo por mail privado (fijate en el enlace Ayuda, en la parte superior de blog).

    ResponderBorrar
  40. Excelente artículo. Me ha sido de gran ayuda. Que bueno tener una tutoría de este nivel y gratis!!

    ResponderBorrar
  41. NO ME APARECE LA PESTAÑA TOOLBOX

    ResponderBorrar
  42. En el editor de VB, abrir el menu Tools y marcar Toolbox.

    ResponderBorrar

Nota: sólo los miembros de este blog pueden publicar comentarios.