Saber el color de una celda con formato condicional

Tengo una hoja excel con una serie de celdas con formatos condicionales, de tal forma que si ocurre algo que es un error, la celda se colorea en ROJO. Al ser la hoja muy grande, había pensado hacer una macro que revisara toda la hoja en el evento activate, y me saltara un mensajebox avisándome que hay algún problema.
Mi problema es que al preguntar por el color con la propiedad "Interior.ColorIndex", aunque el formato condicional lo ha coloreado en rojo, esa propiedad no detecta que ha cambiado el color.
Si utilizo FormatConditions(y). Interior. ColorIndex, tampoco vale, ya que esto pregunta por el color de la condición, independientemente de si se cumple o no se cumple la fórmula.
En fin. Le agradecería muchísimo que me ayudara. Pensaba que era fácil lo que yo quería, pero no tengo conocimientos de vba.
Gracias por todo y un saludo, David.
{"lat":40.4074835579241,"lng":-3.702392578125}

2 Respuestas

Respuesta
1
Pues precisamente no es muy sencillo lo que necesitás, a mi me pasó algo parecido y lo que hice fue en lugar de ver la condición, evaluar nuevamente la fmla y llevar un contador de esto...
No se si se entiende la idea
Y visto que no es fácil, tú planteas evaluar desde vba la fórmula, me parece bien, pero ¿cómo evalúo la fórmula dentro del for de un range? ¿Podrías poner un ejemplo?
Muchas gracias, David.
Por ejemplo (muy resumido asumiendo que revisa el rango seleccionado)
dim r as Range, bError as Boolean
bError = False
for each r in Selection
 if IsError(r.Value) then
  bError = True
  Exit For
 end if
next r
if bError Then 
 MsgBox "Alerta, se detectaron errores"
Endif
...
Creo que no he comprendido bien tu ejemplo. Te adjunto el código que he puesto en el activate (el rango es un ejemplo con 3 celdas, la C5 cumple la fórmula del formato condicional y está en rojo):
Dim Rango_Datos As Range
Dim c As Range
Dim y As Integer
Dim error As Boolean
error = False
Set Rango_Datos = Range("A5:C5")
For Each c In Rango_Datos
   If c.FormatConditions.Count > 0 Then
     For y = 1 To c.FormatConditions.Count
       If IsError(c.Value) Then
         error = True
         Exit For
       End If
     Next y
   End If
   If error Then Exit For
Next c
If error Then MsgBox ("HAY UN SEMAFORO ROJO ENCENDIDO")
En ppio creo que está bien, lo único "raro" es que estás usando la variable error como boolean, no es por nada pero cambiale el nombre pues excel maneja una variable en forma interna que también se llama error (en realidad Error) y tal vez por esto tenga inconvenientes...
Además, ojo con esto en el código
If c.FormatConditions.Count > 0 Then
  For y = 1 To c.FormatConditions.Count
    If IsError(c.Value) Then 'acá preguntás si tiene error la fórmula y no la condicion del formato (no se si es esto en realidad lo que querés...)
      error = True
      Exit For
    End If
  Next y
Tienes razón, lo que quiero preguntar es si se cumple la condición de la fórmula que está en el formato condicional, pero no sé cómo hacerlo.
Gracias por tu tiempo
Probá con
if IsError(c.FormatConditions(y).Formula1) Then
...
Y por las dudas cambiá la variable error por otro nombre
He probado la condición y no evalúa la fórmula. Si se ve en la inspección que "Formula1" contiene la fórmula a evaluar, pero IsError() creo que no valida si la fórmula se cumple.
He mirado por internet y no consigo la forma de realizarlo. Te adjunto el código por si me he equivocado en algo:
Dim Rango_Datos As Range
Dim c As Range
Dim y As Integer
Dim HayError As Boolean
HayError = False
Set Rango_Datos = Range("A5:C5")
For Each c In Rango_Datos
  If c.FormatConditions.Count > 0 Then
   For y = 1 To c.FormatConditions.Count
    If IsError(c.FormatConditions(y).Formula1) Then
     HayError = True
     Exit For
    End If
   Next y
  End If
  If HayError Then Exit For
Next c
If HayError Then MsgBox ("HAY UN SEMAFORO ROJO ENCENDIDO")
Costó pero llegó, ahí te dejo la corrección
Dim Rango_Datos As Range
Dim c As Range
Dim y As Integer
Dim HayError As Boolean
HayError = False
Set Rango_Datos = Range("A5:C5")
For Each c In Rango_Datos
If c.FormatConditions.Count > 0 Then
For y = 1 To c.FormatConditions.Count
If IsError(Evaluate(c.FormatConditions(y).Formula1)) Then
HayError = True
Exit For
End If
Next y
End If
If HayError Then Exit For
Next c
If HayError Then MsgBox ("HAY UN SEMAFORO ROJO ENCENDIDO")
No sabes como lo siento, pero no funciona. En cuanto encuentra una celda con una fórmula en el formato condicional, al hacer el evaluate siempre devuelve TRUE.
La idea es que devuelva true si la fórmula devuelve true. No se si me explico.
Quizás falta algo ¿?.
Leyendo en foros, al parecer hay un problema con el idioma. Mi excel está en español, quizás el tuyo es versión inglesa, en la que parece que funcionaría... que caos...
gfellay, se te ocurre alguna posible idea/solución.
Muchas gracias y un saludo, David.
A mi me funciona pero mi excel está en español, aunque la parte de vba "siempre" está en ingles...
La verdad que no entiendo porque lo ejecuté en 2 formatos distintos y me daba la respuesta esperada, el Evaluate lo que te hace es evaluar la fmla (pues antes te daba el literal de la fmla), y a partir de allí la función IsError debería trabajar bien.
La verdad que no entiendo cual es el problema que tenés pues tenemos configuraciones "similares" (excel 2003 en español)
Cuando ejecuto tu código vba, independientemente de si la fórmula se cumple o no, IsError devuelve TRUE y muestra el msbox.
Creo que es extraño, aunque volviendo a los idiomas, mi vba está en Español y según ponen en otros foros, el evaluate no funciona correctamente en el vba Español, ¿podría ser esto?.
Otro Experto me ha dado un código que 'teoricamente' resuelve mi problema, aunque me parece desmasiado código (son varias funciones) para hacer una simple pregunta. No lo he probado.
Siento muchísimo molestaros tanto, pero si no consigo hacer esta macro, tengo que revisar una excel de casi 1000 filas y 20 columnas "a ojo", para ver si tiene una celda en rojo: "lamentable", pero es lo que hay.
Gracias de verdad.
Si conoces alguna alternativa, o podemos validar alguna otra opción, o tengo que instalar algo, o lo que sea, dímelo y lo intento.
Un saludo, David.
La verdad que lo del evaluate no lo sabía pero probá entonces reemplazando donde dice
Evaluate(c. FormatConditions(y). Formula1)
Por
[c.FormatConditions(y).Formula1)]
Que también funciona (aunque no se si tenga el mismo inconveniente que evaluate...)
Saludos
Gfellay
PD: en caso que no te funcione esto, lo "único que se me ocurre es que uses una celda auxiliar para colocar cada una de las condiciones del formato condicional...
gfellay, no sabes como lo siento, pero tampoco funciona.
Lo que comentas de una celda auxiliar, se me había ocurrido, pero no sé implementarlo, es más creo que lo intenté, moviendo siempre la fórmula a una celda y luego evaluar esa celda, pero no lo conseguí.
Podrías ponerme las dos líneas que realizan el volcado de la fórmula y la condición (aunque supongo que será muy parecido al código que ya me has pasado)
Gracias. (Nunca pensé que esto sería tan difícil)
En realidad por cada celda que tenés el formato condicional, deberías tener tantas filas (obvio hasta 3) como condiciones en el formato condicional. Y en cada celda repetís la fmla que tiene el formato condicional.
Lo siento, no te entiendo.
Gracias.
Decime las fórmulas que tenés para todos los formatos condicionales en una celda
Columna B :  =Y((LARGO($B5)=0);(LARGO($E5)>0))
Columna C: =Y($C5="Sin Asignar";$J5<>"Otros";$AB5>0)
                   =Y($C5="Oportunidad";$AB5>0)
                   =Y((LARGO($C5)=0);(LARGO($E5)>0))
Columna D: =Y(($C5="Oportunidad");(LARGO($E5)>0))
                    =Y(($C5<>"Oportunidad");(LARGO($E5)>0))
Columna E: =Y((LARGO($E5)=0);(LARGO($C5)>0);($AB5>0))
Columna G: =Y((LARGO($G5)=0);(LARGO($E5)>0))
                    =Y(($G5<>"Java/J2EE");($G5<>"SAP");($G5<>"Cobol");($G5<>"C/C++");($G5<>"Otras tecnologías");($G5<>".Net");($G5<>"Power Builder / C");($G5<>"Cross Facturable");($G5<>"Cross No Facturable");(LARGO($E5)>0))
Columna H: =Y(($G5="Otras Tecnologías");(LARGO($H5)=0);($C5="Proyecto"))
Columna J: =Y($J5="Otros";$K5<>"Otros";$AB5>0)
                  =Y($J5<>"Otros";$K5="Otros";$AB5>0)
                  =Y((LARGO($J5)=0);$AB5 > 0)
Columna K: =Y($K5="Otros";$J5<>"Otros";$AB5>0)
                 =Y($K5<>"Otros";$J5="Otros";$AB5>0)
                 =Y((LARGO($K5)=0);$AB5 > 0)
Columna L:  =Y((LARGO($L5)=0);$AB5 > 0)
                    =Y((LARGO($L5)=0);(LARGO($E5)<>0))
Columna Y,Z,AA:  =(SUMA($Y5:$AA5)<>$AB5)
Columna AB:  =Y((LARGO($AB5)=0);(LARGO($C5)>0))
Ok. Esto mismo lo deberías poner en alguna columna auxiliar (ejemplo en AD ponés la fmla de la B, en AE la de la C-acá como tenés 3 vas a tener que usar AE:AG), etc
una vez que esté todo esto en las columnas auxiliares, lo que queríamos hacer con macros los hacemos contra estas columnas...
Decime si más o menos me entendiste la idea
Lo entendí. Hoy lo haré y te comento.
Me parece una opción aceptable, pero sigo sin comprender porque no funciona una simple comprobación sobre el color de la celda. Bueno, sea como sea, lo probaré así. Si no funciona, abandono la idea de crear una macro que busque una celda de color (eso sí, el color pintado por un formato condicional).
Gracias gfellay
Cualquier cosa avisa
Vale, lo he realizado en una sola fila como ejemplo, pero no me convence... se me ocurre otra opción, a ver si me explico... sería realizar la evaluación de las fórmulas directamente desde vba, ¿podría ser?, es decir, darle un rango y que se lo recorra preguntando si esa fórmula se cumple, en cuanto encuentre una que se cumpla, se para y muestra un msgbox.
¿Qué te parece? ¿Cómo podría ser?.
Gracias por todo.
Pero eso es básicamente lo que quisimos hacer con el formato condicional; no estoy seguro como quedaron tus datos pero calculo que ahora el ciclo que habíamos tratado de hacer en las celdas mirando el formato condicional, habría que modificarlo ligeramente para cambiarle el rango y evaluar directamente estas celdas...
Gracias por tu dedicación. No he implementado la opción más óptima, pero es lo que de momento puedo hacer con el Excel que tengo instalado.
El trato y las soluciones son de alto nivel.
Gracias.
Respuesta
1
Hasta donde yo sé, y al menos en Excel 2003 que es el que utilizo, la única forma de averiguar el color generado por los formatos condicionales es reproducir mediante código en VBA el comportamiento del propio formato: un lío.
Para acabar de complicarlo, si se usa una versión de Excel que no sea la inglesa es casi imposible conseguirlo si la condición activa del formato condicional se debe a 'Fórmula' en lugar de a 'Valor de la celda', porque la fórmula es guardada en el idioma del Excel que se esté ejecutando y resulta imposible usar el método Evaluate de VBA con fórmulas que no estén en inglés.
Yo creé hace tiempo un libro de ejemplo que usa código VBA para evaluar los formatos condicionales. La función que usé está escrita por Chip Pearson, y el enlace al libro es: http://www.jrgc.es/ejemplos/sumar_o_contar_celdas_segun_color_formato_condicional.xls
La respuesta es muy interesante.
Tienes razón. He mirado las funciones vba y parece increíble que para saber el color de una celda haya que comprobar todas las condiciones.
Le echo un ojo y te cuento (para finalizar la pregunta).
Gracias de momento.
Me he bajado la excel que me pusiste en la URL y no veo código. Tampoco lo entiendo muy bien. Lo que tengo claro es que creo que tienes razón, todo viene por el idioma. ¿Alguna idea?, si puedes pegarme el código aquí, así lo veo.
Gracias por todo
¿No ves el código del libo? Pues lo tiene, está en Módulo1 y es:
Function SumarColor(rango As Range, color As Long) As Double
    Application.Volatile
    Dim rngC As Range
    For Each rngC In rango.Cells
        If rngC.FormatConditions.Count > 0 Then If ColorIndexDelFC(rngC) = color Then SumarColor = SumarColor + rngC
    Next rngC
    Set rngC = Nothing
End Function
Function ContarColor(rango As Range, color As Long) As Long
    Application.Volatile
    Dim rngC As Range
    For Each rngC In rango.Cells
        If rngC.FormatConditions.Count > 0 Then If ColorIndexDelFC(rngC) = color Then ContarColor = ContarColor + 1
    Next rngC
    Set rngC = Nothing
End Function
Function ColorIndexDelFC(Rng As Range, Optional OfText As Boolean = False) As Integer
    'Función escrita por Chip Pearson
    Dim AC As Integer
    AC = CondiciónActiva(Rng)
    If AC = 0 Then
        If OfText = True Then
            ColorIndexDelFC = Rng.Font.ColorIndex
        Else
            ColorIndexDelFC = Rng.Interior.ColorIndex
        End If
    Else
        If OfText = True Then
            ColorIndexDelFC = Rng.FormatConditions(AC).Font.ColorIndex
        Else
            ColorIndexDelFC = Rng.FormatConditions(AC).Interior.ColorIndex
        End If
    End If
End Function
Function CondiciónActiva(Rng As Range) As Integer
    'Función escrita por Chip Pearson
    Dim Ndx As Long
    Dim FC As FormatCondition
    If Rng.FormatConditions.Count = 0 Then
        CondiciónActiva = 0
    Else
        For Ndx = 1 To Rng.FormatConditions.Count
            Set FC = Rng.FormatConditions(Ndx)
            Select Case FC.Type
            Case xlCellValue
                Select Case FC.Operator
                Case xlBetween
                    If CDbl(Rng.Value) >= CDbl(FC.Formula1) And _
                        CDbl(Rng.Value) <= CDbl(FC.Formula2) Then
                        CondiciónActiva = Ndx
                        Exit Function
                    End If
                Case xlGreater
                    If CDbl(Rng.Value) > CDbl(FC.Formula1) Then
                        CondiciónActiva = Ndx
                        Exit Function
                    End If
                Case xlEqual
                    If CDbl(Rng.Value) = CDbl(FC.Formula1) Then
                        CondiciónActiva = Ndx
                        Exit Function
                    End If
                Case xlGreaterEqual
                    If CDbl(Rng.Value) >= CDbl(FC.Formula1) Then
                        CondiciónActiva = Ndx
                        Exit Function
                    End If
                Case xlLess
                    If CDbl(Rng.Value) < CDbl(FC.Formula1) Then
                        CondiciónActiva = Ndx
                        Exit Function
                    End If
                Case xlLessEqual
                    If CDbl(Rng.Value) <= CDbl(FC.Formula1) Then
                        CondiciónActiva = Ndx
                        Exit Function
                    End If
                Case xlNotEqual
                    If CDbl(Rng.Value) <> CDbl(FC.Formula1) Then
                        CondiciónActiva = Ndx
                        Exit Function
                    End If
                Case xlNotBetween
                    If CDbl(Rng.Value) <= CDbl(FC.Formula1) Or _
                        CDbl(Rng.Value) >= CDbl(FC.Formula2) Then
                        CondiciónActiva = Ndx
                        Exit Function
                    End If
                Case Else
                    Debug.Print "UNKNOWN OPERATOR"
                    End Select
            Case xlExpression
                If Application.Evaluate(FC.Formula1) Then
                    CondiciónActiva = Ndx
                    Exit Function
                End If
            Case Else
                Debug.Print "UNKNOWN TYPE"
                End Select
        Next Ndx
    End If
    CondiciónActiva = 0
End Function
Saludos y perdón por el retraso en responder, he estado de "finde".
Gracias por la molestia, pero me parece demasiado código para una simple comprobación.
Creo que has sido muy amable.
No lo he implementado, pero supongo que funciona.
Un saludo, David.

Añade tu respuesta

Haz clic para o

Más respuestas relacionadas