consultas e impresiones en Harbor y Qt
29/09/2010
desde el ultimo reporte me he dedicada al desarrollo lo que por lo
menos para mi aplicacion es escencial y que las anteriores
versiones eran para mi un verdadero quebradero de cabeza.
Las consultas y las impresiones, que alguna manera me venia acercando
a unificar un unico modelo que permitiera que ambas opciones
co-existan de forma colaborativa , si tener qu hacer un desarrollo
para unas y para otros como ocurre en las versiones anteriores,
situacion impuesta por el problama del numero de caracteres y de los
distintos,visores , los cuales representan los caracteres ascII de
una forma mediore a menos que se ponga uno en la tarea de configurar
el editor para cada caso y modo de acceso desde el tipo de terminal.
esto me llevo a tener consultas firmemente ancladas a su presentacion en
pantalla y otras de papel, pudiendo en las primeras hacer uso ,
incluso abusivo en algunos de comprimidos y elongados para
aprovechar el espacio de impresion al maximo. cosa que desde luego no
tenia en las salidas por pantalla.
en esta nueva version y el poder que tien de la presentacion grafica
y la manera de pasar esta a la impresora con una buena definicion y
manteniendo las caracteristicas de pantalla , gracias al uso de
caracteres tipo COURIR y ARIAL, que mantiene la proporciones adecuadas
de impresion se facilito el modelo a seguir.
Lo primero es que gracias a que las librerias Qt , cuentan con una
herramienta verdaderamente interesante como es QTextEdit(), que es
un editor con muchas prestaciones y que incluso facilita el documento
del usuario de cara a la consulta o la impresion posterior, me aplique
en este periodo a la utilizacino de esta herramienta, si bien es
cierto que todo el enfasis lo hice en presentar un documento de
consulta sin capacidad de edicion, para que posteriorme este mismo
fuera impreso o gravado en un archivo independiente para su posterior
proesamiento en diferentes herramientas del sistema operativo del
usuario.
El sistema quedó diseñado de la siguiente forma.
El usurio crea una consulta que es desplegada en la pantalla del
usuario en formtato HTML, puro.
El usuario tiene la opcion de imprimir el documento o guardarlo como
un archivo en formato:
*.dbf, texto separado por comas (CVS), html o PDF.
Los primero fue crear una funcion que acondicione los datos de la
tabla de consulta de la tablas basicas a una tablas on los requisitos
de la consulta misma, en los cuales esta implicito el filtrado de
la informacion y formato de los campos de fecha y nuemericos mediante
el uso de transform(variableTmp,mask).
donde variableTmp es la variable a trasformar y mask es la mascara de la
presentacion de datos que se quiere mostrar.
un ejemplo del condicionamiento de la infromacion es la siguiente:
En este caso concreto se tiene una bvase datos con la informacion
de los terceros con los cuales la empresa tiene relacion comercial.
llamda tabla de NIT.
1) En primer lugar creamos un arreglo de los campos que queremos
mostrar en la consulta con el nombre que el usuario pueda
identificar en la pantalla (columna 1 del arreglo) y en
la columna dos el nombre del campo de la tabla que vamos a
desplegar.
c[1 ,1] := Tr("RUT") ; c[1 ,2] := "NIT"
c[2 ,1] := Tr("C") ; c[2 ,2] := "COD_CTRL"
c[3 ,1] := Tr("Nombre") ; c[3 ,2] := "NOMBRE"
c[4 ,1] := Tr("Telefono") ; c[4 ,2] := "TELEFONO"
c[5 ,1] := Tr("Direccion") ; c[5 ,2] := "DIRECCION"
c[6 ,1] := Tr("Pais") ; c[6 ,2] := "PAIS"
c[7 ,1] := Tr("Departamento") ; c[7 ,2] := "DEPARTAMEN"
c[8 ,1] := Tr("Ciudad") ; c[8 ,2] := "CIUDAD"
c[9 ,1] := Tr("Razon social") ; c[9 ,2] := "RAZON_SOCI"
c[10,1] := Tr("Representante") ; c[10,2] := "REPRESENTA"
c[11,1] := Tr("E-Mail") ; c[11,2] := "E_MAIL"
c[12,1] := Tr("Sitio WEB") ; c[12,2] := "WEB"
2) Creamos la estructura de la consulta en una tabla alterna,
que con objeto de recordaciion simpre llamo PRESENTA.dbf
Un un principo yo era muy renuente a crear este tipo de estructuras
de copiar una tabla en otro y preferia vaciar la informacio que se
iba desplegando, aunque es muy eficiente en consumo de recursos
el modelo de programacion se vuelve muy casuistico y dificil de
darle mantenimiento, ademas con las maquinas actuales con capacidad
de memoraria y disco duro no es cosa que preocupe demaciado.
archivo1 := chr(34) + presenta_ + chr(34)
select 10
dbcreate(&archivo1, ;
{ ;
{ c[ 1,2] ,"C", 10,0}, ;
{ c[ 2,2] ,"C", 1,0}, ;
{ c[ 3,2] ,"C", 50,0}, ;
{ c[ 4,2] ,"C", 50,0}, ;
{ c[ 5,2] ,"C", 50,0}, ;
{ c[ 6,2] ,"C", 50,0}, ;
{ c[ 7,2] ,"C", 50,0}, ;
{ c[ 8,2] ,"C", 50,0}, ;
{ c[ 9,2] ,"C", 50,0}, ;
{ c[10,2] ,"C", 50,0}, ;
{ c[11,2] ,"C", 50,0}, ;
{ c[12,2] ,"C", 50,0} ;
} ;
)
select 10
use &presenta_ alias PRESENTA
3) Vacio la informacion de NIT a presenta y hagos las transformaciones
y calculos del caso si hubiera lugar, en este caso particular no fue
necesario y se vacia la informacion tal cual, podria incluso haber
usado la tabla de forma directa sin nngun contra tiempo, pero como lo
que se trata es que el modelo sea generico, no me preocupo si es o no
identica a PRESENTA, es una plantilla que se llena y se espera que
funcione igua para cualquier consulta por simple o sofisticada que sea.
select NIT
goto top
do while .not. eof()
select PRESENTA
append blank
store rlock() to verror
replace NIT with NIT -> NIT
replace COD_CTRL with NIT -> COD_CTRL
replace NOMBRE with NIT -> NOMBRE
replace TELEFONO with NIT -> TELEFONO
replace DIRECCION with NIT -> DIRECCION
replace PAIS with NIT -> PAIS
replace DEPARTAMEN with NIT -> DEPARTAMEN
replace CIUDAD with NIT -> CIUDAD
replace RAZON_SOCI with NIT -> RAZON_SOCI
replace REPRESENTA with NIT -> REPRESENTA
replace E_MAIL with NIT -> E_MAIL
replace WEB with NIT -> WEB
unlock
select NIT
skip
enddo
4) Si la tabla PRESENTA no tiene informacion advierte al usuario
y termina la consulta.
select PRESENTA
if eof()
textoTmp = "No hay items para consultar"
ms := MsgInfo(TextoTmp,MSG_WARNING)
RETURN CANCELAR
endif
5) Si la tabla contiene informacion llama la FUNCION consultar
con los siguientes parametros.
H1 : Consultar(param1,param2,param3,param4) //consulta en formato Html
param1 :: Un texto a mostrar con la consulta.
param2 :: Es un arreglo de 2 columnas la primera columna con el
nombre a mostrar al usuario y que de hecho varia dependiendo
de la variable LOCAL (fecha, lenguaje,moneda etc) y la
segunda el nombre del acampo asociado al nombre en la tabla
presenta.
en este caso c[nombre, campo]
param3 :: el tipo de formato de salida, aunque en este caso concreto
me entre en hacer todo el desarrollo en formato Html para
ser presentado por QTextEdit en forma RICH, no es limitante
y puede ser desarraldo el modelo de consultq para QListView
sin que la estructura subra alteracion. ("H" -> html)
param4 :: nombre canonico del la tabla PRESENTA, le recuerdo que yo no
suelo usar nombre propios para las tablas dianmicas sino que
les doy nombre randomicos, como se explico akl inicio de
esta bitacora.
H1 := Consultar(textoTmp,C,"H",presenta_) //consulta en formato Html
-----------------------------------------------------------------
la funcion consulta es un menu para elegir la accion hacer una vez
ls consulta sea hecha y llama la funcion de presentacion de datos
en este caso concreto solo tengo una que es Html, que como se dijo
ya anteriormente desplega en el el objeto QTextEdit() la informacion
tipo texto rich (html)
Se genra un dialogo donde usario selccina lo que desea hacer con la
informacion que esta en pantalla, imprimir o grabar en archivo o
salir.
la funcion:
GG := HtmlK(NIL, textoTmp, variableTmp)
es la encargada de desplegar la informacion de la consulta
GG := HtmlK(param1, param2, param3)
param1 := un objeto asociado a la venta o dialogo dende la
consulta va a ser desplegada , en este caso es un
dialog flotante. (NIL)
param2 := Texto que encabeza la presentacion de la ventana del
objeto QTextEdit()
param3 := es el arreglo heredado de consulta con los nombre
a ser vistos por el usuario y los campos de la tabla
presenta. /ver param2 de la funcion consulta , arriba.
retorna un objeto con el contenido del la presentacion en este
caso un objeto QTextedito que puede ser impreso o
grabado.
GG := HtmlK(NIL, textoTmp, variableTmp)
FUNCTION Consultar(textoTmp,variableTmp,tipoTmp,archivoTmp)
#define QT_EVE_CLICKED "clicked()"
LOCAL S1,GG
LOCAL winD, layoP, layoD, layoB
LOCAL archivoB, imprimirB, cancelarB
LOCAL iExit := .F.
LOCAL aExit := .F.
LOCAL cExit := .F.
LOCAL elegido_ := ACEPTAR
LOCAL salida_ := ""
LOCAL pathS := pathI_ + look + slash
do case
case tipoTmp == "H" // presentacion en formato Html
GG := HtmlK(NIL, textoTmp, variableTmp)
endcase
layoP := QVBoxLayout():new()
layoD := QVBoxLayout():new()
layoB := QHBoxLayout():new()
winD := QMainWindow():new()
winD : setWindowTitle(textoTmp)
winD : setStyleSheet(cssK(CSS_GET))
winD : setMouseTracking( .T. )
winD : resize(X(80),Y(25))
winD : setWindowIcon( pathS + "Ksos" )
oDA := QWidget():new( winD )
oDA : setStyleSheet(cssK(CSS_GET))
S1 := SayK(NIL,,,textoTmp,Y(02),X(50))
imprimirB := PushButtonK(NIL,,,Tr("Imprimir"), pathS + "Printer.gif" ,,)
archivoB := PushButtonK(NIL,,,Tr("archivo") , pathS + "Archivo.gif" ,,)
cancelarB := PushButtonK(NIL,,,Tr("Cancelar"), pathS + "Cancelar.jpeg",,)
cancelarB : setDefault(.T.)
layoD : addWidget(S1)
layoD : addWidget(GG)
layoD : sizeConstraint(1)
layoB : addWidget(imprimirB)
layoB : addWidget(archivoB)
layoB : addWidget(cancelarB)
layoP : addLayout(layoD)
layoP : addLayout(LayoB)
oDA : setLayout(layoP)
winD : setCentralWidGet(oDA)
winD : show()
Qt_Connect_Signal(imprimirB,QT_EVE_CLICKED, {|| iExit := .T. })
Qt_Connect_Signal(archivoB ,QT_EVE_CLICKED, {|| aExit := .T. })
Qt_Connect_Signal(cancelarB,QT_EVE_CLICKED, {|| cExit := .T. })
oEventLoop := QEventLoop():new( oDA )
do while .T.
oEventLoop:processEvents()
if aExit .or. iExit .or. cExit
exit
endif
enddo
oEventLoop:exit( 0 )
oEventLoop := 0
HB_GCALL( .T.)
do case
case cExit
elegido_ := CANCELAR
case iExit
imprimirArchivo(GG)
case aExit
copiarArchivo(GG,archivoTmp)
endcase
Inicio("I")
RETURN {GG,salida_,elegido_}
-----------------------------------------------------------------
En la funcioon es de interes observas los siguientes puntos:
1. Se crea un dialogo con Un progress bar para mostrar el
proceso de llenado del QTextEdit() , en realidad lleno una
variable llamda textoHtml con la informaacion necesaria y
luego la inserto en el campo de texto de QTextEdit(), la
informacion de QTextEdit() recominda usar directamente append()
pero a mi no me funciono, mas adelante tengo que ver que pasa
pues si las consultas con muy eshaustivas puede tner problemas
con este tipo de conformacion de variabe, fuera de que hago la
carga dos veces lo que ya si es muy ineficiente, par pequeñas
no vale la pena pero si son grandes la cosa es seria pues tengo
informacion duplicada en textoHtml y en el objeto QTextEdit()
Se debe obsrvar que no abrio el objeto sino hasta que termino
de conformar la cosnulta html, esto lo hice asi , pues note que
si habra todo el principo y dejo el show() , para el final la
presentacion se demora muchisimo, asi comoo esta es casi
instantanea la presentacion.
al final muevo el cursor al principio del documento.
FUNCTION HtmlK(ksosObj, textoTmp, varArr)
LOCAL oText, layoP, winD
layoP := QVBoxLayout():new()
winD := QDialog():new()
winD : setWindowTitle(textoTmp)
winD : setStyleSheet(cssK(CSS_GET))
B1 := ProgressBarK(NIL ,,, 0, Y(02) ,X(80),1,reccount())
layoP : addWidget(B1)
winD : setLayout(layoP)
winD : show()
k := 1
textoHtml := ""
textoHtml += ""
/**
Crea la tabla y su cabecera con los titulos de los campos de la
tabla que se esta tabulando.
*/
textoHtml := ""
textoHtml += "" textoHtml += "" textoHtml += "" textoHtml += Cia + " " textoHtml += "" textoHtml += "" textoHtml += CiaNit + " " textoHtml += "" textoHtml += "" textoHtml += " " textoHtml += "" textoHtml += "" textoHtml += ""
textoHtml += "" textoHtml += "" textoHtml += " " textoHtml += "
"
textoHtml += "" textoHtml += " " for i = 1 to len( varArr ) textoHtml += "" textoHtml += "" textoHtml += "" textoHtml += "" textoHtml += "" next textoHtml += " " textoHtml += "" /** Llena la tabla con el contenido del arreglo en varArr */ goto top do while .not. eof() if (round(k/2,0)*2 <> k) textoHtml += " " else textoHtml += " " endif for i := 1 to len( varArr ) textoHtml += "" next textoHtml += " " k++ B1:setValue(k) skip enddo textoHtml += "
"
textoHtml += ""
textoTmp += "
"
textoHtml += ""
textoHtml += PiePagina()
textoHtml += ""
textoHtml += " "
textoHtml += ""
textoHtml += ""
winD := NIL
oText := QTextEdit():new(ksosObj)
oText : setReadOnly(.T.)
oText : acceptRichText( .T. )
oText : autoFormatting( 0xffffffff )
otext : createStandardContextMenu()
oText : resize(X(80),Y(20))
oText : insertHtml(textoHtml)
/** moveCursor(param1,param2) : Coloca el cursor a una posicion
param1 :: 1 = Inicio 11 = Final
param2 :: 0 mantine el de tamano minimo del cursos
*/
oText : moveCursor(1,0)
oText : show()
RETURN oText
----------------------------------------------------------------------
Siguiendo con la funcion consulta() , se observa el llamado a 2
funciones
do case
case aExit
copiarArchivo(GG,archivoTmp)
case iExit
imprimirArchivo(GG)
endcase
copiar archivo, guarda el objeto QTextEdit() y la segunda lo imprime.
la copia de archivo facilita difereentes mecanismois de soporte.
*.dbf , lo usan mis usuarios para facilitar el trasporte de
informaciona excel
*. html , usan para pegarlo a documentos de trabajo o enviar la
informacion por e-mail
* text (cvs) , para algunos prograsm que requieren importatr
informacion en este formato
la impresion permite dar salia a la consulta o incluso a otro archivo
con formato PDF, para tener una o foto de la inforamcion una vez
incorporada la clave de seguridad para que esta no sea modificada.
Para destacar la simplicidad del la rutina de impresion,
QPrintDialog, permite crear un dialogo sonde se eligen la impresora
de salida de impresion y caracteristicas basicas como margens ,
orientacion
QPrintDialog regresa un objeto en el cual se pueden acceder asus
metodos los caules aun antes de la impresino pueden ser modificados
haciendo uso de los paramtros de QPrint(), el metodo exec(), devuelve
un 0 o 1
0 :: Cancelar
1 :: Imprimir
La funcion crearArchivo hace uso de distintos modelos de creacion
de archivos segun la extension, desde un simple renombrado de la
tabla PRESENTA con copy file, hasta el us de memowrit() oar salvar
el contenido del objeto QTextEdit() en un archivo html.
El texto se hace con el comadno copy con delmitador ","
/*-------------------------------------------------------------------*/
/*
Hace una copia del archivo de consulta
en un un archivo PDF o en una impresora de
la red
@author Carlos Arturo castano
@date 25/09/2010
*/
FUNCTION imprimirArchivo(ksosObj, archivoTmp)
impresora := QPrintDialog():new()
if (impresora : exec() == 0)
RETURN NIL
endif
ksosObj : print(impresora:printer)
RETURN NIL
/*-------------------------------------------------------------------*/
/*
Hace una copia del archivo de consulta
en un archivo del usuario.
La recibre como parametro dos tipos de informacion
si la ext == ".dbf" los datos a ser copiados estan
en un archivo DBF y la funcion los guarda en un archivo
elegido por el usuario en la varaible salida_
si la ext == ".html" los datos estan en el primer parametro
de la funcion copiarArchivo(oaram1,param2,param3)
param1 :: es un objeto tipo rich text
param2 :: es el nombre de la tabla desde donde se creo la
informacion desplegada en la consulta
param3 :: es el tipo de archivo de salida
la funcion los guarda en un archivo elegido por el
usuario
Si la ext == ".txt" los datos son grabados en un archivo plano
con extensión -txt y los campos delimitados por comas (CVS)
@author Carlos Arturo castano
@date 25/09/2010
*/
FUNCTION copiarArchivo(ksosObj, archivoTmp)
LOCAL textoTmp, variableTmp, salida_, archV, digiTmp
LOCAL dd, mm, exTmp
LOCAL creado := NO
LOCAL arrTmp[3,3]
LOCAL winC, layoC, G1, C1, R1
LOCAL aExit := .T.
LOCAL cExit := .F.
dd := right("00" + ltrim(str(day (date),2)),2)
mm := right("00" + ltrim(str(month(date),2)),2)
digiTmp := left(digitador,4)
variableTmp := home + slash + "pro" + slash
variableTmp += digiTmp + "_" + dd + mm
variableTmp := lower(left(variableTmp + space(50),50))
textoTmp := Tr("Nombre del archivo de salida")
arrTmp[1,1] := "xbase [.dbf]" ; arrTmp[1,2] := "" ; arrTmp[1,3]:= ".dbf"
arrTmp[2,1] := "web [.html]" ; arrTmp[2,2] := "" ; arrTmp[2,3]:= ".html"
arrTmp[3,1] := "texto [.cvs]" ; arrTmp[3,2] := "" ; arrTmp[3,3]:= ".txt"
layoP := QVBoxLayout():new()
layoD := QFormLayout():new()
layoB := QHBoxLayout():new()
winD := QDialog():new()
winD : setWindowTitle(textoTmp)
winD : setStyleSheet(cssK(CSS_SAY))
winD : setSizeGripEnabled(.T.)
pathS := pathI_ + look + slash
aceptarB := PushButtonK(NIL,,,Tr("Aceptar") ,pathS + "Aceptar.jpeg" ,,)
cancelarB := PushButtonK(NIL,,,Tr("Cancelar"),pathS + "Cancelar.jpeg",,)
aceptarB : setDefault(.T.)
G1 := GetK(NIL ,,,variableTmp,Y(02),X(50),50)
C1 := ComboBoxK(NIL,,, arrTmp, Y(02), X(50) )
layoD : addrow_3("&" + textoTmp , G1)
layoD : addrow_3("&" + Tr("Tipo de archivo"), C1)
layoB : addWidget(aceptarB)
layoB : addWidget(cancelarB)
layoP : addLayout(layoD)
layoP : addLayout(LayoB)
winD : setLayout(layoP)
Qt_Connect_Signal(aceptarB ,QT_EVE_CLICKED, {|| aExit := .T. ,winD:accept() })
Qt_Connect_Signal(cancelarB,QT_EVE_CLICKED, {|| cExit := .T. ,winD:reject() })
winD : exec()
if (cExit)
RETURN NIL
endif
//en extTmp esta el tipo archivo de de salida
extTmp := arrTmp[ C1 : currentIndex() + 1, 3 ]
salida_ := G1 : text + extTmp
archV := chr(34) + salida_ + chr(34)
archivoTmp += ".dbf" // El archivo de tablas siempre es .dbf
close databases
do case
case extTmp == ".dbf"
copy file &archivoTmp to &salida_
if file(&archV)
creado := SI
endif
case extTmp == ".html"
if (memoWrit(salida_, ksosObj : toHtml, .T.))
creado := SI
endif
case extTmp == ".txt"
select 10
use &archivoTmp alias PRESENTA
copy to &salida_ DELIMITED with ","
if file(&archV)
creado := SI
endif
endcase
if (creado == SI)
textoTmp := Tr("Archivo creado exitosamente") + "
"
textoTmp += ResaltarK(archV)
else
textoTmp := Tr("Archivo no fue creado") + "
"
textoTmp += ResaltarK(archV)
endif
ms := MsgInfo(textoTmp,MSG_INFORMATIVO)
RETURN NIL
desde el ultimo reporte me he dedicada al desarrollo lo que por lo
menos para mi aplicacion es escencial y que las anteriores
versiones eran para mi un verdadero quebradero de cabeza.
Las consultas y las impresiones, que alguna manera me venia acercando
a unificar un unico modelo que permitiera que ambas opciones
co-existan de forma colaborativa , si tener qu hacer un desarrollo
para unas y para otros como ocurre en las versiones anteriores,
situacion impuesta por el problama del numero de caracteres y de los
distintos,visores , los cuales representan los caracteres ascII de
una forma mediore a menos que se ponga uno en la tarea de configurar
el editor para cada caso y modo de acceso desde el tipo de terminal.
esto me llevo a tener consultas firmemente ancladas a su presentacion en
pantalla y otras de papel, pudiendo en las primeras hacer uso ,
incluso abusivo en algunos de comprimidos y elongados para
aprovechar el espacio de impresion al maximo. cosa que desde luego no
tenia en las salidas por pantalla.
en esta nueva version y el poder que tien de la presentacion grafica
y la manera de pasar esta a la impresora con una buena definicion y
manteniendo las caracteristicas de pantalla , gracias al uso de
caracteres tipo COURIR y ARIAL, que mantiene la proporciones adecuadas
de impresion se facilito el modelo a seguir.
Lo primero es que gracias a que las librerias Qt , cuentan con una
herramienta verdaderamente interesante como es QTextEdit(), que es
un editor con muchas prestaciones y que incluso facilita el documento
del usuario de cara a la consulta o la impresion posterior, me aplique
en este periodo a la utilizacino de esta herramienta, si bien es
cierto que todo el enfasis lo hice en presentar un documento de
consulta sin capacidad de edicion, para que posteriorme este mismo
fuera impreso o gravado en un archivo independiente para su posterior
proesamiento en diferentes herramientas del sistema operativo del
usuario.
El sistema quedó diseñado de la siguiente forma.
El usurio crea una consulta que es desplegada en la pantalla del
usuario en formtato HTML, puro.
El usuario tiene la opcion de imprimir el documento o guardarlo como
un archivo en formato:
*.dbf, texto separado por comas (CVS), html o PDF.
Los primero fue crear una funcion que acondicione los datos de la
tabla de consulta de la tablas basicas a una tablas on los requisitos
de la consulta misma, en los cuales esta implicito el filtrado de
la informacion y formato de los campos de fecha y nuemericos mediante
el uso de transform(variableTmp,mask).
donde variableTmp es la variable a trasformar y mask es la mascara de la
presentacion de datos que se quiere mostrar.
un ejemplo del condicionamiento de la infromacion es la siguiente:
En este caso concreto se tiene una bvase datos con la informacion
de los terceros con los cuales la empresa tiene relacion comercial.
llamda tabla de NIT.
1) En primer lugar creamos un arreglo de los campos que queremos
mostrar en la consulta con el nombre que el usuario pueda
identificar en la pantalla (columna 1 del arreglo) y en
la columna dos el nombre del campo de la tabla que vamos a
desplegar.
c[1 ,1] := Tr("RUT") ; c[1 ,2] := "NIT"
c[2 ,1] := Tr("C") ; c[2 ,2] := "COD_CTRL"
c[3 ,1] := Tr("Nombre") ; c[3 ,2] := "NOMBRE"
c[4 ,1] := Tr("Telefono") ; c[4 ,2] := "TELEFONO"
c[5 ,1] := Tr("Direccion") ; c[5 ,2] := "DIRECCION"
c[6 ,1] := Tr("Pais") ; c[6 ,2] := "PAIS"
c[7 ,1] := Tr("Departamento") ; c[7 ,2] := "DEPARTAMEN"
c[8 ,1] := Tr("Ciudad") ; c[8 ,2] := "CIUDAD"
c[9 ,1] := Tr("Razon social") ; c[9 ,2] := "RAZON_SOCI"
c[10,1] := Tr("Representante") ; c[10,2] := "REPRESENTA"
c[11,1] := Tr("E-Mail") ; c[11,2] := "E_MAIL"
c[12,1] := Tr("Sitio WEB") ; c[12,2] := "WEB"
2) Creamos la estructura de la consulta en una tabla alterna,
que con objeto de recordaciion simpre llamo PRESENTA.dbf
Un un principo yo era muy renuente a crear este tipo de estructuras
de copiar una tabla en otro y preferia vaciar la informacio que se
iba desplegando, aunque es muy eficiente en consumo de recursos
el modelo de programacion se vuelve muy casuistico y dificil de
darle mantenimiento, ademas con las maquinas actuales con capacidad
de memoraria y disco duro no es cosa que preocupe demaciado.
archivo1 := chr(34) + presenta_ + chr(34)
select 10
dbcreate(&archivo1, ;
{ ;
{ c[ 1,2] ,"C", 10,0}, ;
{ c[ 2,2] ,"C", 1,0}, ;
{ c[ 3,2] ,"C", 50,0}, ;
{ c[ 4,2] ,"C", 50,0}, ;
{ c[ 5,2] ,"C", 50,0}, ;
{ c[ 6,2] ,"C", 50,0}, ;
{ c[ 7,2] ,"C", 50,0}, ;
{ c[ 8,2] ,"C", 50,0}, ;
{ c[ 9,2] ,"C", 50,0}, ;
{ c[10,2] ,"C", 50,0}, ;
{ c[11,2] ,"C", 50,0}, ;
{ c[12,2] ,"C", 50,0} ;
} ;
)
select 10
use &presenta_ alias PRESENTA
3) Vacio la informacion de NIT a presenta y hagos las transformaciones
y calculos del caso si hubiera lugar, en este caso particular no fue
necesario y se vacia la informacion tal cual, podria incluso haber
usado la tabla de forma directa sin nngun contra tiempo, pero como lo
que se trata es que el modelo sea generico, no me preocupo si es o no
identica a PRESENTA, es una plantilla que se llena y se espera que
funcione igua para cualquier consulta por simple o sofisticada que sea.
select NIT
goto top
do while .not. eof()
select PRESENTA
append blank
store rlock() to verror
replace NIT with NIT -> NIT
replace COD_CTRL with NIT -> COD_CTRL
replace NOMBRE with NIT -> NOMBRE
replace TELEFONO with NIT -> TELEFONO
replace DIRECCION with NIT -> DIRECCION
replace PAIS with NIT -> PAIS
replace DEPARTAMEN with NIT -> DEPARTAMEN
replace CIUDAD with NIT -> CIUDAD
replace RAZON_SOCI with NIT -> RAZON_SOCI
replace REPRESENTA with NIT -> REPRESENTA
replace E_MAIL with NIT -> E_MAIL
replace WEB with NIT -> WEB
unlock
select NIT
skip
enddo
4) Si la tabla PRESENTA no tiene informacion advierte al usuario
y termina la consulta.
select PRESENTA
if eof()
textoTmp = "No hay items para consultar"
ms := MsgInfo(TextoTmp,MSG_WARNING)
RETURN CANCELAR
endif
5) Si la tabla contiene informacion llama la FUNCION consultar
con los siguientes parametros.
H1 : Consultar(param1,param2,param3,param4) //consulta en formato Html
param1 :: Un texto a mostrar con la consulta.
param2 :: Es un arreglo de 2 columnas la primera columna con el
nombre a mostrar al usuario y que de hecho varia dependiendo
de la variable LOCAL (fecha, lenguaje,moneda etc) y la
segunda el nombre del acampo asociado al nombre en la tabla
presenta.
en este caso c[nombre, campo]
param3 :: el tipo de formato de salida, aunque en este caso concreto
me entre en hacer todo el desarrollo en formato Html para
ser presentado por QTextEdit en forma RICH, no es limitante
y puede ser desarraldo el modelo de consultq para QListView
sin que la estructura subra alteracion. ("H" -> html)
param4 :: nombre canonico del la tabla PRESENTA, le recuerdo que yo no
suelo usar nombre propios para las tablas dianmicas sino que
les doy nombre randomicos, como se explico akl inicio de
esta bitacora.
H1 := Consultar(textoTmp,C,"H",presenta_) //consulta en formato Html
-----------------------------------------------------------------
la funcion consulta es un menu para elegir la accion hacer una vez
ls consulta sea hecha y llama la funcion de presentacion de datos
en este caso concreto solo tengo una que es Html, que como se dijo
ya anteriormente desplega en el el objeto QTextEdit() la informacion
tipo texto rich (html)
Se genra un dialogo donde usario selccina lo que desea hacer con la
informacion que esta en pantalla, imprimir o grabar en archivo o
salir.
la funcion:
GG := HtmlK(NIL, textoTmp, variableTmp)
es la encargada de desplegar la informacion de la consulta
GG := HtmlK(param1, param2, param3)
param1 := un objeto asociado a la venta o dialogo dende la
consulta va a ser desplegada , en este caso es un
dialog flotante. (NIL)
param2 := Texto que encabeza la presentacion de la ventana del
objeto QTextEdit()
param3 := es el arreglo heredado de consulta con los nombre
a ser vistos por el usuario y los campos de la tabla
presenta. /ver param2 de la funcion consulta , arriba.
retorna un objeto con el contenido del la presentacion en este
caso un objeto QTextedito que puede ser impreso o
grabado.
GG := HtmlK(NIL, textoTmp, variableTmp)
FUNCTION Consultar(textoTmp,variableTmp,tipoTmp,archivoTmp)
#define QT_EVE_CLICKED "clicked()"
LOCAL S1,GG
LOCAL winD, layoP, layoD, layoB
LOCAL archivoB, imprimirB, cancelarB
LOCAL iExit := .F.
LOCAL aExit := .F.
LOCAL cExit := .F.
LOCAL elegido_ := ACEPTAR
LOCAL salida_ := ""
LOCAL pathS := pathI_ + look + slash
do case
case tipoTmp == "H" // presentacion en formato Html
GG := HtmlK(NIL, textoTmp, variableTmp)
endcase
layoP := QVBoxLayout():new()
layoD := QVBoxLayout():new()
layoB := QHBoxLayout():new()
winD := QMainWindow():new()
winD : setWindowTitle(textoTmp)
winD : setStyleSheet(cssK(CSS_GET))
winD : setMouseTracking( .T. )
winD : resize(X(80),Y(25))
winD : setWindowIcon( pathS + "Ksos" )
oDA := QWidget():new( winD )
oDA : setStyleSheet(cssK(CSS_GET))
S1 := SayK(NIL,,,textoTmp,Y(02),X(50))
imprimirB := PushButtonK(NIL,,,Tr("Imprimir"), pathS + "Printer.gif" ,,)
archivoB := PushButtonK(NIL,,,Tr("archivo") , pathS + "Archivo.gif" ,,)
cancelarB := PushButtonK(NIL,,,Tr("Cancelar"), pathS + "Cancelar.jpeg",,)
cancelarB : setDefault(.T.)
layoD : addWidget(S1)
layoD : addWidget(GG)
layoD : sizeConstraint(1)
layoB : addWidget(imprimirB)
layoB : addWidget(archivoB)
layoB : addWidget(cancelarB)
layoP : addLayout(layoD)
layoP : addLayout(LayoB)
oDA : setLayout(layoP)
winD : setCentralWidGet(oDA)
winD : show()
Qt_Connect_Signal(imprimirB,QT_EVE_CLICKED, {|| iExit := .T. })
Qt_Connect_Signal(archivoB ,QT_EVE_CLICKED, {|| aExit := .T. })
Qt_Connect_Signal(cancelarB,QT_EVE_CLICKED, {|| cExit := .T. })
oEventLoop := QEventLoop():new( oDA )
do while .T.
oEventLoop:processEvents()
if aExit .or. iExit .or. cExit
exit
endif
enddo
oEventLoop:exit( 0 )
oEventLoop := 0
HB_GCALL( .T.)
do case
case cExit
elegido_ := CANCELAR
case iExit
imprimirArchivo(GG)
case aExit
copiarArchivo(GG,archivoTmp)
endcase
Inicio("I")
RETURN {GG,salida_,elegido_}
-----------------------------------------------------------------
En la funcioon es de interes observas los siguientes puntos:
1. Se crea un dialogo con Un progress bar para mostrar el
proceso de llenado del QTextEdit() , en realidad lleno una
variable llamda textoHtml con la informaacion necesaria y
luego la inserto en el campo de texto de QTextEdit(), la
informacion de QTextEdit() recominda usar directamente append()
pero a mi no me funciono, mas adelante tengo que ver que pasa
pues si las consultas con muy eshaustivas puede tner problemas
con este tipo de conformacion de variabe, fuera de que hago la
carga dos veces lo que ya si es muy ineficiente, par pequeñas
no vale la pena pero si son grandes la cosa es seria pues tengo
informacion duplicada en textoHtml y en el objeto QTextEdit()
Se debe obsrvar que no abrio el objeto sino hasta que termino
de conformar la cosnulta html, esto lo hice asi , pues note que
si habra todo el principo y dejo el show() , para el final la
presentacion se demora muchisimo, asi comoo esta es casi
instantanea la presentacion.
al final muevo el cursor al principio del documento.
FUNCTION HtmlK(ksosObj, textoTmp, varArr)
LOCAL oText, layoP, winD
layoP := QVBoxLayout():new()
winD := QDialog():new()
winD : setWindowTitle(textoTmp)
winD : setStyleSheet(cssK(CSS_GET))
B1 := ProgressBarK(NIL ,,, 0, Y(02) ,X(80),1,reccount())
layoP : addWidget(B1)
winD : setLayout(layoP)
winD : show()
k := 1
textoHtml := ""
textoHtml += ""
/**
Crea la tabla y su cabecera con los titulos de los campos de la
tabla que se esta tabulando.
*/
textoHtml := "
textoHtml += "" textoHtml += "" textoHtml += "" textoHtml += Cia + " " textoHtml += "" textoHtml += "" textoHtml += CiaNit + " " textoHtml += "" textoHtml += "" textoHtml += " " textoHtml += "" textoHtml += "" textoHtml += ""
textoHtml += "" textoHtml += "" textoHtml += " " textoHtml += "
" textoHtml += dtoc(date()) textoHtml += " | " textoHtml += replicate("_",50) textoHtml += " | " textoHtml += textoTmp textoHtml += " | " textoHtml += replicate("_",50) textoHtml += " | " textoHtml += time() textoHtml += " |
---|
textoHtml += "" textoHtml += " " for i = 1 to len( varArr ) textoHtml += "" textoHtml += "" textoHtml += "" textoHtml += "" textoHtml += "" next textoHtml += " " textoHtml += "" /** Llena la tabla con el contenido del arreglo en varArr */ goto top do while .not. eof() if (round(k/2,0)*2 <> k) textoHtml += " " else textoHtml += " " endif for i := 1 to len( varArr ) textoHtml += "" next textoHtml += " " k++ B1:setValue(k) skip enddo textoHtml += "
" + varArr[i,1] + " |
---|
" textoHtml += "" sos := varArr[i,2] textoHtml += &sos textoTmp += "" textoTmp += " |
textoHtml += ""
textoTmp += "
"
textoHtml += ""
textoHtml += PiePagina()
textoHtml += ""
textoHtml += "
textoHtml += ""
textoHtml += ""
winD := NIL
oText := QTextEdit():new(ksosObj)
oText : setReadOnly(.T.)
oText : acceptRichText( .T. )
oText : autoFormatting( 0xffffffff )
otext : createStandardContextMenu()
oText : resize(X(80),Y(20))
oText : insertHtml(textoHtml)
/** moveCursor(param1,param2) : Coloca el cursor a una posicion
param1 :: 1 = Inicio 11 = Final
param2 :: 0 mantine el de tamano minimo del cursos
*/
oText : moveCursor(1,0)
oText : show()
RETURN oText
----------------------------------------------------------------------
Siguiendo con la funcion consulta() , se observa el llamado a 2
funciones
do case
case aExit
copiarArchivo(GG,archivoTmp)
case iExit
imprimirArchivo(GG)
endcase
copiar archivo, guarda el objeto QTextEdit() y la segunda lo imprime.
la copia de archivo facilita difereentes mecanismois de soporte.
*.dbf , lo usan mis usuarios para facilitar el trasporte de
informaciona excel
*. html , usan para pegarlo a documentos de trabajo o enviar la
informacion por e-mail
* text (cvs) , para algunos prograsm que requieren importatr
informacion en este formato
la impresion permite dar salia a la consulta o incluso a otro archivo
con formato PDF, para tener una o foto de la inforamcion una vez
incorporada la clave de seguridad para que esta no sea modificada.
Para destacar la simplicidad del la rutina de impresion,
QPrintDialog, permite crear un dialogo sonde se eligen la impresora
de salida de impresion y caracteristicas basicas como margens ,
orientacion
QPrintDialog regresa un objeto en el cual se pueden acceder asus
metodos los caules aun antes de la impresino pueden ser modificados
haciendo uso de los paramtros de QPrint(), el metodo exec(), devuelve
un 0 o 1
0 :: Cancelar
1 :: Imprimir
La funcion crearArchivo hace uso de distintos modelos de creacion
de archivos segun la extension, desde un simple renombrado de la
tabla PRESENTA con copy file, hasta el us de memowrit() oar salvar
el contenido del objeto QTextEdit() en un archivo html.
El texto se hace con el comadno copy con delmitador ","
/*-------------------------------------------------------------------*/
/*
Hace una copia del archivo de consulta
en un un archivo PDF o en una impresora de
la red
@author Carlos Arturo castano
@date 25/09/2010
*/
FUNCTION imprimirArchivo(ksosObj, archivoTmp)
impresora := QPrintDialog():new()
if (impresora : exec() == 0)
RETURN NIL
endif
ksosObj : print(impresora:printer)
RETURN NIL
/*-------------------------------------------------------------------*/
/*
Hace una copia del archivo de consulta
en un archivo del usuario.
La recibre como parametro dos tipos de informacion
si la ext == ".dbf" los datos a ser copiados estan
en un archivo DBF y la funcion los guarda en un archivo
elegido por el usuario en la varaible salida_
si la ext == ".html" los datos estan en el primer parametro
de la funcion copiarArchivo(oaram1,param2,param3)
param1 :: es un objeto tipo rich text
param2 :: es el nombre de la tabla desde donde se creo la
informacion desplegada en la consulta
param3 :: es el tipo de archivo de salida
la funcion los guarda en un archivo elegido por el
usuario
Si la ext == ".txt" los datos son grabados en un archivo plano
con extensión -txt y los campos delimitados por comas (CVS)
@author Carlos Arturo castano
@date 25/09/2010
*/
FUNCTION copiarArchivo(ksosObj, archivoTmp)
LOCAL textoTmp, variableTmp, salida_, archV, digiTmp
LOCAL dd, mm, exTmp
LOCAL creado := NO
LOCAL arrTmp[3,3]
LOCAL winC, layoC, G1, C1, R1
LOCAL aExit := .T.
LOCAL cExit := .F.
dd := right("00" + ltrim(str(day (date),2)),2)
mm := right("00" + ltrim(str(month(date),2)),2)
digiTmp := left(digitador,4)
variableTmp := home + slash + "pro" + slash
variableTmp += digiTmp + "_" + dd + mm
variableTmp := lower(left(variableTmp + space(50),50))
textoTmp := Tr("Nombre del archivo de salida")
arrTmp[1,1] := "xbase [.dbf]" ; arrTmp[1,2] := "" ; arrTmp[1,3]:= ".dbf"
arrTmp[2,1] := "web [.html]" ; arrTmp[2,2] := "" ; arrTmp[2,3]:= ".html"
arrTmp[3,1] := "texto [.cvs]" ; arrTmp[3,2] := "" ; arrTmp[3,3]:= ".txt"
layoP := QVBoxLayout():new()
layoD := QFormLayout():new()
layoB := QHBoxLayout():new()
winD := QDialog():new()
winD : setWindowTitle(textoTmp)
winD : setStyleSheet(cssK(CSS_SAY))
winD : setSizeGripEnabled(.T.)
pathS := pathI_ + look + slash
aceptarB := PushButtonK(NIL,,,Tr("Aceptar") ,pathS + "Aceptar.jpeg" ,,)
cancelarB := PushButtonK(NIL,,,Tr("Cancelar"),pathS + "Cancelar.jpeg",,)
aceptarB : setDefault(.T.)
G1 := GetK(NIL ,,,variableTmp,Y(02),X(50),50)
C1 := ComboBoxK(NIL,,, arrTmp, Y(02), X(50) )
layoD : addrow_3("&" + textoTmp , G1)
layoD : addrow_3("&" + Tr("Tipo de archivo"), C1)
layoB : addWidget(aceptarB)
layoB : addWidget(cancelarB)
layoP : addLayout(layoD)
layoP : addLayout(LayoB)
winD : setLayout(layoP)
Qt_Connect_Signal(aceptarB ,QT_EVE_CLICKED, {|| aExit := .T. ,winD:accept() })
Qt_Connect_Signal(cancelarB,QT_EVE_CLICKED, {|| cExit := .T. ,winD:reject() })
winD : exec()
if (cExit)
RETURN NIL
endif
//en extTmp esta el tipo archivo de de salida
extTmp := arrTmp[ C1 : currentIndex() + 1, 3 ]
salida_ := G1 : text + extTmp
archV := chr(34) + salida_ + chr(34)
archivoTmp += ".dbf" // El archivo de tablas siempre es .dbf
close databases
do case
case extTmp == ".dbf"
copy file &archivoTmp to &salida_
if file(&archV)
creado := SI
endif
case extTmp == ".html"
if (memoWrit(salida_, ksosObj : toHtml, .T.))
creado := SI
endif
case extTmp == ".txt"
select 10
use &archivoTmp alias PRESENTA
copy to &salida_ DELIMITED with ","
if file(&archV)
creado := SI
endif
endcase
if (creado == SI)
textoTmp := Tr("Archivo creado exitosamente") + "
"
textoTmp += ResaltarK(archV)
else
textoTmp := Tr("Archivo no fue creado") + "
"
textoTmp += ResaltarK(archV)
endif
ms := MsgInfo(textoTmp,MSG_INFORMATIVO)
RETURN NIL
Comentarios
Publicar un comentario