domingo, 28 de abril de 2024

79 - Filtrar con criterio en otra hoja.

Generalmente seleccionamos, desde las columnas de una hoja de datos, el elemento buscado. O dejamos en alguna celda el criterio a buscar y con una macro se filtra la hoja.

La propuesta que presento aquí está pensada para cuando tenemos listas: de Alumnos, Cuentas de clientes o proveedores, Productos y tantas otras, donde guardamos el nombre y su código.

Y donde las hojas de Movimientos de cuentas solo cuentan con la columna de Código, lo que dificulta la búsqueda de algún registro. 


Entonces vamos a recurrir a una macro que se ejecutará desde la hoja de la Lista. En este ejemplo se utilizó el evento BeforeDoubleClick, aunque bien podría ser ejecutada desde un botón o el menú Desarrollador/Programador, Macros.

En el Editor seleccionamos la hoja Listado y allí colocaremos estas instrucciones:

Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)

'llamamos a la macro de filtrado

Call filtro_Total

End Sub

Y la macro llamada 'filtro_Total' la colocaremos en un módulo:

Sub filtro_Total()   'macro única para uso en los 2 modelos de hoja: rango o tabla

 

'acotamos el rango desde donde podremos hacer doble clic para llamar a la macro

If ActiveCell.Column <> 3 Or ActiveCell.Row < 4 Then Exit Sub

 

'verificamos si la celda seleccionada tiene contenido

If ActiveCell = "" Then Exit Sub

 

'se guarda el dato de la celda seleccionada y se pasa a la otra hoja

dato = ActiveCell.Value

Sheets("MOVIMIENTOS").Select   'agregar instrucciones (*)

 

'quitamos previamente cualquier filtro aplicado

If ActiveSheet.FilterMode = True Then ActiveSheet.ShowAllData

 

'se evalúa si se trata de una hoja con rango o con Tabla (**)

If ActiveSheet.ListObjects.Count = 0 Then

    'establecer el rango y filtrar por el critrio guardado en la variable

    rgo = [C3].CurrentRegion.Address

    ActiveSheet.Range(rgo).AutoFilter Field:=2, Criteria1:=dato

Else

    'si se conoce en qué col se encuentran las claves, utilizar esta instrucción

    ActiveSheet.ListObjects(1).Range.AutoFilter Field:=2, Criteria1:=dato

   

    'si no se conoce la ubicación de la col 'claves' utilizar estas otras

    'colx = ActiveSheet.Range("Tabla1[[CODIGO]]").Column         'Ajustar nombre de tabla y el título de columna al modelo

    'ActiveSheet.ListObjects(1).Range.AutoFilter Field:=colx - 1, Criteria1:=dato

End If

End Sub

NOTAS ACLARATORIAS:

(*) Para que la macro sea de uso en cualquier hoja del libro, se deben agregar instrucciones para evaluar previamente en qué hoja se filtrará. Por ejemplo: colocando el nombre en alguna celda de la hoja Listado.

Hojita= [E1]

Sheets(Hojita).Select 



(**) Como intentamos utilizar la misma macro para diferentes formatos de hojas, necesitamos evaluar si la hoja activa tiene un objeto Tabla o no. ListObjects.Count nos devuelve al número de tablas,

(***)  Para trabajar con un solo modelo de hojas, recomiendo mirar el video donde se muestran en módulos diferentes cada una de sus macros (filtra_Rango o filtra_Tabla)


Ver video Nº 79 desde aquí.

Descargar libro desde aquí o solicitarlo a mi correo de Gmail.

jueves, 18 de abril de 2024

78 - Crear hojas a partir de una Plantilla, para lista de destinatarios.

 Si tenemos nuestra documentación en forma de base de datos (facturación, cobranzas, documentos emitidos, etc), en algún momento necesitaremos enviar esa documentación a los destinatarios. O necesitaremos guardar en hojas separadas esa información.

En este ejemplo, parto de una lista de facturas emitidas y la idea es guardar esa información en formato de documento, por cada cliente de la lista.

Ejemplo 1: la lista no se encuentra filtrada. Se controla si el registro tiene saldo a facturar.




Sub facturando()

Dim hoC As Worksheet, hoF As Worksheet

 

'se declaran las 2 hojas del proceso

Set hoC = Sheets("Clientes")

Set hoF = Sheets("Formato")

 

'recorrer el rango a facturar

With hoC

    For i = 4 To Range("B" & Rows.Count).End(xlUp).Row

        'comprobar si tiene saldo <> 0

        If .Range("X" & i) = 0 Then GoTo sigueOtro

       

        'crear copia de la hoja Formato agregándola al final

        hoF.Copy After:=Sheets(Sheets.Count)

        On Error Resume Next

        ActiveSheet.Name = .Range("D" & i).Text

        If Err.Number > 0 Then GoTo existeHoja

sigo:

        On Error GoTo 0

        Set hoX = ActiveSheet

        'pasar los datos a la nueva hoja

        hoX.[D2] = .Range("D" & i)      'nbre clie

        hoX.[D3] = .Range("C" & i)      'cod clie

        hoX.[D4] = .Range("E" & i)      'domicilio clie

        hoX.[B6] = .Range("F" & i)      'nro fact

        hoX.[E6] = .Range("B" & i)      'fecha

       

        'evluar si hay valores en H o en I

        If .Range("H" & i) = 0 Then

            hoX.[E15] = .Range("I" & i)

        Else

            hoX.[E15] = .Range("H" & i)

        End If

       

        'concatenar col AA + AB

        hoX.[A10] = .Range("AA" & i) & " " & .Range("AB" & i)

       

        hoX.[E16] = .Range("M" & i)    'iva

        hoX.[E17] = .Range("W" & i)     'retencion

'se pasa a la fila siguiente de la hoja base

sigueOtro:

    Next i

   

End With

 

MsgBox "Fin del proceso.", , "Información"

Exit Sub

 

existeHoja:

MsgBox "Ya existe una hoja de nombre " & hoC.Range("D" & i).Text & Chr(10) & _

"El formato se guardará con nombre de hoja " & ActiveSheet.Name & ".", vbCritical

GoTo sigo

End Sub



Ejemplo 2: Se aplicará filtro a la lista. Se recorre el rango rellenando el formato solo con datos de filas filtradas. Se controla si el registro tiene saldo a facturar.

Sub facturando_Filtrado()

 

'se declaran las 2 hojas del proceso

Set hoC = Sheets("Clientes")

Set hoF = Sheets("Formato")

 

'controles previos a la salida del formato (si se aplicó filtro => si hay filas filtradas)

x = hoC.Range("B" & Rows.Count).End(xlUp).Row

If x < 4 Then

    MsgBox "No hay datos para facturar.", , "Atención"

    Exit Sub

End If

 

'recorrer el rango a facturar

With hoC

    For Each celdita In .Range("B4:B" & x).SpecialCells(xlCellTypeVisible)

        'fila de la celda visible

        i = celdita.Row

        'comprobar si tiene saldo <> 0

        If .Range("X" & i) = 0 Then GoTo sigueOtro   

        'crear copia de la hoja Formato agregándola al final

        hoF.Copy After:=Sheets(Sheets.Count)

        On Error Resume Next

        ActiveSheet.Name = .Range("D" & i).Text

        If Err.Number > 0 Then GoTo existeHoja

sigo:

        On Error GoTo 0

        Set hoX = ActiveSheet

        'pasar los datos a la nueva hoja

        hoX.[D2] = .Range("D" & i)

        hoX.[D3] = .Range("C" & i)

        hoX.[D4] = .Range("E" & i)

        hoX.[B6] = .Range("F" & i)

        hoX.[E6] = .Range("B" & i)

        If .Range("E" & i) = 0 Then

            hoX.[E15] = .Range("H" & i)

        Else

            hoX.[E15] = .Range("I" & i)

        End If

        hoX.[A10] = .Range("AA" & i) & " " & .Range("AB" & i)

        hoX.[E15] = .Range("B" & i)

        hoX.[E16] = .Range("M" & i)

        hoX.[E17] = .Range("W" & i)   

sigueOtro:

Next celdita

End With

 

MsgBox "Fin del proceso.", , "Información"

Exit Sub

 

existeHoja:

MsgBox "Ya existe una hoja de nombre " & hoC.Range("D" & i).Text & Chr(10) & _

"El formato se guardará con nombre de hoja " & ActiveSheet.Name & ".", vbCritical

GoTo sigo

End Sub


Descargar libro con las macros desde aquí o solicitarlo al correo Gmail de: cibersoft.arg

Ver video Nº 78 desde aquí.

miércoles, 10 de abril de 2024

77 - Graficando sin Gráficos.

 Si tenemos que presentar Informes de planillas con gran cantidad de filas y columnas, podemos hacer uso de un par de herramientas para graficar resultados, sin necesidad de crear Gráficos.

Modelo Nº 1:

a- En el primer grupo de Totales aplicamos Gráfico de barras.  

    Desde menú Inicio, Formato Condicional, Barra de datos, y seleccionamos un estilo a gusto.


b- En el segundo grupo, desde el mismo menú Inicio, Formato condicional, aplicamos Escalas de color, simulando un semáforo.

Nota: En la primera imagen se superpuso una Escala de color sobre un gráfico de Barras.


Modelo Nº 2:


Aquí se intenta graficar la evolución de los resultados mensuales. Para ello, desde menú Insertar optamos por el grupo Minigráficos seleccionando un estilo. En el primer grupo de valores se optó por Columnas y en el segundo por Líneas.


Se puede llamar a esta herramienta con algún rango ya seleccionado. Por ejemplo, si seleccionamos el rango de celdas donde se va a ubicar el gráfico, se nos pedirá el ingreso del rango de Datos.

Nota: una vez insertado el Minigráfico, se activará una nueva barra de herramientas que nos permitirá darle formato a gusto: color de las barras o líneas, marcar el punto más alto y el más bajo y otras opciones más. En el ejemplo, además, se le dió color de fondo a las celdas y se colocó como título las iniciales de los meses para una mejor visualización.


Modelo Nº 3:

En este modelo, el objetivo es colocar un objeto junto a los valores máximo, mínimo y coincidente con el contenido de una celda.

Para ello primero insertaremos unos objetos gráficos como imágenes o iconos (en versión Excel 365). Y luego ejecutaremos una macro para ubicar esos objetos en el Informe.

Nota: para insertar Iconos en versiones Excel 365 los invito a buscar en este Blog, la entrada de Mayo 2023


En el Editor de macros, insertamos un módulo y allí colocaremos la macro que recorrerá esta tabla colocando los objetos en el lugar que les corresponda según los valores de la tabla.

Nota: En el video Nº 77 (Graficando sin Gráficos) de mi canal, alrededor del minuto 5:50 se explica cómo obtener los nombres de los objetos para ser utilizados desde la programación.

Sub graficando_tabla()

Dim maxi As Single, mini As Single, ideal As Single

Dim cd As Range

Dim rangoTabla

 

'guardar los valores máximos y mínimos del rango

rangoTabla = Range("Préstamo[[Saldo final]]").Address

maxi = Application.WorksheetFunction.Max(Range(rangoTabla))

mini = Application.WorksheetFunction.Min(Range(rangoTabla))

ideal = [K1]      'celda donde se encuentra el valor 'ideal'

 

'se recorre el rango buscando el valor maxi y mini

For Each cd In Range(rangoTabla)

 

    'si la celda contiene el valor 'maxi' se coloca el gráfico 4 en el tope y margen izquierdo de esa celda

    If cd.Value = maxi Then

        ActiveSheet.Shapes.Range(Array("Gráfico 4")).Top = cd.Top

        ActiveSheet.Shapes.Range(Array("Gráfico 4")).Left = cd.Offset(0, 1).Left + 20

       

    ElseIf cd.Value = mini Then

        'si la celda contiene el valor 'mini' se coloca el gráfico 2 en el tope y margen izquierdo de esa celda

         ActiveSheet.Shapes.Range(Array("Gráfico 2")).Top = cd.Top

         ActiveSheet.Shapes.Range(Array("Gráfico 2")).Left = cd.Offset(0, 1).Left + 20

 

    ElseIf cd.Value = ideal Then

        'si la celda contiene el valor 'mini' se coloca la imagen en el tope y margen izquierdo de esa celda

         ActiveSheet.Shapes.Range(Array("Group 17")).Top = cd.Top

         ActiveSheet.Shapes.Range(Array("Group 17")).Left = cd.Offset(0, 1).Left + 20

    End If

Next cd

End Sub

 


Nota: En el libro que se puede descargar desde este enlace o solicitarlo al correo Gmail: cibersoft.arg encontrarán otra macro que recorre un rango común (no Tabla).

Ver video Nº 77 desde aquí.