Página 1 de 1

[RESUELTO] Control de Árbol (TreeControl).

NotaPublicado: Mié Jul 26, 2017 10:25 pm
por Dario Piedra
Buenas tardes,

Soy nuevo en el foro, y hace unos días (5 aproximadamente) que empecé a usar OpenOffice (del cual no conozco mucho).
Tengo la idea de hacer un macro que ayude a unos compañeros en el trabajo, sin embargo no conozco nada acerca de programación en Basic (ooo Basic).

Descargué el Manual de Mauricio Baeza y traté de "hacer algo por mi cuenta" pero llegué a un punto donde estoy estancado, y humildemente quisiera pedirles ayuda.

Mi idea es la siguiente: (Dividida en Pasos).

1- Crear un control de Arbol que me permita seleccionar una carpeta.
2- Abrir todos los archivos ODS contenidos en esa carpeta.
3- Copiar determinadas columnas de esos archivos y consolidarlos en un solo ODS.
4- Guardar el archivo consolidado.

Ahorita no he podido cumplir ni siquiera el paso uno (voy paso a paso sin prisa), y el problema es el siguiente:
El control de árbol se ejecuta correctamente, me muestra la carpeta de raiz y me muestra las carpetas que hay dentro de la raiz, pero no puedo ir más abajo (subcarpetas)....

Según entiendo tendría que crear un nodo hijo y ligarlo al nodo padre, lo he intentado de varias formas sin éxito alguno.

Código: Seleccionar todo   Expandir vistaContraer vista
REM  *****  BASIC  *****

'Sentencia de Macro.
Sub EjecutarMiDialogo1()
   'Variables para el dialogo que usará el usuario.
   Dim Cuadro_Dialogo As Object
   Dim Explorador As Object
   Dim modelo_Explorador As Object
   'Variables para establecer la ruta.
   Dim ruta_Raiz As Object   'es la ruta origen, desde aquí el usuario podrá seleccionar cualquier carpeta.
   Dim nodo_Padre As Object   'Será el primer nivel del control.
   Dim nodo_Hijo as Object   'Será el segundo nivel del control.
   Dim ruta As String 'Ruta que alimentará el origen del control.

   'Se realiza la carga de la librería standard.
   DialogLibraries.LoadLibrary( "Standard" )
   'Cargamos el cuadro de diálogo en memoria
   Cuadro_Dialogo = CreateUnoDialog( DialogLibraries.Standard.getByName("Dialogo") )
   'Se obtiene el control creado en el diálogo.
   Explorador = Cuadro_Dialogo.getControl("TreeControl1")   

   'Servicio para controlar el contenido del control
   modelo_Explorador = createUnoService("com.sun.star.awt.tree.MutableTreeDataModel")
   
   'La ruta origen para explorar directorios.
   ruta = "C:\Users\uidcr01407\Desktop\"
   'Si la ruta no es vacía deberá recorrer las carpetas y mostrarlas en el control.
   If Dir(ruta) <> "" Then
      'Creamos el nodo raíz
      ruta_Raiz = modelo_Explorador.createNode( ruta, True )
      'Establecemos el nodo raíz
      modelo_Explorador.setRoot( ruta_Raiz )
      'Buscamos el primer directorio (16) (esto lo vi en el libro de Mauricio, pero no sé que
      'significa el 16, probé cambiarlo por true y es el mismo resultado.
      ruta = Dir(ruta,16)
      'Cuando no haya más directorios ruta estará vacía
      Do While ruta <> ""
         Select Case Left(ruta,1)
            'Nos saltamos los ocultos
            Case ".", ".."
            Case Else
               nodo_Padre = modelo_Explorador.createNode( ruta, True )
               ruta_Raiz.appendChild(nodo_Padre)
                  'Intento crear un nodo hijo.
                  '*************   Es aquí donde tengo el problema.  *************
                  nodo_Hijo = modelo_Explorador.createNode(nodo_Padre,True)
                  nodo_Padre.appendChild(nodo_Hijo)
                  '*************   *********************************  *************
         End Select
         'Siguiente directorio
         ruta = Dir
      Loop      
      
      Explorador.getModel.DataModel = modelo_Explorador   
   End If
   'Se ejecuta el dialogo.
   Cuadro_Dialogo.execute()
   
   If Explorador.getSelectionCount > 0 Then
   'Se muestra el nodo seleccionado.
   MsgBox Explorador.getSelection.getDisplayValue
   End If

   'Se libera el dialogo.
   Cuadro_Dialogo.dispose()
   
End Sub


Les agradezco la orientación que me puedan brindar, y disculpas por tanta explicación no soy bueno resumiendo.

Saludos

Re: Control de Árbol (TreeControl).

NotaPublicado: Jue Jul 27, 2017 6:46 pm
por mauricio
Hola...

Lo que quieres esta resuelto en easy-macro con una línea:
Código: Seleccionar todo   Expandir vistaContraer vista
dlg.tree_folders.data = '/home/mau/test'

aquí en ejemplo completo mostrando una ruta:
https://gitlab.com/mauriciobaeza/easy-m ... 1rbol-tree
tree_es_02.png

Los otros tres pasos también pueden resolverse en unas cuantas líneas, pero sin un archivo de ejemplo, esta complicado ayudarte.

Saludos

Re: Control de Árbol (TreeControl).

NotaPublicado: Jue Jul 27, 2017 7:14 pm
por Dario Piedra
Muchas gracias Mauricio por la pronta respuesta.
Al ser un poco nuevo en esto, tengo una pequeña duda (no entendí a la primera).
¿1- En este caso Easy Macro sería un código distinto (Phyton)?
¿2- Easy Macro es compatible con OpenOffice, o solo con Libre Office?

Imagino que debo descargar easy macro y realizar la instalación para windows, vi un foro donde dejas un video de como hacerlo.

Con respecto a los demás pasos, voy a ver si puedo montar un archivo ejemplo con los datos y adjuntarlo.

Saludos Cordiales;

Re: Control de Árbol (TreeControl).

NotaPublicado: Jue Jul 27, 2017 7:27 pm
por mauricio
Dario Piedra escribió:¿1- En este caso Easy Macro sería un código distinto (Phyton)?
¿2- Easy Macro es compatible con OpenOffice, o solo con Libre Office?

1.- Si, es Python que permite hacer cosas muy potentes con sencillez.
2.- Si, ahora es compatible con OpenOffice, no he podido validar todas las funcionalidades, pero si me ayudan con esto, me comprometo a hacerlo 100% compatible.

Saludos

Re: Control de Árbol (TreeControl).

NotaPublicado: Jue Jul 27, 2017 8:09 pm
por Dario Piedra
Entendido, voy a hacer las descargas necesarias y a revisar entre la documentación.

Gracias por la ayuda.

Adicional adjunto un archivo .rar donde está la siguiente información.
1- Archivo para consolidar. - Este archivo es el que consolidará toda la información, y es el que llevará el macro. (ahorita no tienen ningún macro porque apenas estar descargando las herramientas).
2- Carpeta con subcarpetas y con archivos.
3- Archivo txt explicativo.

Es una idea un poco "estructura" de lo que debería hacer el macro.

Una vez más, gracias por toda la ayuda.

Saludos Cordiales;

Re: Control de Árbol (TreeControl).

NotaPublicado: Jue Jul 27, 2017 8:42 pm
por mauricio
El proceso esa más que pintado para resolverse fácilmente con easy-macro, por favor, mira la documentación y los ejemplos, yo te voy guiando mientras vas validando que funcione todo en OpenOffice.

Saludos

Re: Control de Árbol (TreeControl).

NotaPublicado: Jue Jul 27, 2017 10:36 pm
por Dario Piedra
Buenas tardes Mauricio, ya tengo todo instalado.
Copié el vínculo en mi carpeta, probé con el macro de ejemplo que viene en el video, el que muestra un msgbox con la versión y nombre del OpenOffice que tengo instalado.
Todo eso funcionó correctamente.

Leyendo la documentación acerca de los dialogos, quise empezar con lo más básico, crear un dialogo por código.

Código: Seleccionar todo   Expandir vistaContraer vista
from libo import LIBO

def main():
    app = LIBO()
    propiedades = {
        'Title': 'Prueba de Dialogo',
        'Width': 100,
        'Height': 30,
    }
    dlg = app.create_dialog(propiedades)
    dlg.execute()
    return


Sin embargo si lo ejecuto, obtengo el siguiente error: (adjunto).
Según veo, dice algo de parámetros, un bloqueo modal, y algo más que no estoy seguro.

Podrías ayudarme a identificar donde está el error?

Saludos.

Re: Control de Árbol (TreeControl).

NotaPublicado: Jue Jul 27, 2017 10:39 pm
por mauricio
Hola...

por favor, prueba de nuevo... ya esta corregido... gracias por probar.

Saludos

Re: Control de Árbol (TreeControl).

NotaPublicado: Jue Jul 27, 2017 11:37 pm
por Dario Piedra
Listo, probando y funcionando ya puedo ver un diálogo vacío.

Ahora me pasa algo curioso, intenté agregar un control en este caso una etiqueta, pero ya no me aparece la opción para ejecutar el macro dentro del OpenOffice. (imagen adjunta).

Código: Seleccionar todo   Expandir vistaContraer vista
from libo import LIBO

def main():
#~sentencias originales del código, para mostrar un dialogo en blanco
    app = LIBO()
    propiedades = {
        'Title': 'Directorio de Archivos.',
        'Width': 200,
        'Height': 100,
    }
    dlg = app.create_dialog(propiedades)
#~Sentencias para agregar una etiqueta.
   propiedades_etiq = {
        'Type': 'label',
        'Name': 'lbl_nombre',
        'Label': 'Nombre: ',
        'Width': 25,
        'PositionY': 8,
        'PositionX': 5,
   }
#~Se ejecuta el control.
   dlg.add_control(propiedades_etiq)
    dlg.execute()
   
    return


El código solo para el diálogo funciona correcto, pero si agrego algún control no me aparece la opción para ejecutarlo.

Que pena molestar tanto, muchas gracias de antemano.

Re: Control de Árbol (TreeControl).

NotaPublicado: Vie Jul 28, 2017 12:22 am
por mauricio
Si así lo tienes tal cual... tienen errores de indentacion, Python es muy, muy, muy estricto con esto. Asegurate de que todo este correctamente identado como en las propiedades del dialogo.

Los comentarios no tiene que ver, pero acostumbrate a identarlos junto con tu código.

Saludos

Re: Control de Árbol (TreeControl).

NotaPublicado: Vie Jul 28, 2017 12:42 am
por Dario Piedra
Demasiado amable, me sorprende lo que hacen unos "tab" y unos "espacios" que no puse bien.
Listo y corregido.
Demasiado amable.

Voy a seguir con el proyecto.

Re: Control de Árbol (TreeControl).

NotaPublicado: Vie Jul 28, 2017 3:20 am
por Dario Piedra
Buenas noches Mauricio, un gusto saludarte nuevamente.
Gracias por la ayuda e indicaciones que me has brindado, ya pude usar el treecontrol, sin embargo tengo una duda con respecto a los eventos.
Por ejemplo: el dialogo puede tener dos botones uno para cancelar (cierra el diálogo) y otro para aceptar (confirmar la ruta seleccionada).

Revisando la documentación dice que es necesario crear una clase para controlar los eventos, adicional para conocer los nombres de los eventos revisé el documento libo.py y encontré uno que considero me podría servir:

Código: Seleccionar todo   Expandir vistaContraer vista
class EventsMouse(ListenerBase, XMouseListener):

    def __init__(self, controller):
        super(EventsMouse, self).__init__(controller)

    def mousePressed(self, event):
        control_name = '{}_click'.format(event.Source.Model.Name)
        if hasattr(self._controller, control_name):
            getattr(self._controller, control_name)(event)
        return


Sin embargo no logro entender como funciona, en los ejemplos de la documentación vienen algunas ideas pero no logro comprenderlas del todo.

¿Sería posible me ayudaras a entender un poco como funcionan los eventos? y que parámetros son los que se deben pasar.

P.D en mis intentos de invocar el evento obtuve este error (adjunto).

Re: Control de Árbol (TreeControl).

NotaPublicado: Vie Jul 28, 2017 4:51 am
por mauricio
Un ejemplo mínimo pero ilustrativo. Lo he probado en OpenOffice... ejecuta la macro main
Código: Seleccionar todo   Expandir vistaContraer vista
from libo import LIBO


app = LIBO()


def main():
    dialogo_eventos()
    return


class Controllers(object):

    def __init__(self, dlg):
        self.dlg = dlg

    def cmd_aceptar_action(self, event):
        self.dlg.close(1)
        return

    def cmd_cancelar_action(self, event):
        self.dlg.close()
        return


def dialogo_eventos():

    opciones = {
        'Title': 'Acciones'
    }
    dlg = app.create_dialog(opciones)
    #~ IMPORTANTE: pasar la clase para controlar los eventos, inmediatamente
    #~ despues de crear el cuadro de diálogo
    dlg.events = Controllers(dlg)

    opciones = {
        'Type': 'button',
        'Name': 'cmd_aceptar',
        'Label': 'Aceptar',
        'PositionX': 50,
        'PositionY': 10,
    }
    dlg.add_control(opciones)

    opciones = {
        'Type': 'button',
        'Name': 'cmd_cancelar',
        'Label': 'Cancelar',
        'PositionX': 50,
        'PositionY': 70,
    }
    dlg.add_control(opciones)

    res = dlg.execute()

    if res:
        msg = 'Se presiono Aceptar'
    else:
        msg = 'Se presiono Cancelar'

    app.msgbox(msg)
    return

EL esquema general es:
Código: Seleccionar todo   Expandir vistaContraer vista
NOMBRE_CONTROL_NOMBRE_EVENTO

Para los botones siempre usa el evento action, por supuesto, puedes usar cualquier otro evento de ratón, como el click
Código: Seleccionar todo   Expandir vistaContraer vista
cmd_aceptar_click(self, event)

Saludos

Re: Control de Árbol (TreeControl).

NotaPublicado: Vie Jul 28, 2017 3:21 pm
por Dario Piedra
Muchas gracias Mauricio, demasiado amable.
Voy a realizar las pruebas y a seguir avanzando.
Por cierto, el error que me aparecía se debe a que puse "_init_", en vez de "__init__", en la declaración del evento.

Saludos Cordiales;

Re: Control de Árbol (TreeControl).

NotaPublicado: Vie Jul 28, 2017 4:22 pm
por Dario Piedra
Buenos días Mauricio,

Estaba tratando de definir un evento para el botón aceptar, donde capturara la ruta seleccionada por el usuario. "para validar que la ruta esté correcta, pensé en mostrar un mensaje en pantalla que la confirmara".
El código es el siguiente:
Código: Seleccionar todo   Expandir vistaContraer vista
   def bt_aceptar_action(self, event):
      seleccion = self.dlg.directorio.selection
      if seleccion is None:
         app.msgbox('Por favor seleccione una ruta')
         return
      else:
         app.msgbox(seleccion)
         return
      self.dlg.close()
      return


Sin embargo, cuando se presiona el botón aceptar: (adjunto).
Decidí probar con el evento selection_changed, pero me muestra el mismo error cuando se cambia la ruta.

Podrías ayudarme a identificar el error.

Saludos Cordiales,

Re: Control de Árbol (TreeControl).

NotaPublicado: Vie Jul 28, 2017 4:43 pm
por mauricio
Hola...

Es correcto, la selección es un nodo del control Tree, que tiene, entre otros valores, DataValue para el valor interno, y DisplayValue, por lo que si quieres el valor seleccionado seria:
Código: Seleccionar todo   Expandir vistaContraer vista
seleccion.DisplayValue

pero supongo que quieres la ruta completo de la jerarquia que selecciono el usuario. Se me ocurre agregar una propiedad value que, cuando el control muestre rutas, te devuelve al ruta completa seleccionada, y cuando no sean ruta, solo el valor seleccionado.
Código: Seleccionar todo   Expandir vistaContraer vista
self.dlg.directorio.value

¿Que opinas?

Re: Control de Árbol (TreeControl).

NotaPublicado: Vie Jul 28, 2017 5:11 pm
por mauricio
Ahora, quiero entender como quieres hacerlo... el control solo muestra carpetas, de la carpeta seleccionada... ¿vas a seleccionar un archivo o todos?

Re: Control de Árbol (TreeControl).

NotaPublicado: Vie Jul 28, 2017 5:28 pm
por Dario Piedra
Muchas gracias por la pronta ayuda,
Efectivamente me estaba haciendo falta el .DisplayValue, ya probado se muestra en pantalla, pero tal y como mencionas mi interés primordial sería obtener la ruta completa.
Con respecto a la nueva propiedad que mencionas, no termino de comprender la idea, en ese caso habría que agregarla al archivo Libo.py para que el usuario pueda escoger que resultado "invocar".

El control solo muestra las carpetas, no llega a la selección de archivos. (Adjunto).
La idea es seleccionar una carpeta y que en esa ruta se busquen todos los archivos ods (incluyendo los que están en subcarpetas), y copiar la información de esos archivos.

Gracias de antemano.

Re: Control de Árbol (TreeControl).

NotaPublicado: Vie Jul 28, 2017 5:48 pm
por mauricio
El control por default ya guarda todos los archivos contenidos en las carpetas, además de que ya filtra los documentos por tipo de acuerdo a la extensión. Para que solo seleccione los ODS, agrega (ajusta a tu código):
Código: Seleccionar todo   Expandir vistaContraer vista
    opciones = {
        'Type': 'tree',
        'Name': 'tree_folders',
        'PositionX': 5,
        'PositionY': 5,
        'Width': 100,
        'Height': 100,
    }
    dlg.add_control(opciones)
    dlg.tree_folders.filter_ext = 'ods'
    dlg.tree_folders.data = '/home/mau/test'

Y pruebas en el botón Aceptar:
Código: Seleccionar todo   Expandir vistaContraer vista
    def cmd_aceptar_action(self, event):
        files = self.dlg.tree_folders.files
        msg = 'Ruta seleccionada: {}\n\nArchivos:\n{}'.format(
            self.dlg.tree_folders.value, '\n'.join(files))
        app.msgbox(msg)
        return

ANTES, de probar esto, actualiza la librería, cada cambio que hago debes de actualizar, de ahí la recomendación de usar git para clonar el repositorio.

Saludos

Re: Control de Árbol (TreeControl).

NotaPublicado: Vie Jul 28, 2017 5:53 pm
por mauricio
pero... si solo vas a dejar que el usuario selecciona la ruta, y a partir de ahí realizar todo el proceso, tal vez te convenga no guardar los archivos y procesar la carpeta al momento de presionar aceptar. Nota que ya no ponemos filtro, pues no vamos a guardar ningún archivo:
Código: Seleccionar todo   Expandir vistaContraer vista
    opciones = {
        'Type': 'tree',
        'Name': 'tree_folders',
        'PositionX': 5,
        'PositionY': 5,
        'Width': 100,
        'Height': 100,
    }
    dlg.add_control(opciones)
    dlg.tree_folders.save_files = False
    dlg.tree_folders.data = '/home/mau/test'

y entonces, procesamos todos los ODS que estén en la carpeta seleccionada y subcarpetas...
Código: Seleccionar todo   Expandir vistaContraer vista
    def cmd_aceptar_action(self, event):
        path = self.dlg.tree_folders.value
        files = app.get_files(path, 'ods')
        app.msgbox(files)
        return

Esta lista de archivos, esta lista para procesarse...

Saludos

Re: Control de Árbol (TreeControl).

NotaPublicado: Vie Jul 28, 2017 7:59 pm
por Dario Piedra
Listo Mauricio, ya apliqué los cambios y funciona de maravilla.

El valor o variable "files" almacena la ruta de cada uno de los archivos, sobre esta variable debo apoyarme para la instrucción de apertura de los archivos y empezar a copiarlos en el excel consolidado, cierto?

Saludos Cordiales;

Re: Control de Árbol (TreeControl).

NotaPublicado: Vie Jul 28, 2017 8:26 pm
por mauricio
Lee atentamente mis dos respuestas anteriores...

1.- Si, en files, vas a tener los archivos de la carpeta seleccionada, pero ojo, solo tendrás los archivos de la carpeta seleccionada, NO de las subcarpetas
2.- Si usas el segundo método que te propongo, entonces, solo le permites seleccionar la carpeta al usuario, y al procesar, obtenemos todos los ODS, incluyendo las subcarpetas.

Te recomiendo el segundo método.

Saludos

Re: Control de Árbol (TreeControl).

NotaPublicado: Vie Jul 28, 2017 10:24 pm
por Dario Piedra
Excelente Mauricio, muchísimas gracias por todo el apoyo.
Tal y como me indicaste usé el segundo método y en el Msgbox se muestra la ruta y nombre de cada archivo .ods encontrado en las subcarpetas.

Además viendo en la documentación veo que para abrir un archivo se utiliza el método .open(path) y usa como parámetro la ruta existente del archivo (path).
En este caso las rutas están almacenadas en "files", pero es más de una ruta, me parece que no serviría como parámetro para el método Open.

Por lo que veo el método get_files, retorna un arreglo, eso convertiría a "files" en un arreglo de direcciones, para procesarlo debería recorrer una a una las direcciones que están almacenadas y a su vez realizar los siguientes pasos:
1- Abrir en oculto.
2- Copiar las celdas de interés.
3- Cerrar el archivo.
4- Repetir proceso con todos los archivos.

De ser así, como podría recorrer "files"

Código: Seleccionar todo   Expandir vistaContraer vista
for path in files


Agradezco de antemano la ayuda brindada,

Saludos.

Re: Control de Árbol (TreeControl).

NotaPublicado: Vie Jul 28, 2017 11:05 pm
por mauricio
Exactamente, es el proceso correcto...
Código: Seleccionar todo   Expandir vistaContraer vista
    def cmd_aceptar_action(self, event):
        path = self.dlg.tree_folders.value
        files = app.get_files(path, 'ods')
        opciones = {'Hidden': True}
        for f in files:
            origen = app.open(f, opciones)
            #~ Aquí se obtienen los datos origen y se copian en destino
        return

Te recomiendo probar primero sin ocultar el archivo, con una carpeta que tenga uno o dos archivos, en cuanto todo este bien, ya puedes procesar los archivos de forma oculta y todos los que quieras.

Mira la documentación para saber como hacer referencia a hojas y celdas.

Saludos

Re: Control de Árbol (TreeControl).

NotaPublicado: Vie Jul 28, 2017 11:24 pm
por Dario Piedra
Entendido, mil gracias por la ayuda y consejos.
Voy a realizar la prueba con pocos datos y te comento

Sumamente amable Mauricio,
Bendiciones.

Re: Control de Árbol (TreeControl).

NotaPublicado: Sab Jul 29, 2017 1:13 am
por mauricio
Creo, si estas de acuerdo, que la pregunta inicial concreta de este tema esta resuelta. Si es así, por favor, marca como resuelto el tema y cualquier nueva duda concreta de easy-macro, abre un nuevo tema, para que no hagamos este hilo interminable.

Saludos

Re: [Resuelto] - Control de Árbol (TreeControl).

NotaPublicado: Sab Jul 29, 2017 1:43 am
por Dario Piedra
Listo! Espero haberlo marcado de forma correcta.
Saludos.