Pasar tabla como parámetro

302 views
Skip to first unread message

3rn3st0

unread,
Feb 4, 2009, 4:48:07 PM2/4/09
to Mundo Visual FoxPro
He creado una clase genérica visual la cual utilizo para manipular
registros en diversas tablas, mi problema estriba en que en algunas
oportunidades requiero llamar a un método de la clase enviándole como
parámetro el nombre de una tabla, ej.:

lparameters tTable As String

Luego uso el parámetro para hacer un select de la tabla usando
macrosustitución de esta manera:

select &tTable

Hasta ahí todo va bien, el problema se presenta cuando requiero usar
esa "tabla" en alguna otra parte del método, como en la siguiente
línea, la cual utilizo para determinar si existen registros en la
tabla-parámetro para de esta manera actualizar una propiedad de la
clase. ej.:

This.TheAreRecs = Iif( Reccount( &tTable ) > 0, .T., .F. )

Mi pregunta es: ¿Qué estoy haciendo mal? ¿Hay alguna manera de enviar
la tabla como un parámetro de tipo Tabla o algo por el estilo? Hasta
ahora envío el parámetro como una cadena de caracteres y el select
funciona.

De antemano agradezco la ayuda que puedan prestarme.

NOTA: Agradecería que quienes no entiendan el problema no respondan
con soluciones vacías. Si existe alguna duda sobre lo que estoy
haciendo, escriban directamente a mi correo para no llenar la lista de
off-topics.

Trento

unread,
Feb 4, 2009, 5:14:36 PM2/4/09
to Mundo Visual FoxPro
¿Exactamente a qué método te refieres cuando escribes "... el problema
se presenta cuando requiero usar esa "tabla" en alguna otra parte del
método..."?

Puedes crear una propiedad en tu clase que almacene el nombre de la
tabla.

Evento INIT de la clase
LPARAMETERS tcTable
THIS.TableName = tcTable

Con eso ya podrías hacer referencia a la table en cualquier otro
método de tu clase.

THIS.ThereAreRecs = ( RECCOUNT( THIS.TableName ) > 0 )

A ver si entendí bien y no respondí con una "solución vacía"...


Saludos.

3rn3st0

unread,
Feb 4, 2009, 5:45:11 PM2/4/09
to Mundo Visual FoxPro
Trento, primero que nada, gracias por la respuesta. Sin embargo, pocos
minutos antes ya había encontrado la solución. De hecho, volví al
Grupo de Mundo VFP para referirme a la misma.

En primer término, cuando hablo de "...en alguna otra parte del
método..." me refiero a que en el código del método que estoy editando
funciona bien la referencia a la tabla pasada como parámetro cuando
hago el select de la tabla para hacerla la tabla activa, el problema
estribaba (de eso me di cuenta después) cuando hacía referencia a la
tabla dentro de la función Reccount(). Allí VFP me generaba un error
de "Variable <NombreTabla> no existe".

Reccount() trabaja de dos maneras, o le envías un parámetro con el
número/alias del área activa o no le envías ningún parámetro y por
omisión la función toma la tabla que esté activa en ese momento. La
solución fue tan sencilla como olvidarm, del parámetro en la función
Reccount() y dejar que ésta usara la tabla activa (en mi caso &tTabla)
y voilà, todo funcionó como lo esperaba.

Por último y para mejorar la visión de lo que planteé anteriormente,
te cuento que lo que estaba haciendo era crear una clase visual estilo
ToolBar para encapsular todos los procedimientos de: Agregar nuevo
registro, eliminar registro, modificar registro, etc. y de esa manera
escribir la menor cantidad de código posible.

El método en cuestión donde tenía problema es un procedimiento que
verifica si en la tabla activa existen registros guardados para así
activar el botón de búsqueda (no le encuentro sentido a un botón
activo si no hay nada que buscar) y por eso mi necesidad de usar la
tabla que se correspondiera con los elementos a ser editados.

Sobre tu respuesta, no, no es una "solución vacía", por el contrario
sin embargo, no hubiera funcionado por la misma razón que a mi no me
funcionó, Reccount() habría generado un error diciendo que la variable
"tcTable" no existe. En todo caso, te agradezco realmente la ayuda :-)

Saludos desde Venezuela.

Trento

unread,
Feb 4, 2009, 8:39:11 PM2/4/09
to Mundo Visual FoxPro
Vaya, pues qué bien que hayas dado con la solución.

1) Efectivamente, RECCOUNT() funciona tál como lo has descrito.

Pero también hay que tomar en cuenta esto: RECCOUNT() te devuelve el
número de registros físicos que tiene una tabla, incluyendo aquéllos
marcados para borrar, con lo que puede generar "confusiones".

¿Qué pasaría si en base a RECCOUNT() generas un reporte que al pié de
página imprima:

"Total de registros: " + TRANSFORM( RECCOUNT() )

y resulta que ves 3 líneas de detalle y el pié de página te dice que
son más?

2) Te apuesto una botella del mejor tequila a que el ejemplo que te
pasé hubiera funcionado perfectamente ;-)
Uno de los ejemplos más usados para formularios genéricos es usar
precisamente una propiedad del formulario que almacene el nombre de la
tabla principal, o incluso usar

THISFORM.DataEnvironment.InitialSelectedAlias = tcTable

Por lo que si yo hago esto:

SELECT ( THISFORM.TableName )

o bien

SELECT ( THISFORM.DataEnvironment.InitialSelectedAlias )

Y a continuación emito un

BROWSE

Me mostraría la tabla definida en cualquiera de esas propiedades.


Saludos desde Guadalajara, México.

3rn3st0

unread,
Feb 4, 2009, 10:43:16 PM2/4/09
to Mundo Visual FoxPro
¡Bravo! Excelente tu explicación y sin errores o fallas. Ahora bien
Trento, creo que hay algo que no expliqué y que posiblemente sea parte
del problema. La clase que he creado, es una clase visual basada en un
Container. El Container NO tiene una propiedad DataEnvironment (por lo
menos no he sabido como agregársela). De ahí que lo que me propones no
creo que me sirva. Sin embargo y más por curiosidad y porque además lo
que propones me parece excelente, trataré de implementarlo.

Por cierto, no había tomado en cuenta lo que mencionas sobre Reccount
(), es cierto, esta retorna la cantidad de registros físicos de la
tabla independientemente de si están o no marcados para ser borrados.
Se me ocurre una función que haga un SELECT SQL obviando los registros
marcados como borrados y usar Reccount() con el cursor creado para
retornar ese valor, y luego borrar el cursor.

Nuevamente gracias, creo que voy a disfrutar mucho estas
conversaciones programáticas :-)

Jose Oscar Vogel

unread,
Feb 5, 2009, 4:34:46 AM2/5/09
to mundovis...@googlegroups.com
si bien la clase Container no tiene un DataEnvironment puedes hacer lo siguiente, que hace referencia al formulario activo,
 
SELECT(_screen.activeform.DataEnvironment.InitialSelectdAlias)
 
saludos oscar

3rn3st0

unread,
Feb 5, 2009, 2:40:57 PM2/5/09
to Mundo Visual FoxPro
Muy buena sugerencia, la cual, empero, me hace pensar en otra cosa...
Mi aplicación no se ejecuta sobre la GUI de VFP, detesto tener que
andar modificando propiedades de la ventana principal de VFP, en vez
de ello, uso un formulario de nivel superior y oculto la ventana
principal de VFP (_VFP.Visible = .F.). La que ahora se me ocurre es
que la línea que sugieres podría quedar de la siguiente manera:

SELECT This.Parent.DataEnvironment.InitialSelectdAlias

¿Estoy en lo correcto?

On 5 feb, 05:34, Jose Oscar Vogel <oscarvo...@gmail.com> wrote:
> si bien la clase Container no tiene un DataEnvironment puedes hacer lo
> siguiente, que hace referencia al formulario activo,
>
> SELECT(_screen.activeform.DataEnvironment.InitialSelectdAlias)
>
> saludos oscar
>
> --
> Prof. Jose Oscar Vogel
> Garuhapé - Misiones
> CP 3334
> Cel: 03743-15498001

Jose Oscar Vogel

unread,
Feb 5, 2009, 2:47:43 PM2/5/09
to mundovis...@googlegroups.com
yyy siguiendo el nivel de los formularios tendría que ser asi como tu dices, nunca lo probé, habría que probarlo, tengo mis dudas.
 
si creas un formulario de nivel superior, los demas formularios que crees a partir de ahi estan contenidos en el de nivel superior?, si no es asi no creo que puedas hacer referencia a this.parent, pero bueno como te digo, nunca lo probé
 
pruebalo y nos comentas ;)
 
saludos

Trento

unread,
Feb 5, 2009, 4:15:00 PM2/5/09
to Mundo Visual FoxPro
Y me sigo preguntando... ¿para qué tanto brinco estando el suelo tan
parejo? como decimos en México.

Añade una propiedad a tu clase en donde almacenes la tabla. Así como
agregaste la propiedad

ThereAreRecs = .F.

Agrega otra:

TableName = ""

O como la quieras llamar. Y hago copy&paste de mi primer respiuesta a
este hilo:

******************************************
Puedes crear una propiedad en tu clase que almacene el nombre de la
tabla.

Evento INIT de la clase
LPARAMETERS tcTable
THIS.TableName = tcTable

Con eso ya podrías hacer referencia a la table en cualquier otro
método de tu clase.

THIS.ThereAreRecs = ( RECCOUNT( THIS.TableName ) > 0 )
********************************************

OJO: Si la tabla se llama, por ejemplo, "CLIENTES", entonces el valor
de la propiedad es "CLIENTES", no "tcTable".

Vamos, que estamos creando, por así decirlo, un "cajón" donde se
almacene la variable tcTable.


Incluso puedes acceder a ella desde cualquier parte del programa.

WAIT WINDOW ..cntClase.TableName

USE ( ..cntClase.Table )
BROWSE IN ( ..cntClase.Table )

Uso ".." al inicio, pues no sé a qué nivel esté tu contenedor. Pudiera
ser "THISFORM.cntClase.TableName". Pongamos que así sea.

Otro ejemplo:

lcTabla = THISFORM.cntClase.TableName

IF !USED ( lcTabla )

USE ( lcTable ) IN 0 ORDER .... etc....
ENDIF

SELECT ( lcTabla )
BROW

En fin...


Saludos.

Trento

unread,
Feb 5, 2009, 4:17:40 PM2/5/09
to Mundo Visual FoxPro
Válgame Dios...

Olviden lo de "BROWSE IN ( ..cntClase.Table )"...

Me emocioné, me emocioné...

Qué pena... :-(

3rn3st0

unread,
Feb 6, 2009, 12:53:14 PM2/6/09
to Mundo Visual FoxPro
Trento, tu idea sigue siendo muy buena, pero algo se te está pasando
por alto...

En todo el código que escribes, haces referencia a "TableName", una
propiedad que sería creada para almacenar en ella el nombre o alias de
la tabla con la que se está trabajando y he ahí el problema. Dentro de
TableName estaría contenida una cadena de caracteres con el nombre de
mi tabla activa. Hasta ahí no hay problema, el problema está en que
las funciones y comandos que usan tablas hacen referencias o a un
número de área o a un alias de área, jamás a cadenas de caracteres.
Creo que todo lo que enviaste funciona si antes de hacer referencia a
la propiedad TableName, esta es asignada a variables dentro de los
procedimientos que se use y luego pasada a las funciones o comandos
que hagan uso de la tabla de la siguiente manera (uso uno de tus
propios ejemplos):

&& Este es tu código
THIS.ThereAreRecs = ( RECCOUNT( THIS.TableName ) > 0 )

&& Modificado quedaría así
lcTable = THIS.TableName

THIS.ThereAreRecs = ( RECCOUNT( &lcTable ) > 0 )

Fíjate que son dos líneas de código, pero en realidad lo más
importante no es que escribamos un poco más, sino que debemos estar
pendientes de hacer referencia al contenido de la variable lcTable con
el operador de macrosustitución "&" para que no se haga referencia a
una cadena de caracteres sino al contenido de la variable de manera
directa, esa última línea es como si escribieramos esto:

USE NombreTabla
nRecs = RECCOUNT( NombreTabla ) && Sin el operador porque esta
vez si estoy haciendo referencia a un alias

Saludos y gracias por tus ideas. Buscaré la manera de aplicarlas,
porque son buenas. Lo mismo para José Oscar. Hoy me pongo a modificar
mi código a ver que sale de todo ello :-)

Saludos desde Venezuela para ambos
Reply all
Reply to author
Forward
0 new messages