Una consulta mas, que proviene de
mi página en Facebook , de un nuevo y muy amable lector del blog: Juan Manuel Escobar Sanchez. La verdad que a este problema no me lo habían planteado nunca, como así tampoco nunca necesité utilizarlo en mis proyectos. Pero ahora que Juan Manuel lo dice... me viene perfecta su pregunta para, probablemente, solucionar otros problemas.
El tema es así: el necesita ingresar datos en una hoja bloqueada. Sí, tal cual lo leen, y ahí se presenta el nudo de la cuestión, ya que si tengo las celdas protegidas ¿como ingreso valores en ellas? Y las cosas se ponen peor: si el usuario puso algún dato... la hoja debe volver a bloquearse e impedir que dicho valor pueda ser modificado. Todo un desafío, el cual creo haber solucionado. Espero que así sea.
Generamos un ejemplo sencillo: armamos una tabla de 3 columnas, luego seleccionamos el rango que ocupa (excluyendo los encabezados) y en el cuadro de nombres le damos uno: "tabla" (sin comillas):
[+/-] Ver el resto / Ocultar
Ahora bien ¿como sigo? Me resulta un tanto difícil explicarlo, pero intentaré ir por partes. Como primer medida, apenas abrimos el libro, protegemos la hoja. Para ello usamos el evento "Workbook_Open()" (al abrir el libro):
le pasamos una contraseña, para que nuestros usuarios no puedan desprotegerla
Listo, nuestra hoja "tabla" tiene todas sus celdas bloqueadas. Dentro de dicha hoja tenemos al rango "tabla" (que vimos en la primer imagen del post), que es la matriz de celdas en donde se deben colocar los datos.
Utilizaré por primera vez en el blog una función de VBA muy poco conocida:
INTERSECT(Arg1 as range, Arg2 as range, Arg3 as range, ArgN as range)
Con esta función se pueden realizar muchas cosas, pero aquí la utilizaremos para su principal virtud: conocer una intersección. Ella me permitirá saber si una celda está o no dentro de un rango. Veamos un ejemplo:
El código de arriba dice lo siguiente: si la intersección de la celda actual (Target) es válida, entonces en un MsgBox alertame de ello. La sintaxis puede ser confusa, por que al principio niega (Not), pero si unimos bien sería If Not IsNothing (si no es "nada")... lo que equivale a decir: "si es".
Entonces, cuando hago click sobre alguna celda del rango G1:G5:
si seleccionamos alguna celda que se encuentre dentro del rango G1:G5, es decir que ambos rangos se "intersectan", aparecerá el mensaje.
Analizado lo anterior, veremos que es el punto clave de este ejercicio: recordemos que nuestros usuarios solo pueden modificar celdas que se encuentren dentro del rango "tabla". Y con INTERSECT() puedo determinar si la celda seleccionada está o no dentro de dicho rango.
Armamos un poco los pasos a seguir:
1) al abrir el libro, bloqueamos toda la hoja
2) cuando el usuario seleccione una celda:
3) corroborar que se encuentre dentro del rango "tabla"
4) ver que haya seleccionado una sola celda
5) que esa celda esté en blanco (no contenga ningún valor)
6) si se cumplen las condiciones del punto 3 al 5, desbloqueamos la hoja, para permitir el ingreso de
datos.
7) luego de cualquier cambio realizado, bloqueamos de nuevo la hoja.
Veamos en imágenes como va funcionando todo:
se abre el libro: vean que las barras de herramientas están de color gris, clara señal de que nuestra hoja se encuentra bloqueada.
Seleccionamos A2, que cumple todas las condiciones: está dentro del rango "tabla", es una sola celda y no contiene ningún valor:
observen como ahora las barras de herramientas recuperaron su color: la hoja está desprotegida, permitiendo el ingreso de datos.
Colocaremos un valor en A2 y presionamos "enter":
la macro nos permitió agregar el valor y cuando volvimos a seleccionar el rango... se bloqueó nuevamente la hoja, ya que A2 ahora tiene datos.
Si seleccionan cualquier celda sin valor del rango "tabla" la hoja se desprotege, permitiendo el ingreso de valores. Si, por el contrario, seleccionan cualquier celda fuera del rango tabla, o bien la celda ya tiene algún dato en su interior, la hoja se bloquea. El código que hace esto posible es el siguiente:
Private Sub Worksheet_Change(ByVal Target As Range)
'cada vez que se produce un cambio en la hoja, protejo
ProtegerHoja
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
'si la celda seleccionada está dentro del rango "tabla"
If Not Intersect(Target, Range("tabla")) Is Nothing Then
'si seleccionó solo una celda
If Target.Cells.Count = 1 Then
'si esa celda está en blanco:
If Target.Value = "" Then
DesprotegerHoja
ElseIf Target.Value <> "" Then
'si la celda tiene un valor, protejo
ProtegerHoja
End If
Else
'si selecciona un area mayor a una sola celda,
'protejo
ProtegerHoja
End If
Else
'si la celda seleccionada no se encuentra dentro del
'rango "tabla", protejo
ProtegerHoja
End If
End Sub
Sub ProtegerHoja()
'aca va la contraseña que deseen colocar:
ActiveSheet.Protect Password:="locked"
End Sub
Sub DesprotegerHoja()
ActiveSheet.Unprotect Password:="locked"
End Sub
Otra forma posible sería llamar a un formulario cada vez que se seleccione una celda del rango "tabla". El usuario introduciría datos en el formulario, desprotegemos la hoja, colocamos el dato en la celda y la protegemos nuevamente, descargando al final el formulario de la pantalla.
Vos me dirás Juan Manuel si este ejemplo te fué de utilidad, cualquier cosa probamos con el UserForm a ver si te sirve mas. Un abrazo y gracias por tus palabras.
Link al archivo.
muy util. excelente!!!
ResponderEliminargracias AnyMa. anduve dando unas vueltas por tu blog, el cual lo agregué al mío (http://ligalogica.blogspot.com/), y estoy con el tema ese de tu nuevo post. ¿¿¿ como se hace para deducir esas cosas ??? jaja
ResponderEliminar