
Datamodules en entorno MDI
Started by
jlopez
, Nov 16 2011 09:21 PM
12 replies to this topic
#1
Posted 16 November 2011 - 09:21 PM
Hola!
He encontrado algún hilo sobre el tema pero no termino de saber como hacerlo.
Creo tantos Tform como TDataModules pero no se como hacer referencia a uno u otro.
En el caso de los Tform los nombres se van 'bautizando' automáticamente (frm_child_1,frm_child_2) pero no sucede así con los datamodules.
Puede alguien orientarme en como acometer este problema?
He encontrado algún hilo sobre el tema pero no termino de saber como hacerlo.
Creo tantos Tform como TDataModules pero no se como hacer referencia a uno u otro.
En el caso de los Tform los nombres se van 'bautizando' automáticamente (frm_child_1,frm_child_2) pero no sucede así con los datamodules.
Puede alguien orientarme en como acometer este problema?
#2
Posted 16 November 2011 - 10:35 PM
No necesitas tantos DATAMODULES a menos que los manejes con controles de distintas BASES, por lo generar creas uno o dos DATAMODULOS y cuando requieras accesar a alguno en algun form.. unicamente lo declaras en el
[DELPHI]
implementation
uses
datamodulo1, datamodulo2.... ;
[/DELPHI]
tal como se hace con la asociacion de Unidades..
En tu form.. te vas al menu File y das click en Use Unit.. y la seleccionas..
SALUDOS..
[DELPHI]
implementation
uses
datamodulo1, datamodulo2.... ;
[/DELPHI]
tal como se hace con la asociacion de Unidades..
En tu form.. te vas al menu File y das click en Use Unit.. y la seleccionas..
SALUDOS..
#3
Posted 17 November 2011 - 02:30 AM
Buenas,
Lo malo delo que comenta pcicom es que si desde un form te mueves en una tabla, en todos los forms que usen esa tabla te estarás moviendo (si usas el mismo TDataSource, claro).
Lo que yo suelo hacer en aplicaciones MDI es declararme una propiedad en el formulario MDI del tipo del DataModule que quiera usar en esa pantalla y en el constructor lo creo y asigno los DataSources y en el destructor lo destruyo. De esta manera, por mucho que me "mueva" en una pantalla, las demás ni se enteran.
También puedes tener el DataSource en el form MDI, con lo que en el constructor sólo tendrías que lincar los TDataSources con los TDataSets.
Espero te sirva
Nos leemos
Lo malo delo que comenta pcicom es que si desde un form te mueves en una tabla, en todos los forms que usen esa tabla te estarás moviendo (si usas el mismo TDataSource, claro).
Lo que yo suelo hacer en aplicaciones MDI es declararme una propiedad en el formulario MDI del tipo del DataModule que quiera usar en esa pantalla y en el constructor lo creo y asigno los DataSources y en el destructor lo destruyo. De esta manera, por mucho que me "mueva" en una pantalla, las demás ni se enteran.
También puedes tener el DataSource en el form MDI, con lo que en el constructor sólo tendrías que lincar los TDataSources con los TDataSets.
Espero te sirva
Nos leemos
#4
Posted 17 November 2011 - 06:03 AM
Gracias por las respuestas...
Lo que quiero es exactamente lo que comenta cadetill, el problema es precisamente esa asignación, como hago referencia al tdatamodule?
He probado a hacer un array de tdatamodules pero sin éxito (lo tengo hecho para series de teechart y sus querys).
Creo que me estoy liando de mala manera... podrías mostrarme un ejemplo sencillo?
Te estaría eternamente agradecido...
Lo que quiero es exactamente lo que comenta cadetill, el problema es precisamente esa asignación, como hago referencia al tdatamodule?
He probado a hacer un array de tdatamodules pero sin éxito (lo tengo hecho para series de teechart y sus querys).
Creo que me estoy liando de mala manera... podrías mostrarme un ejemplo sencillo?
Te estaría eternamente agradecido...

#5
Posted 17 November 2011 - 10:40 AM
Buenas
Veamos. Tenemos por un lado un DataModule llamado DM y por otro un MDIChild llamado Child (me complico en los nombre eh!!
)
Bien, ahora en Child tienes que hacer algo así
Y ahora su implementación suponiendo que el TDatasource está en el formulario MDIChild y no en el TDataModule
Lo he puesto de cabeza. Espero te sirva.
Nos leemos
Veamos. Tenemos por un lado un DataModule llamado DM y por otro un MDIChild llamado Child (me complico en los nombre eh!!

Bien, ahora en Child tienes que hacer algo así
delphi
type TChild = class(TForm) .... protected // lo ponemos en protected por si hacemos herencia visual y esas cosas property MyDM: TDM read FMyDM write FMyDM; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; end;
Y ahora su implementación suponiendo que el TDatasource está en el formulario MDIChild y no en el TDataModule
delphi
constructor TChild.Create(AOwner: TComponent); begin inherited; FMyDM := TDM.Create(nil); aDataSource.DataSet := FMyDM.aTable; end; destructor TChild.Destroy; begin if Assigned(Self.FMyDM) then FreeAndNil(Self.FMyDM); inherited; end;
Lo he puesto de cabeza. Espero te sirva.
Nos leemos
#6
Posted 17 November 2011 - 11:04 AM
Creo que deberias tener un solo datamodule si solo tienes una conexion a la base de datos, el datasource deberia estar en cada child, y el problema de como asignarle el datamodule, tanto en tiempo de diseño como de ejecución, es sencillo:
En tu aplicacion abre el código (Aplication, View Source code o algo asi aparece en el menú), tienes un gra "uses" y luego un procedimiento solo con su begin y un end, y dentro se inicializa el objeto aplication y luego se crean los forms que tengas con autocrete.
Lo que yo hago es editar ese codigo y le añado a mano una variable DM del tipo de tu datamodule (que ya deberia estar en el uses porque loo añadiste a tu aplicación), no recuerdo si va antes del procedure como VAR o dentro, y justo tras el begin la inicializo con DM:= TMyDataModule.create; y asi sé que esa variable esta siempre accesible en todos los forms de mi aplicacion.
Cuando diseño mi childform, le incluyo en el uses la unidad del datamodule y conecto los dataset con ese DM que, al ser una variable creada en el inicio de la aplicacion, siempre esta visible.
Asi funciona muy bien, quizas algun detalle no lo he explicado correcxtamente, es de memoria, pero es una forma sencilla de solventar el problema sin tener que memorizar ni crear datamodules durante la ejecucion de la aplicacion.
Si te interesa este sistema, te busco el trozo de codigo y te lo pego, es sencillo pero los detalles pueden complicarlo si no lo ves ya funcionando.
En tu aplicacion abre el código (Aplication, View Source code o algo asi aparece en el menú), tienes un gra "uses" y luego un procedimiento solo con su begin y un end, y dentro se inicializa el objeto aplication y luego se crean los forms que tengas con autocrete.
Lo que yo hago es editar ese codigo y le añado a mano una variable DM del tipo de tu datamodule (que ya deberia estar en el uses porque loo añadiste a tu aplicación), no recuerdo si va antes del procedure como VAR o dentro, y justo tras el begin la inicializo con DM:= TMyDataModule.create; y asi sé que esa variable esta siempre accesible en todos los forms de mi aplicacion.
Cuando diseño mi childform, le incluyo en el uses la unidad del datamodule y conecto los dataset con ese DM que, al ser una variable creada en el inicio de la aplicacion, siempre esta visible.
Asi funciona muy bien, quizas algun detalle no lo he explicado correcxtamente, es de memoria, pero es una forma sencilla de solventar el problema sin tener que memorizar ni crear datamodules durante la ejecucion de la aplicacion.
Si te interesa este sistema, te busco el trozo de codigo y te lo pego, es sencillo pero los detalles pueden complicarlo si no lo ves ya funcionando.
#7
Posted 17 November 2011 - 11:37 AM
Hola
Si lo que te interesa es independizar cada formulario de los demás, es decir que usen cada uno su propia copia de cada DataSet, la solución de Cadetill me parece muy acertada, aunque te tocará picar más código y acordarte de tenerlo actualizado cada vez que añadas un Dataset al DataModule, y es buena idea, como dice Cadetill, para estos menesteres colocar un DataSource en el mismo formulario al que ligar los controles, de esta forma sólo tienes que ligar por código dicho DataSource al DataSet correspondiente, despreocupándote de los controles que tengas ligados al DataSource.
Otra opción que te propongo, si tienes a bien echarle un vistazo, son unos componentes de Al González, los MagiaData, que entre otros fines están pensados para crear este tipo de duplicaciones (o clonados) de forma que tú ligas los controles de un formulario a DataSets en un TDataModule, y los componentes MagiaData ya se encargan de generar copias independientes de cada DataSet para cada formulario, independizando los formularios. Te dejo el enlace de su bitácora donde hace poco anunció que son de libre distribución:
http://rescatandoade...a-descarga.html
Saludos
Si lo que te interesa es independizar cada formulario de los demás, es decir que usen cada uno su propia copia de cada DataSet, la solución de Cadetill me parece muy acertada, aunque te tocará picar más código y acordarte de tenerlo actualizado cada vez que añadas un Dataset al DataModule, y es buena idea, como dice Cadetill, para estos menesteres colocar un DataSource en el mismo formulario al que ligar los controles, de esta forma sólo tienes que ligar por código dicho DataSource al DataSet correspondiente, despreocupándote de los controles que tengas ligados al DataSource.
Otra opción que te propongo, si tienes a bien echarle un vistazo, son unos componentes de Al González, los MagiaData, que entre otros fines están pensados para crear este tipo de duplicaciones (o clonados) de forma que tú ligas los controles de un formulario a DataSets en un TDataModule, y los componentes MagiaData ya se encargan de generar copias independientes de cada DataSet para cada formulario, independizando los formularios. Te dejo el enlace de su bitácora donde hace poco anunció que son de libre distribución:
http://rescatandoade...a-descarga.html
Saludos
#8
Posted 17 November 2011 - 06:47 PM
Carai! muchas gracias a los tres... estoy probando la opción de cadetill pero mi datasource esta en el datamodule...
Pensé que todo sería iterar por el array de components hacer un 'is tdbedit ' con findcomponent pero soy incapaz de realizar las asignaciones...
Alguna idea o muevo toooodos los datasources a los child?
Pensé que todo sería iterar por el array de components hacer un 'is tdbedit ' con findcomponent pero soy incapaz de realizar las asignaciones...
Alguna idea o muevo toooodos los datasources a los child?
#9
Posted 18 November 2011 - 01:50 AM
Buenas,
Si no quieres mover los TDataSource al formulario, tendrás que tirar de RTTI. Tendrás que recorrer todos los componentes del fomulario y "preguntar" a cada componente si tiene la propiedad DataSource y, en caso de tenerla, asignársela.
El único "problema" que tiene ésto es si usas más de una tabla (DataSource) en el mismo formulario. Te tocará escoger el que menos componentes tenga y asignarle el DataSource "a mano" después de la función de asignación de DataSources.
La función de asignación del DataSource principal podría ser algo así
PPropInfo está definido en la unit TypInfo
Ahora, en el constructor de la clase, sólo te hace falta llamar a este método y seguidamente asignar "a pelo" los DataSources a los controles que no dependan de MiDataSource (en el caso de que los hubiera).
Espero te sirva
Nos leemos
Si no quieres mover los TDataSource al formulario, tendrás que tirar de RTTI. Tendrás que recorrer todos los componentes del fomulario y "preguntar" a cada componente si tiene la propiedad DataSource y, en caso de tenerla, asignársela.
El único "problema" que tiene ésto es si usas más de una tabla (DataSource) en el mismo formulario. Te tocará escoger el que menos componentes tenga y asignarle el DataSource "a mano" después de la función de asignación de DataSources.
La función de asignación del DataSource principal podría ser algo así
delphi
procedure TCustomModalDbFrm.AssignDataSet; procedure Assignar(Componente: TComponent); var idx: integer; PropInfo: PPropInfo; Component: TComponent; begin for idx := 0 to Componente.ComponentCount - 1 do begin Component := Componente.Components[idx]; PropInfo := GetPropInfo( Component.ClassInfo, 'DataSource' ); if Assigned(PropInfo) then SetObjectProp(Component, 'DataSource', MiDataSource); if Component.ComponentCount > 0 then Assignar(Component); end; end; begin Assignar(Self); end;
PPropInfo está definido en la unit TypInfo
Ahora, en el constructor de la clase, sólo te hace falta llamar a este método y seguidamente asignar "a pelo" los DataSources a los controles que no dependan de MiDataSource (en el caso de que los hubiera).
Espero te sirva
Nos leemos
#10
Posted 18 November 2011 - 02:50 PM
Bueno... sin duda tu método es mejor a mi chapuza....
for i := ComponentCount-1 downto 0 do
begin
if Components[i] is tdbnavigator then
begin tdbnavigator(Components[i]).datasource:=tdatasource(fmydm.FindComponent(stringreplace(string(tdbnavigator (Components[i]).Name),'dbnv_','ds_', [rfReplaceAll, rfIgnoreCase])));
end;
end;
Asi si el dbnavigator se llama dbnv_oe se q tengo q asignar al ds_oe.
Estaría bien poder solucionar esta chapuza estableciendo la asignacion con lo que se ha definido en tiempo de diseño.
Es decir, que si al dbnavigator le he asignado el datasource dm_oe.ds_oe me evito un problema... el tema es que no soy capaz de sacar un dbnavitagor.datasource.tostring sin que de la lógica excepción....
Y si... tengo mas de un datasource en el mismo formulario...
( Parece que lo he hecho todo mal...
for i := ComponentCount-1 downto 0 do
begin
if Components[i] is tdbnavigator then
begin tdbnavigator(Components[i]).datasource:=tdatasource(fmydm.FindComponent(stringreplace(string(tdbnavigator (Components[i]).Name),'dbnv_','ds_', [rfReplaceAll, rfIgnoreCase])));
end;
end;
Asi si el dbnavigator se llama dbnv_oe se q tengo q asignar al ds_oe.
Estaría bien poder solucionar esta chapuza estableciendo la asignacion con lo que se ha definido en tiempo de diseño.
Es decir, que si al dbnavigator le he asignado el datasource dm_oe.ds_oe me evito un problema... el tema es que no soy capaz de sacar un dbnavitagor.datasource.tostring sin que de la lógica excepción....
Y si... tengo mas de un datasource en el mismo formulario...

#11
Posted 18 November 2011 - 03:59 PM
Buenas
Yo no me complicaría la vida y pasaría los TDataSources al formulario. No te cuesta nada y la facilidad en el código la notarás.
No obstante, depende de la cantidad de componentes que tengas de cada DataSet. Si por ejemplo es un pantalla master-detail, y tienes dbEdits para la master y un grid para el detail, puedes hacer algo así:
Espero te sirva
Yo no me complicaría la vida y pasaría los TDataSources al formulario. No te cuesta nada y la facilidad en el código la notarás.
No obstante, depende de la cantidad de componentes que tengas de cada DataSet. Si por ejemplo es un pantalla master-detail, y tienes dbEdits para la master y un grid para el detail, puedes hacer algo así:
delphi
constructor TForm1.Create(aOwner: TComponent); begin inherited; // asignamos un determinado dataset a todos los componentes del formulario AssignDataSet; // asignamos los componentes individuales navidatorDetail.DataSource := DataModule.DataSourceDetail; grid.DataSource := DataModule.DataSourceDetail; end;
Espero te sirva
#12
Posted 18 November 2011 - 04:36 PM
Nah! Definitivamente muevo los datasources al child y para asignar algo asi:
tdatasource(Components[i]).dataset:=tdataset(fmydm.FindComponent(stringreplace(string(tdxbardbnavigator(Components[i]).Name),'ds_','qry_', [rfReplaceAll, rfIgnoreCase])));
end;
end;
[/code]
Y arreglao...
Ahora el tema es que tengo un arbol de datamodules es decir tengo un dm_lgstc y un dm_lgstc_ul y en los childs utilizo ambos...
Los de nivel superior suelen ser maestro el tema es si tambien los "clono" o los uso compartidos.
Esto es mas una duda de implementación que técnica no se si continuamos con el hilo o abro uno nuevo...
Gracias a todos por la ayuda...
delphi
for i := ComponentCount-1 downto 0 do begin if Components[i] is tdatasource then begin
tdatasource(Components[i]).dataset:=tdataset(fmydm.FindComponent(stringreplace(string(tdxbardbnavigator(Components[i]).Name),'ds_','qry_', [rfReplaceAll, rfIgnoreCase])));
end;
end;
[/code]
Y arreglao...
Ahora el tema es que tengo un arbol de datamodules es decir tengo un dm_lgstc y un dm_lgstc_ul y en los childs utilizo ambos...
Los de nivel superior suelen ser maestro el tema es si tambien los "clono" o los uso compartidos.
Esto es mas una duda de implementación que técnica no se si continuamos con el hilo o abro uno nuevo...
Gracias a todos por la ayuda...

#13
Posted 18 November 2011 - 04:52 PM
Buenas,
Abre otro hilo y explicate un poco mejor, que al menos yo no he terminado de entenderte
Nos leemos
Abre otro hilo y explicate un poco mejor, que al menos yo no he terminado de entenderte

Nos leemos