Hola Rolphy,
Desconozco Report Builder, por lo que en ese aspecto no puedo asesorarte. Lo que me llama la atención y en lo que tengo en duda es relacionado con lo que comentas:
Después de la llamada al método LoadFromDatabase es que se conocen cuales son los componentes que pertenecen al diseño seleccionado. Supongamos que el usuario ha seleccionado la opción de reporte llamada Estado de Cuenta donde se pide un rango de Fecha, esas fechas seleccionadas son las que quiero mostrar en la impresión; entonces debe existir un procedimiento donde yo le diga esto:
Uses DmCustomReport;
TFrmEstadoCuenta.btnImprimir(Sender : TObject);
begin
DmCustomReport.[b]Modificar[/b](ComponenteFecha, ValorAMostrar);
end;
Como bien indica Escafandra el procedimiento que debe de existir en el DataModule donde reside el componente de Reporte debe de tener un FindComponent o cualquier otra forma para conocer los componentes que se van a modificar en Run-Time.
Ahora bien, el usuario selecciona la opción Reportes de Cliente aquí solo es necesario un Clic en el botón impresión sin mandar ningún cambio al reporte. Sin embargo, pienso que el procedimiento de modificar debe de ejecutarse aunque no tenga nada que modificar.
Espero haber sido más claro.
Léase las negritas que he colocado.
No termino de comprender. Tienes un método Modificar que debe ser capaz de modificar un componente (o al menos uno) que no necesariamente debe ejecutarse.
Primero indicas que en un supuesto caso de querer imprimir un Estado de Cuenta se necesita de un rango, y por tanto se debe modificar un componente. Por el otro existe otra opción de imprimir los Reportes de Cliente y que no requiere de modificación alguna.
Si es como estoy entendiendo, y existe un único componente "Reporte" en el cual se visualiza todos y cualesquiera de los tantos reportes disponibles, entonces el método Modificar debe ser capaz de determinar en que casos es necesario dicha modificación. Si es así, por tanto Modificar debe ser capaz de reconocer un diseño de otro a fin de aplicar los cambios adecuados (si es necesario).
¿Si en alguna ocasión no debe realizar cambio alguno, que sentido tiene que deba ejecutarse?
Por un lado entiendo que Modificar no sabe que informe es, que sólo se limita a modificar ciertas propiedades de algún componente. Entonces, antes de cada impresión deberá invocarse a dicho método. Algo así, a modo de ejemplo:
procedure ButtonImprimirFactura(Sender: TObject);
begin
DataModule.CargarReporte(Factura);
DataModule.Modificar(Componente, Valor);
DataModule.Imprimir;
end;
En el ejemplo, se ilustra que se pide al DataModule que cargue el reporte de Factura, luego modifica algún componente y lo manda a imprimir.
En caso de que en otro reporte no sea necesario modificar algo simplemente no se lo invoca.
Eso es lo que me parece que has intentado ilustrar con tu ejemplo.
La pregunta aquí es si en realidad las modificaciones dependen o están relacionadas fuertemente con los reportes. Por ejemplo, si en algunos reportes es necesario modificar 20 labels, en otro 4 combos, en otro un pie de página y 6 logos, etc.
En caso de que todas las modificaciones tengan un denominador común (como por ejemplo: en realidad sólo se necesita modificar el título, un caption). Es posible esperar entonces un método muy simple y algo que con un simple FindComponent() bastaría.
Pero si estamos hablando de un escenario en donde las modificaciones dependen fuertemente del reporte es necesario un rediseño.
Quien tiene el poder, en principio, de leer el reporte adecuado tiene la información (Patrón "Experto en Información") y la capacidad (Patrón "Hacerlo yo Mismo") para determinar que cambios aplicar es el DataModule (según lo que desprendo de tus mensajes).
Debe dotarse de un mecanismo capaz de "traducir" reporte -> cambios.
Desde un punto exquisito de OO lo de esperar es una especie de "motor" de reportes. Esto se puede conseguir con algo como esto:
1. Disponer de una clase base "MotorReporte" con un método Modificar() virtual (quizás hasta abstracto).
2. Disponer de tantas clases descendientes de MotorReporte como tipos de informes existan. Cada una con un método Modificar() capaz de encontrar los diferentes tipos de controles y cambiar las propiedades adecuadas.
3. Existe una Fábrica FabricaMotorReporte que se encarga de crear las clases descendientes de MotorReporte.
4. Se asocia al DataModule con la clase que regresa la fábrica. Por tanto, el DataModule le indica a la fábrica cual necesita y ésta le regresa el objeto adecuado.
5. El DataModule envía la orden al motor creado de Modificar y luego envía el mensaje de Imprimir al reporte ya modificado.
Espero que se entienda.
Otra alternativa, similar a esta, es que sea el mismo DataModule quien asuma el rol de Fábrica. De este modo reducimos la cantidad de clases, aunque se pierde cierta cohesión. En este escenario es posible que el mismo método CargarReporte() quien, además de cargar el reporte, crea el objeto (después de todo... tiene la misma visibilidad de parámetro adecuada para lo que requiere el hipotético método CrearMotor() de una fábrica)
Es evidente que este enfoque del motor sólo es útil cuando la cantidad de reportes es mayor que la de los posibles cambios a realizar.
Me gustaría que Rolphy nos describiera con mayor precisión y profundidad sobre lo que está realizando. Me quedan muchas dudas sobre el enfoque que está siguiendo.
Saludos y disculpen el rollo.