ACCESS vs PowerPoint      26-sep-2020
No es que sea habitual … pero puede ocurrir que haya que obtener datos en una presentación PowerPoint (nota: para no repetir mucho PowerPoint usaré Ppt en su lugar). La verdad es que para presentaciones de empresa se usan mucho, pero hasta ahora nunca me habían pedido obtenerlo desde Access.
Pero no hay que asustarse, es una herramienta de la familia Office, lo cual significa que por automatización podemos hacer con ello lo que queramos, desde el mismo pptx usando ‘macros’ como si fuera Excel o en nuestro caso desde Access con VBA.
Como ‘queja’ decir que Ppt no tiene una grabadora de macros como tiene Excel, que te ayude a encontrar el camino a recorrer. Dejó de estar operativa en la versión 2.003 de Office. Y por otro lado muchas de las acciones que se realizan no las ‘graba’ con lo que no es de mucha ayuda, por decirlo de una manera suave.
Declaraciones y referencias
Para poder desarrollar lo ‘más fácilmente’ posible, tener acceso a la ayuda de Ppt y que el Intellisense te ayude, lo mejor es referenciar la librería de PowerPoint correspondiente, referenciar los tipos de objeto a PowerPoint y abrir la automatización con:
     New PowerPoint.Application
y una vez hecho el proceso, cambiar la definición de todos los objetos a Object, abrir la automatización con:
     CreateObject("PowerPoint.Application")
y eliminar la referencia de Ppt.
Decir que hago lo mismo cuando uso Excel, Word o Outllook.
Otros compañeros tienen otras formas de atacar este problema, por ejemplo Access de Xavi
Para desarrollo:
|
Dim oPpt As PowerPoint.Application
Dim Presentacion As PowerPoint.Presentation
Dim Diapositiva As PowerPoint.Slide
Dim Shape As PowerPoint.Shape
Dim TextLoc As PowerPoint.TextRange
Set oPpt = New PowerPoint.Application
oPpt.Visible = True
|
Para producción:
|
Dim oPpt As Objet          ‘PowerPoint.Application
Dim Presentacion As Object ‘PowerPoint.Presentation
Dim Diapositiva As Object  ‘PowerPoint.Slide
Dim Shape As Object        ‘PowerPoint.Shape
Dim TextLoc As Object      ‘PowerPoint.TextRange
Set oPpt = CreateObject("PowerPoint.Application")
oPpt.Visible = True
|
Nota: el Ppt hay que ponerlo visible si o si para poder trabajar con él, no vale lo de Excel o Word de mantenerlo oculto y sólo mostrarlo al terminar.
Métodos de trabajo
He realizado el trabajo de dos maneras distintas:
- creando un Ppt desde ‘la nada’, añadiendo diapositivas, textos, tablas, etc
- modificando un Ppt aportado por el cliente, dónde ya está diseñada la presentación, creados los textos, tablas, imágenes, … dónde sólo tenemos que incluir los datos necesarios
Mejor la segunda, crear el diseño desde VBA no es difícil, pero si muy tedioso y ‘largo’. Además el Ppt es ‘lento’ a la hora de seguir las órdenes que se le dan, a mí por lo menos se me hace mucho más largo que obtener un Excel.
Acciones
Ya hemos visto las declaraciones de variables, la apertura de la app y hacerla visible, vamos con el detalle de las distintas acciones que podemos realizar con el Ppt:
Crear una presentación:
     Set Presentacion = oPpt.Presentations.Add
     oPpt.ActiveWindow.ViewType = ppViewSlide
Abrir una presentación ya existente:
     Set Presentacion = oPpt.Presentations.Open(RutaCompletaPowerPoint)
Añadir una diapositiva:
     Set Diapositiva = Presentacion.Slides.Add(3, ppLayoutBlank)
    (*) siendo 3 la posición en la que queremos insertarla
Posicionarnos en una diapositiva:
     Set Diapositiva = Presentacion.Slides(3)
     Diapositiva.Select
    (*) indispensable hacer el Select para las siguientes acciones a realizar en la misma, sino queremos estar referenciando todo incluyendo la diapositiva y el orden de la misma
Recorrer las diapositivas de una presentación:
     For i = 1 to Presentacion.Slides.Count
         Set Diapositiva = Presentacion.Slides(i)
         Diapositiva.Select
         Debug.print Diapositiva.Name
     Next
   otro método:
     For Each Diapositiva In Presentacion.Slides
         Debug.print Diapositiva.Name
     Next
Shapes. Formas.
Todo en Ppt es una Shape (forma), un texto, una linea, un conector, una imagen, una tabla … así que lo que hay que hacer es crear una y con sus propiedades situarla, darla grosor, color, alineación, texto, asignarle imagen, …
Crear Shape:
     Diapositiva.Shapes.Add (Tipo, Left, Top, Width, Heigh).Name = “Nombre”
     Diapositiva.Select
    (*) siendo Tipo (MsoAutoShapeType) el tipo de objeto que necesitemos, por ejemplo msoShapeRectangle = 1.
También podemos
crear directamente el Shape
que necesitemos:
     Diapositiva.shapes.AddLine …
     Diapositiva.shapes.AddLabel …
     Diapositiva.shapes.AddPicture …
     Diapositiva.shapes.AddTable …
     Diapositiva.shapes.AddTextBox …
     Diapositiva.shapes.AddTittle …
Una vez que lo tenemos creado es solo cuestión de
personalizar las propiedades del Shape:
     With Diapositiva.Shapes(Nombre)
         .Fill.ForeColor.RGB = RellenoColor
         .Line.ForeColor.RGB = LineaColor
         With .TextFrame.TextRange
             .ParagraphFormat.Alignment = Justificacion
             .Text = Texto
             .Font.Name = FontName
             .Font.Color.RGB = FontColor
             .Font.Size = FontSize
             .Font.Bold = FontBold
             .Font.Underline = FontUnderline
         End With
     End With
En la opción de crearme un Ppt de la nada, con el fin de teclear lo menos posible, me creé un par de funciones para realizar este trabajo (no están nada optimizadas):
|
Function PW_Shape(ByRef Diapo As Object, ByVal Nombre As String, ByVal Texto As String, _
     ByVal Left As Integer, ByVal Top As Integer, ByVal Width As Integer, _
     ByVal Height As Integer, Optional ByVal FontColor As Long = vbBlack, _
     Optional ByVal FontSize As Long = 12, Optional ByVal FontBold As Long = False, _
     Optional ByVal FontName As String = "Arial", Optional ByVal Justificacion = ppAlignLeft, _
     Optional ByVal RellenoColor = vbWhite, Optional ByVal LineaColor = vbWhite, _
     Optional ByVal FontUnderline As Long = False)
     Diapo.Shapes.AddShape(Type:=msoShapeRectangle, Left:=Left, Top:=Top, Width:=Width, _
         Height:=Height).Name = Nombre
     With Diapo.Shapes(Nombre)
         .Fill.ForeColor.RGB = RellenoColor
         .Line.ForeColor.RGB = LineaColor
         With .TextFrame.TextRange
             .ParagraphFormat.Alignment = Justificacion
             .Text = Texto
             .Font.Name = FontName
             .Font.Color.RGB = FontColor
             .Font.Size = FontSize
             .Font.Bold = FontBold
             .Font.Underline = FontUnderline
         End With
     End With
End Function
Function PW_Linea(ByRef Diapo As Object, ByVal Nombre As String, ByVal BeginX As Integer, _
     ByVal BeginY As Integer, ByVal EndX As Integer, ByVal EndY As Integer, _
     Optional ByVal ColorLinea As Long = vbBlack, Optional ByVal GrosorLinea As Long = 1)
     Diapo.Shapes.AddLine(BeginX:=BeginX, BeginY:=BeginY, EndX:=EndX, EndY:=EndY).Name = Nombre
     Diapo.Shapes(Nombre).Line.ForeColor.RGB = ColorLinea
     Diapo.Shapes(Nombre).Line.Weight = GrosorLinea
End Function
|
Asi que para crear Shapes basta con:
     PW_Shape Diapositiva, "Tit1", "TITULO", 20, 30, 630, 20, 12632256, 28, True, , ppAlignRight
     PW_Shape Diapositiva, "Tit2", Format(Date, "mmmm \de yyyy"), 20, 68, 680, 10, 0, 10, False, _
         "Calibri", ppAlignRight
     PW_Linea Diapositiva, "Lin1", 20, 80, 695, 80, 13408512, 2
     PW_Shape Diapositiva, "Tit3", "Gestión social de la vivienda", 20, 85, 630, 20, 13408512, 16, False, _
         "Arial", ppAlignLeft
     PW_Shape Diapositiva, "Tit4", "Situación en España", 20, 105, 630, 20, 13408512, 12, False, _
         "Arial", ppAlignLeft
Para añadir directamente una imagen:
     Diapositiva.Shapes.AddPicture (”C:\Temp\Imagen.jpg", True, True, 20, 50, 665, 450).Name = "Imagen"
Tablas
Uno de los objetos que más vamos a usar. No tiene mucho misterio su creación, una vez hecho el tratamiento es simple y la modificación de sus propiedades también, se hace sobre todo a través de los objetos TextFrame.TextRange que ya hemos visto anteriormente.
Creación de una tabla:
     Diapositiva.Shapes.AddTable(NumRows:=19, NumColumns:=4, Left:=40, Top:=100, Width:=260, _
         Height:=100).Name = "Tabla1"
Como veis, le decimos el número de filas y columnas que queremos que tenga. Distinto es modificar su formato, no nos deja hacer directamente un tamaño 'normal',
en su lugar hay que crear la tabla y después reducir su tamaño modificando la escala de la misma, con esto logramos la altura de las filas. Una vez hecho esto, ya podemos modificar la anchura de las columnas.
Modificar alto de las filas de una tabla:
     Diapositiva.Shapes(“Tabla1”).Table.ScaleProportionally (0.6)
Modificar ancho de las columnas de una tabla:
     Diapositiva.Shapes(“Tabla1”).Table.Columns(1).Width = 140
     Diapositiva.Shapes(“Tabla1”).Table.Columns(2).Width = 60
Modificar las propiedades de las celdas:
     With Diapositiva.Shapes(“Tabla1”).Table.Cell(Fila, Columna).Shape.TextFrame.TextRange
         .ParagraphFormat.Alignment = ppAlignCenter
         .Font.Name = “Calibri”
         .Font.Size = 10
         .Font.Italic = True
         .Font.Color.RGB = vbRed
         .Characters.Text = “Texto”
     End With
     Está claro que lo suyo es un bucle anidado fila / columna y mucho With para evitar grandes chorizos …. :-P
     A la hora de realizar los ajustes, hay que hacerlo con paciencia benedictina, modificando directamente la propiedad del Shape que estemos tratando, para ello ponemos un Stop justo después de haber creado el Shape y en la ventana inmediato ajustamos el valor que necesitemos:
     Diapositiva.Shapes("xxxx").Left = 360
Modificar una presentación existente
La segunda opción de trabajo, modificar un Ppt ya existente sólo cambiando los datos, es más simple de implementar (y mucho más rápida). Para poder trabajar cómodamente necesitaremos renombrar los objetos que tengamos que utilizar. Para ello recorreremos la colección de diapostivas (ya hemos visto como hacerlo) y en cada una de ellas analizaremos los Shapes existentes, modificando el "name" de aquellos que nos interese tratar.
Para recorrer los distintos Shapes de una diapositiva yo he utilizado el siguiente bucle:
     For Each Shape In Diapositiva.Shapes
         Shape.Select
         Debug.Print Shape.Name
         Stop ' Shape.Name = "xxxxxx"
     Next
que me muestra en el diseño de la diapositiva seleccionada el Shape seleccionado y en la ventana inmediato su nombre, en el caso de que vaya a tratarlo le
pongo un nombre significativo con la instrucción:
     Shape.Name = "NuevoNombre"
Una vez ‘personalizada’ la plantilla Ppt (y debidamente guardada) es cuando desde nuestro proceso Access accederemos a la misma y ‘actualizaremos’ los datos
correspondientes:
     Set Diapositiva = Presentacion.Slides(1)
     Diapositiva.Select
     Diapositiva.Shapes("NombreEntidad").TextFrame.TextRange.Text = “NombreEntidad”
     Diapositiva.Shapes("FechaLarga").TextFrame.TextRange.Text = Format(Date, "mmmm \de yyyy")
Para dar valores a una tabla usaremos el formato que ya vimos anteriormente:
     Diapositiva.Shapes(“Tabla1”).Table.Cell(fila, columna).Shape.TextFrame.TextRange.Characters.Text = "--"
Un caso especial es cuando solo queramos cambiar parte del texto de un TextFrame.
Por ejemplo, tenemos un Shape cuyo texto es:
     "La localidad de MARCA1 tiene MARCA2 habitantes.”
Podríamos hacerlo todo por VBA (siendo Xs String):
     Xs = “La localidad de “ & Me.NombreLocalidad & “ tiene “ & Me.Habitantes & “ habitantes.”
     Diapositiva.Shapes("DatosLoc").TextFrame.TextRange.Text = Xs
o:
     Xs = Diapositiva.Shapes("DatosLoc").TextFrame.TextRange.Text
     Xs = Replace(Xs, “MARCA1”, Me.NombreLocalidad)
     Xs = Replace(Xs, “MARCA2”, Me.Habitantes)
     Diapositiva.Shapes("DatosLoc").TextFrame.TextRange.Text = Xs
Y obtendríamos:
     "La localidad de VillaRiba tiene 1.200 habitantes.”
La pega que tiene cualquiera de estas dos formas de hacerlo, es que unifican el formato de todo el texto (al mismo tipo, tamaño, color, etc) y perdemos ‘riqueza’ en el mensaje puesto que puede estar el nombre de la localidad en negrita y fuente color rojo, una parte subrayada, etc.
Para que esto no nos ocurra lo que tenemos que hacer es trabajar justo con la parte de la cadena a sustituir usando para ello un objeto TextRange.
El ejemplo anterior quedaría así:
     Set TextLoc = Diapositiva.Shapes("DatosLoc ").TextFrame.TextRange.Find("MARCA1")
     TextLoc.Text = Me.NombreLocalidad
     Set TextLoc = Diapositiva.Shapes("DatosLoc ").TextFrame.TextRange.Find("MARCA2")
     TextLoc.Text = Me.Habitantes
y el resultado que obtendríamos sería:
     "La localidad de VillaRiba tiene 1.200 habitantes.”
Si necesitamos eliminar diapositivas de la presentación basta con:
     Presentacion.Slides(6).Delete
     Presentacion.Slides(5).Delete
   (*) a recordar que como en cualquier colección si tenemos que eliminar varias hay que hacerlo desde el final hacia
        el principio, si no queremos encontrarnos con sorpresas no deseadas.
Para guardar datos :
     Presentacion.Save
     Presentacion.Quit      (si necesitamos cerrarla)
Nota con las plantillas :
- Con Ppt las plantillas no funcionan como en Word, que abres un dotx y crea un documento nuevo al que el usuario tiene que dar nombre.
- En Ppt hay que duplicar la plantilla con el nombre que queramos usar (con FileSystem por ejemplo).
- La plantilla de Pptx lo que hace es introducir un modelo de diapositiva en la presentación que tengamos abierta.
Valores Constantes PPt :
Al eliminar la referencia a la libreria Ppt necesitaremos tener definidos los valores de las constantes usadas. En mi caso han sido:
     '*** Constantes PowerPoint
     Global Const msoShapeRectangle = 1
     Global Const ppViewSlide = 1
     Global Const ppLayoutBlank = 12
     Global Const ppAlignLeft = 1
     Global Const ppAlignRight = 3
     Global Const ppAlignCenter = 2
     Global Const ppAlignJustify = 4
     Global Const ppAlignDistribute = 5
     Global Const ppAlignJustifylow = 7 ' justificar abajo
     Global Const msoAnchortop = 1      ' justificar vertical arriba
     Global Const msoAnchorMiddle = 3
     Global Const msoAnchorBottom = 4
|