Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Conexión con bases de datos (https://www.clubdelphi.com/foros/forumdisplay.php?f=2)
-   -   actualizar tabla al calcular un campo autocalculado (https://www.clubdelphi.com/foros/showthread.php?t=8954)

Telemaco 07-04-2004 11:57:43

actualizar tabla al calcular un campo autocalculado
 
Hola a todos

estoy trabajando con Delphi 7 y sqlserver 2000 y en mi aplicacion en la tabla de fichajes transformo una cadena como esta 08:00 a un valor numerico, y pretendo asignarselo a un campo de la bd de tipo entero, pero siempre me sale el mismo error:
"stack over flow"
y no se como hacer que me modifique la bd con el dato que quiero introducir, alguien podria ayudarme.

Gracias.

guillotmarc 07-04-2004 12:10:38

Hola.

¿ Como transformas a valor numérico ?. Porqué yo no veo claro que valor numérico corresponde a la cadena '08:00'

Saludos.

Telemaco 07-04-2004 13:05:52

he hecho una funcion que transforma de una cadena los numero en valores numericos y desecha los caracteres.

Cita:

Empezado por guillotmarc
Hola.

¿ Como transformas a valor numérico ?. Porqué yo no veo claro que valor numérico corresponde a la cadena '08:00'

Saludos.


guillotmarc 07-04-2004 13:46:05

El mensaje de error te indica que tienes un desbordamiento de pila. ¿ Esta función es recursiva ?.

Vas a tener que poner algo de código, de la función que falla, y de como intentas actualizar el campo.

Saludos.

Telemaco 07-04-2004 16:02:12

Hola GuillotMarc

este es el codigo del procedimiento CalcFields
var
manyana,tarde:boolean;
M1,M2,T1,T2:String;
op,hor,min:integer;

h1,h2:string;
ht : array [0..2] of char;
mt : array [0..5] of char;
x:STRING;

m,t:Tdatetime;
horas:string;
i:byte;
hh,mm:string;
hint,mint:integer;

begin
op:= strtoint(FCronos.TipoAccion.text);
case op of
1 : {Actualizo los campos autocalculados'}
begin
manyana:=false;
tarde:=false;
if Tfichajes.FieldByName('HoraEntM').AsString >'00:00:00'
then begin
M1:=TFichajes.FieldbyName('HoraEntM').AsString;
end
else begin
manyana:=true;
{ M1:='07:07:00';}
end;
if (TFichajes.FieldByName('HoraSalM').AsString) > '00:00:00'
then begin
M2:=Tfichajes.FieldByName('HoraSalM').Asstring;
end
else begin
manyana:=true;
{ M2:='13:33:00'}
end;
if TFichajes.FieldByName('HoraEntT').AsString > '00:00:00'
then begin
T1:=Tfichajes.fieldbyname('HoraEntT').AsString;
end
else begin
Tarde:=true;
end;
if TFichajes.FieldByName('HoraSalT').AsString > '00:00:00'
then begin
T2:=Tfichajes.fieldbyname('HoraSalT').AsString;
end
else begin
Tarde:=true;
end;

if not manyana
then h1:=timetostr(strtotime(M1)-strtotime(M2))
else begin
h1:='00:00:00';
manyana:=true;
end;
if not tarde
then h2:=timetostr(strtotime(T1)-strtotime(T2))
else begin
h2:='00:00:00';
tarde:=true;
end;

x:=timetostr((strtotime(h1)+strtotime(h2)));
if (not tarde) and (not manyana)
then begin
FFichaEmp.GEFichaje.Font.color := clnavy;


TFichajes.FieldByName('HTXT').AsString:=x;
mm:='';hh:='';
TFichajes.fieldbyname('Mayana').asstring:=h1;
TFichajes.fieldbyname('Tarde').asstring:=h2;

horas:=x;
for i:=1 to length(horas) do
begin
if Horas[i] <> ':'
then if i<3 then hh:=hh+Horas[i]
else if i>3 then
if i<6 then mm:=mm+Horas[i];
end;
hint:=strtoint(hh);
mint:=strtoint(mm);
TFichajes.Edit; { AL AÑADIR ESTA LINEA ME DA DESBORDAMIENTO}
TFichajes.FieldByName('Horas').AsInteger:= hint;
TFichajes.FieldByName('Minutos').AsInteger:=mint;

end
else begin
FFichaEmp.GEFichaje.Font.Color :=clred;
TFichajes.FieldByName('HTXT').AsString:=x;

mm:='';hh:='';
horas:=x;

for i:=1 to length(horas) do
begin
if Horas[i] <> ':'
then if i<3 then hh:=hh+Horas[i]
else if i>3 then
if i<6 then mm:=mm+Horas[i];
end;
hint:=strtoint(hh);
mint:=strtoint(mm);
TFichajes.Edit;
TFichajes.FieldByName('Horas').AsInteger:= hint;
TFichajes.FieldByName('Minutos').AsInteger:=mint;

end;

Como ves el codigo es muy rudimentario, lo siento pero soy novato...jeje

gracias por tu ayuda.

Adios.

Cita:

Empezado por guillotmarc
El mensaje de error te indica que tienes un desbordamiento de pila. ¿ Esta función es recursiva ?.

Vas a tener que poner algo de código, de la función que falla, y de como intentas actualizar el campo.

Saludos.


andres1569 07-04-2004 17:21:40

Hola, Telemaco, sería de agradecer que encerraras todo ese código entre etiquetas [ code ] y [ /code ], aparecería el código identado y más gente se animaría a investigarlo en busca de la solución ...

Un Saludo

guillotmarc 07-04-2004 17:42:24

Hola.

Un desbordamiento de pila, indica un bucle infinito de llamadas a procedimientos. ¿ El evento CalcFields que programas es sobre el mismo dataset TFichajes ?.

Probablemente la llamada al Edit, provoca que se vuelva a ejecutar el evento CalcFields, que vuelve a llamar al Edit, que vuelve a ejecutar el evento, ..., ..., ... Hasta el desbordamiento de pila.

¿ Para que necesitas llamar al Edit dentro del CalcFields ? Si los campos Horas y Minutos són campos Calculados, entonces no hace falta que llames al Edit, los puedes modificar tranquilamente. Si en lugar de ser campos calculados són campos normales, no deberías asignarles su valor en el CalcFields (que se ejecuta muchas veces por el mismo registro, y sin que hayan cambiado los valores de sus campos) sinó que tendrías que cambiar el valor, dentro del evento OnChange de los campos HoraEntM, HoraEntT, HoraSalM, HoraSalT, ...

Saludos.

jachguate 07-04-2004 18:39:34

Dado que no está indentado, se me hace realmente dificil leer el código, y no lo he hecho (seguí la recomendación de Andres al respecto). Sin embargo me parece que, dado que se trata de un evento OnCalcFields, seguramente estas haciendo una asignación a un campo no calculado dentro del evento, con lo que éste se dispara nuevamente... provocando una recursividad indirecta, e infinita (ya que no hay condición que pare esta recursividad).

Esto lo podes comprobar fácilmente poniendo un breakpoint al inicio del método, siguiendolo paso a paso, y viendo como, al hacer alguna asignación (o probablemente la llamada a otra rutina que hace una asignación) el evento se dispara nuevamente (pasando por el breakpoint).

Yo elimino normalmente este efecto teniendo un flag en el formulario o módulo de datos, digamos FCalculando... que inicializas a false, y luego hago algo como esto en el evento:

Código:

Procedure Form1Table1CalcFields(parametros);

Begin
  if not FCalculando Then
  Begin
    FCalculando := True;
    // se enciende el flag, para evitar la recursividad indirecta.
    try 
      CodigoNormalDelEvento;
    finally
      FCalculando := False; // esto siempre se ejecuta, aunque el evento se aborte
      // por una condición de error.
    End;
  End;
  // de esta forma, no se ejecuta ni una sola línea si ya se ha entrado al evento
  // una vez
End;

Hasta luego.

;)

Telemaco 08-04-2004 09:32:22

Hola a todos de nuevo y disculparme pero no sabia que debia utilizar al etiqueta Code, aqui os paso de nuevo el codigo.

Código:

  var
    manyana,tarde:boolean;
    M1,M2,T1,T2:String;
      op,hor,min:integer;
 
      h1,h2:string;
      ht : array [0..2] of char;
      mt : array [0..5] of char;
      x:STRING;
 
      m,t:Tdatetime;
      horas:string;
      i:byte;
      hh,mm:string;
      hint,mint:integer;
 
  begin
    op:= strtoint(FCronos.TipoAccion.text);
    case op of
    1 : {Actualizo los campos autocalculados'}
          begin
            manyana:=false;
            tarde:=false;
              if Tfichajes.FieldByName('HoraEntM').AsString >'00:00:00'
                then  begin
                        M1:=TFichajes.FieldbyName('HoraEntM').AsString;
                      end
                else  begin
                        manyana:=true;
                        {    M1:='07:07:00';}
                      end;
              if (TFichajes.FieldByName('HoraSalM').AsString) > '00:00:00'
                then  begin
                        M2:=Tfichajes.FieldByName('HoraSalM').Asstring;
                      end
                else  begin
                        manyana:=true;
                      {  M2:='13:33:00'}
                      end;
              if TFichajes.FieldByName('HoraEntT').AsString > '00:00:00'
                then begin
                      T1:=Tfichajes.fieldbyname('HoraEntT').AsString;
                      end
                else  begin
                        Tarde:=true;
                        end;
              if TFichajes.FieldByName('HoraSalT').AsString > '00:00:00'
                then  begin
                          T2:=Tfichajes.fieldbyname('HoraSalT').AsString;
                      end
                else  begin
                        Tarde:=true;
                      end;
 
            if not manyana
                then h1:=timetostr(strtotime(M1)-strtotime(M2))
                else  begin
                        h1:='00:00:00';
                        manyana:=true;
                      end;
            if not tarde
                then h2:=timetostr(strtotime(T1)-strtotime(T2))
                else  begin
                        h2:='00:00:00';
                        tarde:=true;
                      end;
 
            x:=timetostr((strtotime(h1)+strtotime(h2)));
            if (not tarde) and (not manyana)
                then  begin
                      FFichaEmp.GEFichaje.Font.color := clnavy;
 
 
                      TFichajes.FieldByName('HTXT').AsString:=x;
                      mm:='';hh:='';
                      TFichajes.fieldbyname('Mayana').asstring:=h1;
                      TFichajes.fieldbyname('Tarde').asstring:=h2;
 
                      horas:=x;
                      for i:=1 to length(horas) do
                        begin
                              if Horas[i] <> ':'
                                then if i<3 then hh:=hh+Horas[i]
                                        else if i>3 then
                                    if i<6 then mm:=mm+Horas[i];
                        end;
                      hint:=strtoint(hh);
                      mint:=strtoint(mm);
                      TFichajes.Edit;  { AL AÑADIR ESTA LINEA ME DA DESBORDAMIENTO}
                      TFichajes.FieldByName('Horas').AsInteger:= hint;
                      TFichajes.FieldByName('Minutos').AsInteger:=mint;
 
                      end
                else begin
                      FFichaEmp.GEFichaje.Font.Color :=clred;
                      TFichajes.FieldByName('HTXT').AsString:=x;
 
                      mm:='';hh:='';
                      horas:=x;
 
                      for i:=1 to length(horas) do
                        begin
                              if Horas[i] <> ':'
                                then if i<3 then hh:=hh+Horas[i]
                                        else if i>3 then
                                    if i<6 then mm:=mm+Horas[i];
                        end;
                      hint:=strtoint(hh);
                      mint:=strtoint(mm);
                      TFichajes.Edit;
                      TFichajes.FieldByName('Horas').AsInteger:= hint;
                      TFichajes.FieldByName('Minutos').AsInteger:=mint;
 
                      end;

He probado tambien a utilizar el OnChange pero no termina de funcionarme bien, ya que no actua en todos los casos, sabriais decirme por que ocurre esto? os adjunto el codigo

Código:

procedure TDM1.TFichajesHoraSalMChange(Sender: TField);
 var
 
    manyana,tarde:boolean;
    M1,M2,T1,T2:String;
    op,hor,min:integer;
 
    h1,h2:string;
    ht : array [0..2] of char;
    mt : array [0..5] of char;
    x:STRING;
 
    m,t:Tdatetime;
    horas:string;
    i:byte;
    hh,mm:string;
    hint,mint:integer;
 
 begin
    manyana:=false;
 
    if dm1.Tfichajes.FieldByName('HoraEntM').AsString >'00:00:00'
          then M1:=dm1.TFichajes.FieldbyName('HoraEntM').AsString
          else  manyana:=true;
    if (dm1.TFichajes.FieldByName('HoraSalM').AsString) > '00:00:00'
          then M2:=dm1.Tfichajes.FieldByName('HoraSalM').Asstring
          else manyana:=true;
    if not manyana
                then h1:=timetostr(strtotime(M1)-strtotime(M2))
                else  begin
                            h1:='00:00:00';
                            manyana:=true;
                          end;
          x:=timetostr(strtotime(h1));
          if (not manyana)
                  then  begin
                            mm:='';hh:='';
                            DM1.TFichajes.Edit;
                            DM1.TFichajes.fieldbyname('Mayana').asstring:=h1;
                            horas:=x;
                            for i:=1 to length(horas) do
                                begin
                                    if Horas[i] <> ':'
                                          then if i<3
                                                  then hh:=hh+Horas[i]
                                                  else if i>3 then
                                    if i<6 then mm:=mm+Horas[i];
                                end;
                            hint:=strtoint(hh);
                            mint:=strtoint(mm);
 
                            dm1.TFichajes.FieldByName('Horas').AsInteger:= hint;
                            dm1.TFichajes.FieldByName('Minutos').AsInteger:=mint;
                            end;
 
    dm1.TFichajes.Post;
    dm1.TFichajes.next;
 
 end;

Se dispara el evento en el momento que actualizo o modifico un valor del field HSalM. Al escribir este evento he eliminado el codigo que asiganba valores en el evento OnCalcFields, pero ahora tambien me aparece el "Stack Overflow" :mad:, alguna sugerencia???

Gracias a todos.

__cadetill 08-04-2004 11:31:58

Cita:

Empezado por Telemaco
Código:

TFichajes.Edit;  { AL AÑADIR ESTA LINEA ME DA DESBORDAMIENTO}

Es que el evento OnCalcFields no es para modificar los campos físicos de la tabla, sino SOLO los calculados. Al hacer un Edit (y luego un Post aunque sea implícito), es cuendo vuelve a saltar el evento OnCalcFields y, así, hasta el infinito y más allá :p

Si esos campos son los calculados, no hace falta que hagas el Edit, sencillamnete asignas los valores y listo ;)

Telemaco 08-04-2004 11:58:44

Ok, Gracias, lo he probado y va perfecto, pero ahora el problema es que me da desbordamiento en el evento OnChange, al hacer un Edit, el codigo del evento esta en mi anterior cita...(por no volverlo a poner ;))

si me puedes aportar alguna idea....gracias.

Cita:

Empezado por cadetill
Es que el evento OnCalcFields no es para modificar los campos físicos de la tabla, sino SOLO los calculados. Al hacer un Edit (y luego un Post aunque sea implícito), es cuendo vuelve a saltar el evento OnCalcFields y, así, hasta el infinito y más allá :p

Si esos campos son los calculados, no hace falta que hagas el Edit, sencillamnete asignas los valores y listo ;)


__cadetill 08-04-2004 12:30:27

Cita:

Empezado por Telemaco
Ok, Gracias, lo he probado y va perfecto, pero ahora el problema es que me da desbordamiento en el evento OnChange, al hacer un Edit, el codigo del evento esta en mi anterior cita...(por no volverlo a poner ;))

si me puedes aportar alguna idea....gracias.

Si los campos que se modifican en el OnChange del DbEdit son calculados, repito lo que te decía anteriormente, el único lugar para asignar valores a los campos calculados es el OnCalcFields

Si son físicos y estás modificando el valor del campo que se visualiza en él, esto hará saltar el evento onChange de forma recursiva

Te aconsejo que pongas un punto de ruptura y lo debugees, yo no veo demasiado claro por donde biene el error :(

marto 08-04-2004 12:48:33

Cita:

Empezado por Telemaco
pero ahora el problema es que me da desbordamiento en el evento OnChange, al hacer un Edit,

Digo yo... ¿Si estás en el evento OnChange, no estás ya en edición? ¿Para qué necesitas hacer un Edit?

guillotmarc 08-04-2004 13:48:59

Hola.

A mi me parece que ya tienes todos los datos para solucionar el problema por ti mismo. Ya te hemos indicado que el problema de desbordamiento de pila se debe a un bucle infinto de disparos de eventos. Te hemos ayudado sobre que evento es más conveniente utilizar para cada caso. Y finalmente Jachguate te ha indicado como evitar los bucles infinitos en el caso de eventos que ejecutan código que forzosamente provoca que se vuelva a disparar el mismo evento.

Ahora lo tienes que solucionar tu, depurando el código para ver cual es la linea que provoca el desbordamiento, y poniendo puntos de ruptura en los eventos, para ver cual es el que se dispara infinitamente. Una vez detectado eso, tienes que solucionarlo, viendo si es que no estás realizando acciones necesarias, y protegiendo con un flag el evento que se dispara infiinitamente.

¿ Supongo que no estás esperando a que te pongamos nosotros el código de los eventos ?

Saludos.

Telemaco 08-04-2004 17:07:14

Por supuesto que no espero que me escribais el codigo, de hecho me habeis dado mas información de la que imaginaba que iba a tener, ahora solo me queda mirarmelo.

Os agradezco vuestra ayuda.

Un saludo.

Adios.

Cita:

Empezado por guillotmarc
Hola.

A mi me parece que ya tienes todos los datos para solucionar el problema por ti mismo. Ya te hemos indicado que el problema de desbordamiento de pila se debe a un bucle infinto de disparos de eventos. Te hemos ayudado sobre que evento es más conveniente utilizar para cada caso. Y finalmente Jachguate te ha indicado como evitar los bucles infinitos en el caso de eventos que ejecutan código que forzosamente provoca que se vuelva a disparar el mismo evento.

Ahora lo tienes que solucionar tu, depurando el código para ver cual es la linea que provoca el desbordamiento, y poniendo puntos de ruptura en los eventos, para ver cual es el que se dispara infinitamente. Una vez detectado eso, tienes que solucionarlo, viendo si es que no estás realizando acciones necesarias, y protegiendo con un flag el evento que se dispara infiinitamente.

¿ Supongo que no estás esperando a que te pongamos nosotros el código de los eventos ?

Saludos.



La franja horaria es GMT +2. Ahora son las 00:51:48.

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