Avatar billede kokoko Nybegynder
19. november 1999 - 19:38 Der er 13 kommentarer og
1 løsning

Timer( "Antal Sec" , "Do Procedure" );

Hej!

Jeg er ved at lave et program hvor jeg skal bruge uendelig mange timere, og vil derfor hvis det er muligt gerne have lavet en procedure som ser cirka sådan ud:

Timer( "Antal Sec" , "Do Procedure" );

Den skal altså kunne kører en procedure efter et bestemt antal sekunder.

Nogen der kan hjælpe?
Avatar billede dj Nybegynder
21. november 1999 - 15:02 #1
Hej Kokoko

Jeg kom til at tænke på efter at jeg havde snakket med dig i går at man muligvis kan lave det som en procedure hvor den creater en Ttimer noget med:

procedure tid(msec: integer);
var
tid1: Ttimer;
begin
tid1:=Ttimer.create;
tid1.interval := msec;
tid1.onTimer := (den procedure du vil udføre, husk på at de parametre proceduren skal have skal være ens med Timerens jeg mener det bare er (sender: Tobject); men jeg er ikke helt sikker)
end;

Jeg vil håbe at dette kan bruges, ps jeg har ikke lige afprøvet koden ovenover, så du må selv lige rette eventuelle fejl jeg måtte have lavet :)

Mvh. _DJ_
Avatar billede delphi Nybegynder
25. november 1999 - 09:01 #2
Lige en ting: Brugen af TTimer kræver en Windows timer - Dem er der ikke mange af og de er resource krævende.

Det vil derfor nok være temmelig smart at frigive dem igen efter brug (dvs. i slutningen af din onTimer procedure)

NiP/Delphi
Avatar billede delphi Nybegynder
25. november 1999 - 09:58 #3
En alternativ løsning der kun kræver brugen af en enkelt timer samt en TList.

Listen indeholder en række objecter med følgende oplysninger for hver action:
- Hvad der skal gøres.
- Tid for hvornår noget skal gøres (evt. som antal sek fremme i tiden).
- Tid for objectets indsættelse i listen.

Du laver så en alm. procedure, parametreret som du skriver i dit spørgsmål, som opretter et object og indsætter det i listen.

I din Timers onTimer procedure, der fx. passende kan køres ~hver halve eller hele sekund, afhængigt af behovet for præsision, løber du listen igennem og finder de objecter der skal aktiveres.  Aktivering indebærer også at du fjerner objectet fra listen.

Når jeg skal bruge nogen form for tidsstyring, vælger jeg iøvrigt oftest at benytte GetTickCount Win API proceduren.  Fx. i dette lille delay:

Const
  MaxDelay = 2*1000; // 2 sek = 2000 mSek
Var
  Start : LongInt;

  .
  .
  Start := GetTickCount;
  Repeat
    Foo := FooBar;
    // Indsæt evt. Application.ProcessMessages her.
  Until Foo Or (GetTickCount-Start > MaxDelay);
  .
  .

Stort set den samme fremgangs måde kan benyttes i ovenstående eksempel:

Type
  TListObject = Object
    InsetTime : LongInt;
    NoOfSec  : LongInt;
    Action    : Some sort of action type description
  End;

// Gennemløb listen for at finde objecter der skal activeres.
Procedure Timer1.OnTimer...
Var
  CurTime : LongInt;
  Index  : Cardinal;
  TempObj : TListObject;  // Temporary helper variabel
Begin
  .
  .
  CurTime := GetTickCount;
  For Index := 0 To ProcList.Count-1 Do
    Begin
      TempObj := (ProcList.Objects[Index]) As TListObject
      If ((CurTime - TempObj.IndsetTime) Div 1000) > TempObj.NoOfSec Then
        Begin
          ProcList.Objects[Index].Delete;
          FireAction(TempObj.Action);
        End;
    End;
  .
  .
End;

Fidusen ved denne metode er, at du ikke skal tage hensyn til om du ruller hen over midnat, månedsskifter osv.  GetTickCount er valid i 49.7 døgn, hvilket normalt er nok i de fleste applicationer, hvorefter den dog resætter til zero.

Hvis man nu forestiller sig, at det er en meget tung opgave du har i tankerne, fx. at din liste vil komme til at indeholde et hav af actions, hvoraf nogle måske først skal startes langt ude i fremtiden, så kan det måske være lidt krævende at gå igennem hele listen hvert halve eller hele sekund.  (Men så skal der dæleme også være mange objecter i listen og det skal være en sløv maskine!)
Løsningen kan i såfald være at have to (eller flere lister). En liste kan så indeholder alle de actions der ligger længere ude i fremtiden end fx. 2 minutter.  Denne liste gennemgåes af en timer procedure 1 gang pr. minut og flytter de actions der snart skal startes over i den primære liste.


NB: Jeg har bare lavet ovenstående lige ud af hovedet, så der er ingen forbehold for noget som helst - heller ikke stavefejl eller at jeg husker procedurenes navne korrekt :)

NiP/Delphi

Avatar billede kokoko Nybegynder
25. november 1999 - 13:33 #4
Delphi: Tak for dit svar... det er en kanon god ide! Så pointene er faktisk dine!

Jeg har dog et problem:

  TListObject = class(Tcomponent)
  Public
    InsetTime: LongInt;
    NoOfSec: LongInt;
    Constructor Create(AOwner:TComponent);override;
    Destructor Destroy;override;
  End;


procedure TForm1.Timer1Timer(Sender: TObject);
Var
  CurTime: LongInt;
  Index: Integer;
  TempObj: TListObject;
begin
  CurTime := GetTickCount;
  If ProcList.Count > 0 Then
    For Index := 0 to ProcList.Count-1 Do
      Begin
        TempObj := ProcList.Items[Index] As TListObject  // Fejl: "Operator not applicable to this operand type"
        If ((CurTime - TempObj.InsetTime) Div 1000) > TempObj.NoOfSec Then
          Begin
            ProcList.Delete(Index);
            osv. osv.
          End;
      End;
end;


Kan du sige mig hvad jeg gør forkert?

Mvh,

Kokoko
Avatar billede kokoko Nybegynder
25. november 1999 - 13:36 #5
En anden ting... Hvordan kan jeg få den til at udføre en procedure? Hvilken type skal action være i nedstående for at man kan sætte den til en procedure:

Type
  TListObject = Object
    InsetTime : LongInt;
    NoOfSec  : LongInt;
    Action    : Some sort of action type description
  End;

Mvh,

Kokoko
Avatar billede delphi Nybegynder
25. november 1999 - 14:33 #6
>>Kan du sige mig hvad jeg gør forkert?

Bagatel: "If ProcList.Count > 0 Then" linien er unødvendig.

Linien: "TempObj := ProcList.Items[Index] As TListObject" skal hedde "TempObj := ProcList.Objects[Index] As TListObject;"

ProcList skal være erklæret som en TStringList

>>Hvilken type skal action være i nedstående for at man kan sætte den til en procedure:

Fx således:

Type
  TSomeAction = Procedure(Param : Integer);

Type
  List....
    Action : TSomeAction

NiP/Delphi

   


Avatar billede delphi Nybegynder
25. november 1999 - 14:34 #7
Her er der et lille demo program, der vist gør det du efter spørger.
Selve programmet har en Timer, en spinedit og en 2-3 knapper - ikke noget specielt.
Du kan se hele dynen på: http://home1.inet.tele.dk/nip/temp/actionlist.zip (~180 kBytes)

Type
  ProcedureAction = Procedure;

  TListObject = class
    Public
      InsetTime: LongInt;
      NoOfSec  : LongInt;
      Action  : ProcedureAction;
      Constructor Create(DelayTime : LongInt; aAction : ProcedureAction);
    End;

{ TListObject }
constructor TListObject.Create(DelayTime: Integer; aAction: ProcedureAction);
begin
  InsetTime:= GetTickCount;
  NoOfSec  := DelayTime;
  Action  := aAction;
end;


// Bemærk: Hvis Foo og Bar procedurene er meget tidskrævende, bør de
// Indeholde et eller flere Application.ProcessMessages kald for ikke at
// blokere for Windows eventstyringen - blandt andet også timeren der
// styre gennemløbet af listen.
// Det har selvfølgelig den effekt, at man risikere at procedurene kaldes
// flere gang "parallelt".  De skal derfor være lavet, således at de
// ikke ubeskyttede globale variable (se: Multi programering, semaphores,
// Atoms etc...)
Procedure Foo;
Begin
  ShowMessage('Foo Action fired');
End;

Procedure Bar;
Begin
  ShowMessage('Bar Action fired');
End;

{ TForm }
procedure TForm1.FormCreate(Sender: TObject);
begin
  // ProcList (ProcedureList eller ActionList) indeholder alle de
  // actions der skal affyres på et eller andet tidspunkt.
  ProcList := TStringList.Create;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
Var
  CurTime: LongInt;
  Index: Integer;
  TempObj: TListObject;
begin
  CurTime := GetTickCount;
  For Index := 0 to ProcList.Count-1 Do
    Begin
      TempObj := (ProcList.Objects[Index]) As TListObject;

      // Time to do the ding-thing?
      If ((CurTime - TempObj.InsetTime) Div 1000) > TempObj.NoOfSec Then
        Begin
          // Remove the action from the list
          ProcList.Delete(Index);

          // Trigger the action
          If Assigned(TempObj.Action) Then
            TempObj.Action;
        End;
    End;
end;

procedure TForm1.buAddFooClick(Sender: TObject);
begin
  ProcList.AddObject('', TListObject.Create(seDelayTime.Value, Foo));
end;

procedure TForm1.buAddBarClick(Sender: TObject);
begin
  ProcList.AddObject('', TListObject.Create(seDelayTime.Value, Bar));
end;

procedure TForm1.buCloseClick(Sender: TObject);
begin
  Close;
end;

end.


NiP/Delphi
Avatar billede gusse Nybegynder
25. november 1999 - 15:26 #8
hvad med en tråd TThread ?, det kunne nok gøre det. Det skal selvfølig lidt ekstra til. Man jo heller ikke få alt foræret :)
Avatar billede delphi Nybegynder
25. november 1999 - 15:31 #9
Jeg skammer mig lidt over det men: Jeg har endnu aldrig rørt en tråd i Delphi....

NiP/Delphi
Avatar billede gusse Nybegynder
25. november 1999 - 15:39 #10
Kig på TThread i hjælpen. Men pas på. det er ikke legetøj. Vi har udviklet en object, der kan klare netop (noget ligende) det du søger. Desvære kan jeg ikke publicere koden...
Avatar billede delphi Nybegynder
25. november 1999 - 15:44 #11
Jeg ved hvordan tråde virker, idet jeg har benyttet dem i andre sprog.  Blandt andet lavede jeg engang noget multiprogramering med threads i Borland Pascal til en data opsamlings opgave.

Der er iøvrigt også noget god info i nogle af mine Delphi bøger - så hudt jeg visker har Marco Cantü også et afsnit om emnet (ellers var det en anden bog).

Jeg har bare aldrig haft brug for muligheden i mine Delphi applicationer.

Det jeg skriver her er da vist iøvrigt ret urelevant....

NiP/Delphi
Avatar billede gusse Nybegynder
25. november 1999 - 15:56 #12
> Det jeg skriver her er da vist iøvrigt ret urelevant....

øhh næ egentlig ikke.  det er da meget rart at vide :)

Nå men ikke mere (vrøvl)...er denne tråd ikke lukket.
Avatar billede kokoko Nybegynder
25. november 1999 - 19:39 #13
Delphi: Jeg har lige prøvet det du sagde... og jeg kan fint få det til at virke med at den kører en procedure efter en vis tid... men jeg kan ikke få den til at bruge parametre.

Type
  TSomeAction = Procedure(Param : Integer);

Hvis jeg sætter action til TSomeAction, så kan jeg jo kun sætte parametrene til en integer værdi, ik?

Mvh,

Kokoko




Avatar billede delphi Nybegynder
26. november 1999 - 08:53 #14
Øhh.. Jo, med den dekleration kan du kun sætte parameteren til en integer værdi.... 

Jeg antager, at du er klar over at en ændring af TSomeAction deklerationen medføre, at du skal ændre Foo og Bar procedurene til også at have de samme parameter typer (ellers vil compileren ikke være med).

I buAddxxxxClick procedurene skal du også huske at have parametrene med, når du indsætter objected i listen, således at procedurene til sin tid får dem overført.

Har du brug for flere forskellige procedure typer, dvs. forskellige antal og/eller typer parametre, så bliver det lige lidt sværere.  Tænke....
Du kan vel bruge:
  - En pointer til en parameter record (Alá Win API), som du Type-caster.
  - Brug Variants
  - Type løse (Untyped) parametre
  - Overloading
  - En liste eller container object, der indeholder nødvendige parametre/metoder.

Der er sikkert andre metoder, men det var lige hvad der faldt mig ind.

Delphi
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester