MDI

MDI

Postby triumvirato » Thu Dec 03, 2009 9:44 am

Hola compañeros!

A ver quién me puede echar una mano. En un ambiente MDI, aparte de los alias de las bases de datos, qué más necesitamos controlar?. Imagino que haya que tener un control sobre variables, objetos, ventanas...
Alguna lectura recomendad? algún manual - tutorial?

Gracias!
triumvirato
 
Posts: 199
Joined: Tue Apr 22, 2008 9:54 am
Location: Valladolid, Spain.

Re: MDI

Postby Antonio Linares » Thu Dec 03, 2009 9:59 am

David,

Aparte del control de los Alias, es importante recordar que las ventanas MdiChild no detienen la ejecución, por lo que se sale de la función en donde se crean, y esto hace que las variables locales se destruyan, salvo que se usen en codeblocks (FWH usa automaticamente codeblocks en las cláusulas ACTION...)

Por ejemplo, si cerrasemos una DBF despues de activar una ventana MDICHILD, la DBF se cerrará de inmediato y no se esperará a que se cierre la ventana MDICHILD.

Además de esto es conveniente revisar la documentación de las Clases asociadas: TMdiFrame, TMdiClient y TMdiChild:

http://wiki.fivetechsoft.com/doku.php?id=fivewin_class_tmdiframe
http://wiki.fivetechsoft.com/doku.php?id=fivewin_class_tmdiclient
http://wiki.fivetechsoft.com/doku.php?id=fivewin_class_tmdichild
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41315
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: MDI

Postby triumvirato » Fri Dec 04, 2009 10:27 am

Antonio,

Gracias por la info. Las clases no son mi fuerte, aprovecho para recordarte que tenemos ese asuntillo pendiente, así que en cuanto me organice y haya avanzado en FW más, hablo contigo para seguir adelante.

Por otro lado quería hacer una preguntita a ver cómo resuelve la gente este problema. Estoy configurando un entorno para hacerlo MDI, controlando varias cosas, pero a la hora de controlar las ventanas, tengo la duda. En principio controlo alias, variables y objetos con un array tridimensional de la forma:
Code: Select all  Expand view
#define aObjVar(i,j)      aArrayVars[1][i][j]
#define aAlias(i,j)     aArrayVars[2][i][j]
 


El primer orden, me especifica si es variable/objeto, el segundo para alias. El segundo orden, lo sustituyo por el nombre (por ejemplo):
Code: Select all  Expand view
#define oWndChild           1
#define oDlg                        2
#define oSayProc                3
#define oSayEmpr                4
#define oSayFecha               5
 


Y el tercer orden, es donde viene la madre del cordero, lo quiero sustituir por la ventana en concreto. Si utilizo una variable para controlar el número de la ventana, según vaya aumentando porque se abran más ventanas, va variando y no la puedo usar para hacer referencia a un determinado objeto de esa ventana. Por ejemplo, si hago referencia al objeto oSayEmpr de una ventana, sería así:

Code: Select all  Expand view
aObjVar( oSayEmpr, nWnd )

Pero si oWnd es una variable, ir´ña cambiando cada vez que se abra una nueva ventana y siempre estaríamos haciendo referencia al oSayEmpr de la última ventana abierta. No sé si me explico con claridad.
Cómo se puede solucionar este inconveniente?

Gracias!
triumvirato
 
Posts: 199
Joined: Tue Apr 22, 2008 9:54 am
Location: Valladolid, Spain.

Re: MDI

Postby Antonio Linares » Fri Dec 04, 2009 11:11 am

David,

Si necesitas tener controladas y accesibles las ventanas MDICHILD lo más sencillo es que crees una Clase:
Code: Select all  Expand view

CLASS TMiAplicacion

   DATA oWndClientes
   DATA oWndArticulos
   DATA oWndFacturas
   ...
   METHOD New() // desde donde construyes todo

ENDCLASS
 

Y creas un objeto publico de esta forma:
Code: Select all  Expand view

public oMiAplicacion := TMiAplicacion():New()
 

asi en cualquier parte de tu aplicación puedes acceder a oMiAplicacion:oWndFacturas o lo que necesites :-)

No se si es lo que quieres, pero es la manera mas simple y facil
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41315
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: MDI

Postby mantonio_08 » Fri Dec 04, 2009 11:14 am

QUE ESTAS INTANTANDO HACER AMIGO::

NO TE ENTENDI..

PODES PONER UN CODE DE LO Q QUIERES HACER::

HABER SI PODEMOS AYUDARTE
mantonio_08
 
Posts: 330
Joined: Fri May 25, 2007 9:06 pm

Re: MDI

Postby triumvirato » Fri Dec 04, 2009 12:19 pm

Antonio,

No es eso lo que busco concretamente, pero me sirve ese ejemplo para no usar public's :)
A lo que me refiero, es que cuando hago referencia a un objeto de una ventana concreta, para indicarle qué ventana es, no puedo usar variables:
Code: Select all  Expand view
aObjVar( oSayEmp, [b]nWnd[/b] )
, porque nWnd cada vez que se abre una ventana nueva, toma un valor distinto, que se le va asignando cada vez que se abre una ventana nueva:
Code: Select all  Expand view
  if nWnd = nil
      nWnd := 1
   else
      nWnd ++
   endif
 


Abrimos una ventana, los objetos de la ventana1, se puede referenciar perfectamente bien con aObjVar( oSayEmp, nWnd ). Cuando abrimos una ventana2, viene el problema, nWnd toma el valor de 2 y a partir de ahí, toda referencia a objetos hecha en la ventana1 no es correcto, puesto que se referencia con aObjVar( oSayEmp, nWnd ) y nWnd ya ha tomado el valor de 2.
Siento explicarme tan mal, entiendo que el problema es no poder o no saber explicarlo mejor. A ver si ahora quedó más claro. Lo que quería saber es cómo solucionan los demás ese problema, para no limitar las ventanas a un número fijo determinado.

Gracias!
triumvirato
 
Posts: 199
Joined: Tue Apr 22, 2008 9:54 am
Location: Valladolid, Spain.

Re: MDI

Postby triumvirato » Fri Dec 04, 2009 12:21 pm

mantonio_08 wrote:QUE ESTAS INTANTANDO HACER AMIGO::

NO TE ENTENDI..

PODES PONER UN CODE DE LO Q QUIERES HACER::

HABER SI PODEMOS AYUDARTE


mantonio_08,

A ver si con esa explicación queda más claro mi problema... es que el código es demasiado complejo ya para ponerlo aquí. Si no se entiende, trataré de hacer algo sencillito y ponerlo aquí.

Gracias!.
triumvirato
 
Posts: 199
Joined: Tue Apr 22, 2008 9:54 am
Location: Valladolid, Spain.

Re: MDI

Postby Antonio Linares » Fri Dec 04, 2009 12:55 pm

David,

No se si te refieres a esto, pero dada una ventana MdiChild puedes calcular su "índice" de esta forma:
Code: Select all  Expand view

nWnd = AScan( oWndPrincipal:oWndClient:aWnd, { | oWndChild | oWndChild == oWndFacturas } )
aObjVar( oSayEmp, nWnd )
 
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41315
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: MDI

Postby Antonio Linares » Fri Dec 04, 2009 1:00 pm

Tambien puedes calcular el "índice" de la ventana MdiChild activa:
Code: Select all  Expand view

nWnd = AScan( oWndPrincipal:oWndClient:aWnd, { | oWndChild | oWndChild == oWndPrincipal:oWndActive } )
aObjVar( oSayEmp, nWnd )
 
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41315
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: MDI

Postby triumvirato » Fri Dec 04, 2009 4:18 pm

Antonio,

Perfecto! :) con esto ya me sirve (creo) para llegar a lo que necesito. Muchas muchas gracias!

Saludos!
triumvirato
 
Posts: 199
Joined: Tue Apr 22, 2008 9:54 am
Location: Valladolid, Spain.

Re: MDI

Postby triumvirato » Sat Dec 05, 2009 10:28 am

Pues ya no sé si es que ayer fué luna llena o algo de eso, que no doy con lo que busco. Voy a poner un trocito de mi código que creo representa el meollo. Esta función es llamada desde el menú de la ventana principal. Por cada vez que se ejecuta, se crea una nueva ventana.
aArrayVars es un array que va contener todas las variables y objetos y nombres de alias. El primer parámetro o índice del array lo utilizo referenciar varibles/objetos o alias. El segundo índice del array, lo uso para
El problema está, como comentaba en post anteriores, que cuando quiero hacer referencia a cualquier objeto de alguna ventana, he perdido la referencia para buscarlo en el array, porque nWnd cambia su valor. Por tanto, cada vez que generamos una nueva ventana, nWnd va a ser referencia únicamente de la última ventana creada. Por ello, si cambiamos de ventana, al hacer referencia a aObjVar( oArt, nWnd ), tan sólo me estaré refiriendo a la última ventana por el valor que tiene nWnd.
La solución de Antonio podría ser valida, excepto porque mi variable para el objeto ventana, la tengo que referenciar con nWnd también, de la manera siguiente: aObjVar( oWndChild, nWnd )
A ver si con el trocito de código se entiende mejor y yo entiendo mejor cómo solucionarlo.

Code: Select all  Expand view

#include "FiveWin.ch"

#define aObjVar(i,j)      aArrayVars[1][i][j]
#define aAlias(i,j)     aArrayVars[2][i][j]
#define nTipVarMax          2  //Tipo máximo de variables (ObjVar y Alias = 2)
#define nWndMax         10 //Tope ventanas Man_Art()
// Objetos y variables
#define oWndChild           1
#define oDlg            2
#define oSayProc            3
#define oSayEmpr            4
#define oArt            5
#define cProc                                            6
#define cEmpresa                                      7
#define nObjVarMax          7  //Número máximo de variables y objetos
// Alias
#define Tec             1
#define Art             2

static aArrayVars[nTipVarMax][nObjVarMax][nWndMax]
static nWnd

**********************************************************************************************************************
function ManArt()
**********************************************************************************************************************

   if nWnd = nil
      nWnd := 1
   else
      nWnd ++
   endif

   aAlias( Tec, nWnd ) := CnwOpenDbf( oWndPrinc, "TEC.DBF", 5, .t., .f. )
   //Funcion para abrir una base de datos compartida o exclusiva, retorna un alias nuevo y único
   SET INDEX TO Tec_Cod, Tec_Nom
   aAlias( Art, nWnd ) := CnwOpenDbf( oWndPrinc, "ART.DBF", 5, .t., .f. )
   SET INDEX TO Art_Cod, Art_Nom, Art_Sub, Art_Int
   
   DATABASE aObjVar( oArt, nWnd )
   aObjVar( oArt, nWnd ):lOemAnsi = .t.
   aObjVar( oArt, nWnd ):Load()
   aObjVar( oArt, nWnd ):bBOF = { || MsgInfo( "Primer Registro" ) }
   aObjVar( oArt, nWnd ):bEOF = { || MsgInfo( "Último Registro" ) }

   SELECT ( aAlias( Art, nWnd ) )

   DEFINE WINDOW aObjVar( oWndChild, nWnd ) MDICHILD OF oWndPrinc ;
          FROM 5,5 TO 6,6;
          COLOR "N/W" ;
          BORDER NONE // prevent resizing

   DEFINE DIALOG aObjVar( oDlg, nWnd ) RESOURCE "Articulos" OF aObjVar( oWndChild, nWnd )
   
   REDEFINE SAY aObjVar( oSayProc, nWnd ) PROMPT aObjVar( cProc, nWnd ) ID 10 OF aObjVar( oDlg, nWnd )

   REDEFINE SAY aObjVar( oSayEmpr, nWnd ) PROMPT aObjVar( cEmpresa, nWnd ) ID 20 OF aObjVar( oDlg, nWnd )

   REDEFINE GET aObjVar( oGetArt_Cod, nWnd ) VAR aObjVar( oArt, nWnd ):Art_Cod ID 40 OF aObjVar( oDlg, nWnd )  PICTURE '@!' UPDATE

   REDEFINE GET aObjVar( oArt, nWnd ):Art_Nom ID 50 OF aObjVar( oDlg, nWnd ) PICTURE '@!' UPDATE
   
   REDEFINE GET aObjVar( oArt, nWnd ):Art_Col ID 60 OF aObjVar( oDlg, nWnd ) PICTURE '@!' UPDATE

   REDEFINE BUTTON aObjVar( oBtnAnterior, nWnd ) ID 1000 OF aObjVar( oDlg, nWnd );
            ACTION ( aObjVar( oArt, nWnd ):Skip( -1 ) , If( aObjVar( oArt, nWnd ):BoF(), MsgBeep(),), aObjVar( oDlg, nWnd ):Update() )

   REDEFINE BUTTON aObjVar( oBtnSiguiente, nWnd ) ID 2000 OF aObjVar( oDlg, nWnd );
            ACTION ( aObjVar( oArt, nWnd ):Skip(),;
                   If( aObjVar( oArt, nWnd ):EoF(), aObjVar( oArt, nWnd ):Skip( -1 ),), aObjVar( oDlg, nWnd ):Update() )

   ACTIVATE DIALOG aObjVar( oDlg, nWnd ) NOWAIT CENTERED;
      ON INIT ( aObjVar( oBtnSiguiente, nWnd ):SetFocus(), aObjVar( oDlg, nWnd ):Move( 0, 0 ), .f. );
      VALID  ( aObjVar( oWndChild, nWnd ):End(), .t. )

   aObjVar( oWndChild, nWnd ):nWidth := aObjVar( oDlg, nWnd ):nWidth+7
   aObjVar( oWndChild, nWnd ):nHeight := aObjVar( oDlg, nWnd ):nHeight+32

   ACTIVATE WINDOW aObjVar( oWndChild, nWnd )

return nil

 


Gracias!
triumvirato
 
Posts: 199
Joined: Tue Apr 22, 2008 9:54 am
Location: Valladolid, Spain.

Re: MDI

Postby mantonio_08 » Sat Dec 05, 2009 11:31 am

disculpa amigo el comentario,, y lo directo::

pero me podrias cual es el beneficio que tienes al programar una aplicacion de esta manera,, metiendo en varios array todo los objetos , y datos necesarios para crear tus window, dialog, say, get, etc,etc.::

??? que beneficio esperas::
mantonio_08
 
Posts: 330
Joined: Fri May 25, 2007 9:06 pm

Re: MDI

Postby triumvirato » Sat Dec 05, 2009 6:37 pm

mantonio_08 wrote:disculpa amigo el comentario,, y lo directo::

pero me podrias cual es el beneficio que tienes al programar una aplicacion de esta manera,, metiendo en varios array todo los objetos , y datos necesarios para crear tus window, dialog, say, get, etc,etc.::

??? que beneficio esperas::


Mantonio_08,

No hay por qué pedir disculpas por un comentario y mucho menos por directo :wink:
Primero comentar que no son varios array, sino UNO solo. Esto tiene varias ventajas, una de ellas es que tan sólo utilizas una variable static (al menos bastante menos), evitas errores GPF y el paso de las mismas a otras funciones es mucho más sencillo (con pasar ese array, pasas absolutamente todo). Por otro lado, para funcionar en un ambiente MDI, es necesario, pues puedes ir aumentando el número de variables y alias a medida que se abren nuevas ventanas MDI, si quieres que el número de ventanas sea ilimitado, tan sólo limitado por memoria del sistema o las 255 workareas que permitía clipper y que no sé si esa limitación sigue en FW y Harbour, etc. Todos estos, digamos, "pros", los he ido sacando de post, ejemplos, etc.
Otro de los motivos y este ya de mi propia cosecha, es que estoy intentando migrar una aplicación de clipper, en la que se han utilizado en un 90% variables private. Efectivamente había que elegir entre depurar todo eso y luego migrar, o a la inversa, ir migrando y luego depurando. Una de las soluciones que he encontrado ha sido esta de ir conteniendo todas esas variables en array y luego irlos pasando a las distintas funciones. Existen en esa aplicación clipper funciones que manejan con 90 variables private, definidas en distintos puntos de la aplicación y el irlas pasando una a una a la función, luego a otra, luego a otra, es tarea inhumana, por lo que teniéndolas contenidas en un array, paso un array y aligeramos un poco el trabajo.

Espero que te ayude a comprender mejor el por qué de este sistema de variables. Por cierto que para MDI se hace casi imprescindible un método similar.

Saludos!
triumvirato
 
Posts: 199
Joined: Tue Apr 22, 2008 9:54 am
Location: Valladolid, Spain.

Re: MDI

Postby Antonio Linares » Sun Dec 06, 2009 8:03 pm

David,

Si nos pudieses proporcionar un ejemplo pequeño y autocontenido que podamos probar facilmente, sería más sencillo poder revisarlo e intentar darte una solución, gracias :-)
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41315
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: MDI

Postby triumvirato » Mon Dec 07, 2009 9:48 am

Antonio,

Gracias a tí por tu preocupación y ayuda.
He hecho un pequeño ejemplo sin ventanas pero con diálogos MDI donde se ve el mismo problema. Funciona con la base clients de \samples.
Pare ver el problema, basta con abrir dos o tres ventanas, situarnos en la primera con las demás a la vista y pulsar sobre siguiente. El diálogo que se actualizará será el tercero siempre.

Code: Select all  Expand view

#include "FiveWin.ch"

#define aObjVar(i,j)      aArrayVars[1][i][j]
#define aAlias(i,j)     aArrayVars[2][i][j]
#define nTipVarMax          2  //Tipo máximo de variables (ObjVar y Alias = 2)
#define nWndMax         10 //Tope ventanas Man_Art()
// Objetos y variables
#define oDlg            1
#define oSayNom         2
#define oSayDir         3
#define oCli            4
#define oBtnAnterior                                 5
#define oBtnSiguiente       6
#define oBtnVer         7
#define nObjVarMax          7  //Número máximo de variables y objetos
// Alias
#define Cli             1

static oWndPrinc
static aArrayVars[nTipVarMax][nObjVarMax][nWndMax]
static nWnd


**********************************************************************************************************************
function Main()
**********************************************************************************************************************

   DEFINE WINDOW oWndPrinc Title "Ventanas" MDI MENU MenuPrin()
   ACTIVATE WINDOW oWndPrinc MAXIMIZED

return nil

**********************************************************************************************************************
function MenuPrin()
**********************************************************************************************************************

   local oMenu

   MENU oMenu

   MENUITEM "&Ventanas"
       MENU
          MENUITEM "&Ventanas" ACTION ( ManArt() )
       ENDMENU
   ENDMENU

return oMenu

**********************************************************************************************************************
function ManArt()
**********************************************************************************************************************

   if nWnd = nil
      nWnd := 1
   else
      // Hacer control ventanas máximas.
      nWnd ++
   endif

   aAlias( Cli, nWnd ) := NewAlias( "Clients.dbf" )
   DbUseArea( .T.,, "Clients.dbf", aAlias( Cli, nWnd ), .t., .f. )
   DATABASE aObjVar( oCli, nWnd )
   aObjVar( oCli, nWnd ):Load()
   aObjVar( oCli, nWnd ):bBOF = { || MsgInfo( "Primer Registro" ) }
   aObjVar( oCli, nWnd ):bEOF = { || MsgInfo( "Último Registro" ) }

   DEFINE DIALOG aObjVar( oDlg, nWnd ) TITLE "Diáologo: " + Str( nWnd ) FROM 0,0 TO 20,40 OF oWndPrinc
   
   @ 1, 1 SAY aObjVar( oSayNom, nWnd ) PROMPT aObjVar( oCli, nWnd ):Name OF aObjVar( oDlg, nWnd ) UPDATE

   @ 2, 1 SAY aObjVar( oSayDir, nWnd ) PROMPT aObjVar( oCli, nWnd ):Adress OF aObjVar( oDlg, nWnd ) UPDATE

   @ 5, 1 BUTTON aObjVar( oBtnAnterior, nWnd ) PROMPT "Anterior" OF aObjVar( oDlg, nWnd );
                 ACTION ( aObjVar( oCli, nWnd ):Skip( -1 ) , If( aObjVar( oCli, nWnd ):BoF(), MsgBeep(),), aObjVar( oDlg, nWnd ):Update() )

   @ 6, 1 BUTTON aObjVar( oBtnSiguiente, nWnd ) PROMPT "Siguiente" OF aObjVar( oDlg, nWnd );
                 ACTION ( aObjVar( oCli, nWnd ):Skip(),;
                 Iif( aObjVar( oCli, nWnd ):EoF(), aObjVar( oCli, nWnd ):Skip( -1 ),), aObjVar( oDlg, nWnd ):Update() )
                 
   @ 7, 1 BUTTON aObjVar( oBtnVer, nWnd ) PROMPT "Ver" OF aObjVar( oDlg, nWnd );
                 ACTION ( MsgInfo( "Alias: " + aAlias( Cli, nWnd ) + CRLF +;
                                   "Valor nWnd: " + Str( nWnd ) ) )

   ACTIVATE DIALOG aObjVar( oDlg, nWnd ) NOWAIT CENTERED;
      ON INIT ( aObjVar( oBtnSiguiente, nWnd ):SetFocus(), aObjVar( oDlg, nWnd ):Move( 0, 0 ) );
      VALID ( aObjVar( oCli, nWnd ) )->( DbCloseArea(), .t. )

return nil

**********************************************************************************************************************
function NewAlias( cNomDbf )
**********************************************************************************************************************
  static nNum := 0
  local cAlias := ""

  nNum++
  cAlias := SubStr( cFileNoExt( cFileName( cNomDbf ) ), 1, 4 ) + LTRIM( STR( nNum ) )
return ( cAlias )
 
triumvirato
 
Posts: 199
Joined: Tue Apr 22, 2008 9:54 am
Location: Valladolid, Spain.

Next

Return to FiveWin para Harbour/xHarbour

Who is online

Users browsing this forum: No registered users and 76 guests