Ver Mensaje Individual
  #18  
Antiguo 27-01-2004
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Reputación: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
Vamos a intentar aclarar un poco las cosas.

El primer paso, aunque parezca un poco pesado, es que aprendas a utilizar la etiqueta [ code ] para escribir código en tus mensajes. Esta etiqueta te permite preservar las indentaciones en las líneas que escribes lo cual facilita muchísimo la lectura:

Código:
if UsoEtiquetaCode then
    LasLineasPreservanLaIndentacion;

{
    Lo anterior fue escrito así:

    [ code ]
    if UsoEtiquetaCode then
        LasLineasPreservanLaIndentacion;
    [ /code ]
}
Pasado este punto mi primera recomendación es que revises el ejemplo que viene con Delphi de un editor mdi ya que aprenderás mucho acerca de cómo manejar ventanas mdi incluyendo los comandos "Nuevo", "Abrir", etc.

Ahora bien, hay que tener claras algunas cosas.

En algún momento preguntaste por cómo llamar a un procedimiento que tiene un parámetro por referencia. Tu pregunta se originó por tu deseo de llamar desde la ventana padre al procedimiento para cerrar la ventana hija.

Aquí hay una confusión de conceptos. El procedimiento para cerrar una ventana es Close mientras que OnCloseQuery es el evento que se genera cuando se intenta cerrar una ventana, sea cual sea el método con el que se cierre (procedimiento Close, hacer click en el cuadrito de la cruz, oprimir Alt-F4, etc.)

Por regla general los eventos no deben llamarse explícitamente ya que no es esa su funcionalidad. Para entender esto conviene separar estos dos conceptos:
  • evento
  • manejador de evento

El evento lo genera "el sistema" y el manejador es el código que responde al evento. Tu parte como programador es escribir el manejador y dejar que el sistema genere el evento (es decir, que sea el sistema el que llame a tu manejador).

Para concretizar pensemos en el evento en particular de CloseQuery:

Cuando un usuario quiere cerrar una ventana (sea cual sea el método que utilice) el sistema (en este caso Windows) manda la señal WM_CLOSE a la ventana. Delphi intercepta esta señal y toma uno de dos caminos:
  • Si no hay manejador disponible (no definiste OnCloseQuery) deja que el evento siga su marcha normal y el resultado es que la ventana se cierra.
  • Si hay un manejador disponible entonces lo llama así:
    Código:
    var
      CanClose: Boolean;
    
    begin
      CanClose := true;
      OnCloseQuery(..., CanClose);
      if CanClose then
        permite cerrar la ventana
      else
        impide cerrar la ventana;
    end;
    Es decir, llama al manejador y dependiendo de lo que éste decida (mediante CanClose), permite o no cerrar la ventana.

Con esto verás que es inútil que tú intentes llamar directamente al manejador ya que es Delphi y no tú quien puede aprovechar el valor de CanClose.

Aplicando esto a tu problema específico: según me da la impresión tu intentas o intentabas usar el manejador OnCloseQuery de una ventana hija desde la ventana padre para controlar si el editor está o no modificado y en su caso presentar un mensaje. Pero esta no es labor de la ventana padre. Es la ventana hija (cada ventana hija) la encargada de determinar esto. Por eso tu código:

Código:
with (ActiveMDIChild as TVentana_Hija) do
begin
  if (RE_Editor.Modified) then
  begin
    Respuesta := Application.MessageBox('¿Desea guardar los cambios? ',
      ' Guardar',mb_IconWarning + mb_yesNoCancel);

    Case Respuesta of
      idYes:
      begin
        SD_Guardar_Fichero.Filename := Caption;
        if (FileExists (SD_Guardar_Fichero.Filename)) then
        begin
          RE_Editor.Lines.SaveToFile(SD_Guardar_Fichero.Filename);
          Close;
        end
        else
          etc
es conceptualmente incorrecto y, por tanto, propenso a los problemas que enfrentas.

Todo el código para determinar si el editor tiene cambios o no, presentar un mensaje, guardar en su caso los cambios, etc. es labor de la ventana hija que esté a punto de cerrarse. Todo esto debe ir en el manejador de CloseQuery.

Piénsalo de esta forma: la ventana hija es un ente independiente de su padre. Es una ventana cuya función en la vida es permitir la edición de textos. Si el padre desaparece (por ejemplo si el día de mañana decides que tu aplicación sólo edite un archivo a la vez) la ventana hija sigue estando lista para hacer todo el trabajo relacionado con el archivo a editar.

La labor del padre es controlar a las hijas independientemente de qué hagan estas hijas: podrías tener distintos tipos de ventanas hijas (editores, calculadoras, gráficos, etc.) y con tú método el padre tendría que ocuparse de todos los posibles casos lo que a todas luces es inconveniente.

El control del padre radica, por ejemplo, en acomodar a las ventanas dentro de su área, mantener una lista de las ventanas abiertas, etc. También se puede encargar de mandar comandos a las ventanas pero dejar que ellas hagan su trabajo. Así por ejemplo, cuando en Word el usuario oprime el botón de guardar, la ventana padre manda llamar al procedimiento Guardar de la ventana activa (ActiveMdiChild) pero nada más; es ésta ventana activa la que se encarga de preguntar al usuario el nombre del archivo, etc.

Si el usuario usa el menú Archivo|Cerrar, la ventana padre se limita a llamar a algún procedimiento de la ventana hija activa del estilo de Close y es ésta última quien se encarga de todo lo demás.

Otro punto de vista para aclarar:

¿Qué pasa cuando el usuario desea apagar la PC?

Puedes considerar a Windows como la ventana padre. Como tal, él se encarga de llamar al procedimiento Close de cada ventana abierta pero estarás de acuerdo que es cada una de éstas, y no Windows, quien hace el trabajo de limpieza (guardar, advertir de cambios, etc.)

Así pues, si deseas que la ventana padre cierre a una hija limítate a llamar al método Close de la hija y deja que ésta haga todo (bueno, tú pero a través de ella).


Yo sé que todo esto es un rollazo pero espero que te sirva para entender que en ocasiones tenemos muchos problemas con el código por la "simple" razón de que estamos enfocando mal el problema.

El resumen aquí podría ser:

Si quieres hacer un editor de textos mdi piensa primero en el problema más sencillo de cómo hacer un editor de una sóla ventana. Programas esta ventana, te peleas con todos los problemas que salgan, etc. Una vez que lo dominas, le pones a la ventana la propiedad MdiChild y la insertas en un proyecto Mdi. Todo, absolutamente todo (te lo aseguro) será mucho más sencillo.


// Saludos
Responder Con Cita