26 de enero de 2013

Arrastrar desde el Explorador y soltar en un cuadro de texto de Visual FoxPro

Artículo original: Drag and Drop from Explorer into a FoxPro TextBox
http://west-wind.com/weblog/posts/3135.aspx
Autor: Rick Strahl
Traducido por: Ana María Bisbé York

Esto parece ser algo muy trivial de hacer; pero no lo es. Mi caso de uso para este escenario es que alguien la semana pasada sugirió que sería muy bueno que el Help Builder (http://www.west-wind.com/wwHelp/) tuviera la capacidad de arrastrar imágenes directamente del explorador a la ventana de edición del Help Builder. Lo bueno en este caso es que puede dejar que el explorador siga funcionando mientras arrastra y suelta varias imágenes simultáneamente.

FoxPro admite arrastrar y soltar fácilmente mediante sus características Ole Drag & Drop que están en el producto desde 7.0 (Creo). Para controlar las acciones de arrastrar y soltar en un control desde una aplicación externa implemente el método OleDragOver que permite el control como un destino para soltar al consultar el dato arrastrado y luego establecer la propiedad OleDropHasData a un valor diferente de cero. Entonces, puede utilizar el evento OleDragDrop para hacer realmente lo que necesita en la acción Soltar.

Con archivos desde el explorador puede verificar un tipo de formato de 15 - controlador de archivos, que permite capturar una matriz de todos los archivos seleccionados para soltar.
* OleDragOver
LPARAMETERS oDataObject, nEffect, nButton, nShift, nXCoord, nYCoord, nState
*** Verificar los archivos
IF odataobject.GETFORMAT(15)
  THIS.OLEDROPHASDATA = 1
ENDIF

* OleDragDrop
LPARAMETERS oDataObject, nEffect, nButton, nShift, nXCoord, nYCoord
LOCAL lcText, lcOldPath, lcImage
IF oDataObject.GetFormat(15)
  DIMENSION laFiles[1]
  oDataObject.GetData(15,@laFiles)
  IF ALEN(laFiles,1) > 0
    lcText = ""
    lcImage = laFiles[1]
    lcext = LOWER(JUSTEXT(lcImage))
    DO CASE
      CASE INLIST(lcExt,"png","gif","jpg","bmp","TIF")
        *** Soltar una imagen
        lcOldPath = SYS(5) + CURDIR()
        CD (JUSTPATH(goHelp.oHelp.cFileName))
        lcRelImage = SYS(2014,lcImage)
        IF lcRelImage # ".."
          lcImage = lcRelImage
        ENDIF
        *** Convertir a mayúsculas
        lcImage = LongPath(lcImage)
        lcText = " " + THIS.cLTag + [img src="]+ lcImage +["]+THIS.cRTag 
        CD (lcOldPath)
    ENDCASE
    this.SelLength = 0
    this.SelText = lcText
  ENDIF
ENDIF
RETURN
Hasta aquí todo bien. Pero este código, en realidad no hace lo que yo quiero. Yo quiero que sea arrastrado hasta la ubicación de un cuadro de texto. Sin embargo, arrastrar y soltar archivos fuera del Explorador no tiene texto, sólo el formato que VFP va a soltar directamente, por lo que de forma predeterminada la operación Soltar no va a colocar los archivos en ningún lugar. Mi código modifica el formato de archivo de tal forma que lo convierte en formato de marcado del Help Builder que está embebido y es almacenado en lcText. Lo primero que pensé fue utilizar SelText para obligar al texto dentro del documento como se muestra arriba. Desafortunadamente no es fácil hacer este truco debido a que el texto es pegado en la posición actual del cursor, no a la posición del cursor al soltar. En realidad arrastrar y soltar no cambian la posición del cursor del cuadro de texto.
Entonces, hay un problema. Otra idea fue modificar el objeto DragAndDrop Data que se pasa utilizando SetData() y asignarle mi texto actualizado y cambiar el formato a 1.

Desafortunadamente, no trabaja, porque SetData() no puede ser llamado desde los eventos DragOver o DragDrop.

Entonces, finalmente la solución ha sido un poco más molesta y rebuscada. El evento OleDragDrop pasa unas coordenadas X y Y desde el formulario. Con esas coordenadas puede forzar el movimiento del cursor a esta posición forzando esencialmente el foco a la localización de SelText. Entonces, el código que funciona correctamente tiene el aspecto siguiente.
LPARAMETERS oDataObject, nEffect, nButton, nShift, nXCoord, nYCoord
LOCAL lcText, lcOldPath, lcImage

IF oDataObject.GetFormat(15)
  DIMENSION laFiles[1]
  oDataObject.GetData(15,@laFiles)
  IF ALEN(laFiles,1) > 0
    lcText = ""
    lcImage = laFiles[1]
    lcext = LOWER(JUSTEXT(lcImage))
    DO CASE
      CASE INLIST(lcExt,"png","gif","jpg","bmp","TIF")
        *** Soltar una imagen
        lcOldPath = SYS(5) + CURDIR()
        CD (JUSTPATH(goHelp.oHelp.cFileName))
        lcRelImage = SYS(2014,lcImage)
        IF lcRelImage # ".."
          lcImage = lcRelImage
        ENDIF
        *** Convertir a letra mayúscula
        lcImage = LongPath(lcImage)
        lcText = " " + THIS.cLTag + [img src="]+ lcImage +["]+THIS.cRTag 
        CD (lcOldPath)
    ENDCASE
    IF !EMPTY(lcText)
      *** Tomar la posición del ratón en la localización al soltar
      *** y obligar al puntero del ratón a esa posición
      MOUSE CLICK AT nYCoord,nXCoord PIXELS WINDOW (THISFORM.Name)
      DOEVENTS
      *** Leer un carácter para verificar los espacios 
      this.SelLength = 1
      IF this.SelText != " "
        lcText = lcText + " "
      ENDIF
      *** Ahora pegar al cursor
      SelLength = 0
      this.SelText = lcText
    ENDIF
  ENDIF
ENDIF
RETURN
Vea que se utiliza el comando MOUSE para forzar la localización del ratón. También es significativo el DOEVENTS que hace que el formulario se refresque antes de cambiar la localización SelText.

Esta forma de arrastrar y soltar en VFP es un poco raro en el TextBox. Puede arrastrar y soltar el cursor y luego verá - unos caracteres debajo, un acento circunflejo (`´) dibujado después. Esto parece un poco confuso. El cursor está donde ha sido soltado en realidad con el comportamiento correcto; pero el cursor muestra una molestia visual.

De cualquier manera aquí lo tiene - trabaja incluso si no es tan claro como yo hubiera esperado.

No hay comentarios. :

Publicar un comentario