Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   ¿Cómo evitar que programa se congele? (https://www.clubdelphi.com/foros/showthread.php?t=96360)

pgranados 19-09-2023 02:58:56

¿Cómo evitar que programa se congele?
 
Buen día compañeros, tengo una aplicación donde paso la información de un XML a base de datos, el proceso tardara dependiendo la cantidad de xml, lo que busco es como evitar que el usuario se desespere y le empiece a dar clic y por ende el programa se congele (No responde)
Ya puse un contador así que busco alguna opción como deshabilitar la forma o que el hacerle clics no le afecte, ¿Cómo puedo hacer esto?

Neftali [Germán.Estévez] 19-09-2023 08:45:16

Es una pregunta demasiado genérica (o a la forma de explicar el proceso le faltan detalles).
Dependiendo de cómo esté programado el proceso de pasar los datos del XML a la Base de Datos, las soluciones pueden ser diferentes.

Por ejemplo, si la importación es por pasos, (donde puedas interferir durante el proceso) puedes usar ProcessMessages y una barra de estado o mensajes.
Si el proceso es "compacto" y no puedes intervenir puedes evaluar usar threads, para mostrar también una barra de progreso (sin fin) o una animación.

Puede haber más y mejores que estas 2, pero sin más detalles es difícil saber qué opción es la que te conviene o la que te funcionará.

duilioisola 19-09-2023 09:47:23

A nivel práctico, lo que comenta Neftalí sería:

Código Delphi [-]
OnCreate()
   // Un label en donde irás mostrando el progreso de proceso
   // Invisible por defecto
   LabelProgeso.Visible := False;


procedure ProcesaXML();
var
  Registro : integer;
begin
  // Visibilizo e inicializo el Label que muestra el progreso.
  LabelProgreso.Visible := True;
  LabelProgreso.Caption := '';
  Registro := 1;

  // Todo entre try..except para evitar que quede el label visible si algo falla
  try
    while XML_tenga_datos do
    begin
      // Muestro la información para que el usuario no se ponga nervioso
      LabelProgreso.Caption := 'Procesando Registro Nro. ' + IntToStr(Registro);
      // Fuerzo a que se procesen los eventos de mouse, teclado y refresco de pantalla
      Application.ProcessMessages;

      // Procesar Registro XML
      ...

      Next_Dato_XML;
      Inc(Registro);
    end;
  finally
    // Inivisibilizo Label ya que ha terminado el proceso
    LabelProgreso.Visible := False;
  end;
end;


Yo suelo poner un panel con labels, memos para logs y barras de progreso que hago visible tapando o invisibilizando los otros paneles de la aplicación.

pgranados 19-09-2023 16:50:58

Gracias por sus comentarios, explicare mejor la situación:

Pasar un XML a la base de datos me demora 0.1 - 0.2 segundos c/u

el problema viene cuando son por ejemplo 7k XML, pues tardaremos como 10 minutos aprox, entonces necesito "congelar" o hacer algo para que el usuario no este dándole clic al sistema y que este cuelgue

Tengo un ciclo mas o menos así:

Código Delphi [-]
var UUID:string;
begin
   for I := 0 to FileListBox.Items.Count-1 do
   begin
         FormaMensaje.label.caption:= 'XML '+IntToStr(i)+' de '+ IntToStr(FileListBox.Items.Count-1);
         FormaMensaje.label.refresh;
         XMLDocLocal.LoadFromFile(NomArchivoXML);
         UUID:= ExtraerDatosParaNombreArchivo(XMLDocLocal); // Obtengo el identificador del XML UUID
         Datamodule.FDQuery.Open('SELECT UUID FROM TABLA WHERE UUID = '+#39+UUID+#39');
         if Datamodule.FDQuery.isEmpty then // No existe en la base de datos, debo de grabarlo
                XMLaTabla(XMLDocLocal);
         // Mas cosas por acá............................
   end;
end;

duilioisola 19-09-2023 17:56:55

Entiendo que FormaMesaje es un Form que contiene un label en el que muestras el progreso.
Solo debes cambiar esta línea.

Código Delphi [-]
var UUID:string;
begin
   for I := 0 to FileListBox.Items.Count-1 do
   begin
         FormaMensaje.label.caption:= 'XML '+IntToStr(i)+' de '+ IntToStr(FileListBox.Items.Count-1);

         Application.ProcessMessages; // FormaMensaje.label.refresh;

         XMLDocLocal.LoadFromFile(NomArchivoXML);
         UUID:= ExtraerDatosParaNombreArchivo(XMLDocLocal); // Obtengo el identificador del XML UUID
         Datamodule.FDQuery.Open('SELECT UUID FROM TABLA WHERE UUID = '+#39+UUID+#39');
         if Datamodule.FDQuery.isEmpty then // No existe en la base de datos, debo de grabarlo
                XMLaTabla(XMLDocLocal);
         // Mas cosas por acá............................
   end;
end;

A veces, el procesar los mensajes de Windows incorpora una demora grande por lo que quizás quieras realizar este proceso cada n pasadas.
Código Delphi [-]
var UUID:string;
begin
   for I := 0 to FileListBox.Items.Count-1 do
   begin
         FormaMensaje.label.caption:= 'XML '+IntToStr(i)+' de '+ IntToStr(FileListBox.Items.Count-1);

          // Solo refresca 1 de cada 10 veces.
          if (i mod 10 = 0) then
             Application.ProcessMessages; // FormaMensaje.label.refresh;

         XMLDocLocal.LoadFromFile(NomArchivoXML);
         UUID:= ExtraerDatosParaNombreArchivo(XMLDocLocal); // Obtengo el identificador del XML UUID
         Datamodule.FDQuery.Open('SELECT UUID FROM TABLA WHERE UUID = '+#39+UUID+#39');
         if Datamodule.FDQuery.isEmpty then // No existe en la base de datos, debo de grabarlo
                XMLaTabla(XMLDocLocal);
         // Mas cosas por acá............................
   end;
end;

Casimiro Notevi 19-09-2023 18:01:59

Justo lo que te han contestado :)

De toda formas, también puedes deshabilitar el botón cuando lo pulsen, así no podrán darle más veces.
Código Delphi [-]
procedure TForm1.Button1Click(Sender: TObject);
begin
  Button1.Enabled:=False;
  //
  ...
end;

Neftali [Germán.Estévez] 20-09-2023 08:39:56

Además de lo dicho y fijándome en este código:

Cita:

Empezado por pgranados (Mensaje 552555)


Código Delphi [-]
   XMLaTabla(XMLDocLocal);
  // Mas cosas por acá............................


Yo añadiría lo siguiente:
Código Delphi [-]
Datamodule.FDQuery.DisableControls;
try
  for I := 0 to FileListBox.Items.Count-1 do begin    ...
    XMLaTabla(XMLDocLocal);
    // Mas cosas por acá..........................
    ...
finally
  Datamodule.FDQuery.EnableControls;
end;

Puede mejorar dependiendo de los componentes visuales que tengas asociados al Dataset (si los tienes). Lo mismo con otros que tengas asociados a componentes visuales (Grids,...)


La franja horaria es GMT +2. Ahora son las 07:15:38.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi