Avatar billede chrisx Nybegynder
19. april 2001 - 11:47 Der er 8 kommentarer og
1 løsning

Tids-forbrug

Findes der en component/kommando/procedure der kontinuerligt viser anvendt tid, á la uret på Windows bundlinie - men som starter fra 0 timer 0 min - placeret på Form1 canvas i et SDI program, og uanset det videre program forløb?
Avatar billede kim_friis Nybegynder
19. april 2001 - 11:54 #1
Ikke direkte men du kan når dit program starter op lave kalde funktionen GetTickCount, den returnere så hvor mange milisekunder der er gået siden at computeren blev startet. Og så laver du en onIdle eventhandler for din applikation hvor du blot hele tiden træker det oprindelige TickCount fra den nuværende og så regner det om til Timer og minutter hvis det er den måde du vil have det på.
Avatar billede dj Nybegynder
19. april 2001 - 11:59 #2
Gettickcount giver dig tid siden windows startede i millisekunder.

dvs. du kan benytte følgende:

Public
  oldtid: integer;
end;

Const  //Erklærer konstanter for udregning af klokslet
  cDay = 1000 * 60 * 60 * 24;
  cHour = 1000 * 60 * 60;
  cMin = 1000 * 60;
  cSec = 1000;
  Cdec = 10;

function Tform1.Duration(ms: integer):string;  //konverterer millisekunder til sekunder, minutter, timer osv.
var
    temp, temp2: string;
begin
    Fday:=0;
    Fhour:=0;
    Fmin:=0;
    Fsec:=0;
    FTotal:=0;
    temp:=\'\';
    FDay := ms div cDay;
    Ftotal:=ms mod cday;
    FHour := Ftotal div cHour;
    Ftotal:=Ftotal mod chour;
    FMin := Ftotal div cMin;
    Ftotal:=Ftotal mod cmin;
    FSec := Ftotal div cSec;
    Ftotal:=Ftotal mod cSec;
    Fdec:=Ftotal div cDec;
    temp2:=inttostr(Fmin);
    if length(temp2)=1 then temp2:=temp2;
    temp := temp + Temp2+\':\';
    temp2:=inttostr(FSec);
    if length(temp2)=1 then temp2:=\'0\'+temp2;
    temp := temp + temp2+\':\';
    temp2:=inttostr(FDec);
    if length(temp2)=1 then temp2:=\'0\'+temp2;
    result:=temp+temp2;
end;


(OnformCreate):
oldtid := Gettickcount

(OnTimer)
label1.caption:=duration(gettickcount-oldtime); //Indsætter den konverterede tid der er gået siden dit program startede op ind i en label.

Håber du kan bruge det

/_DJ_
Avatar billede delphi Nybegynder
19. april 2001 - 16:04 #3
Det virker på spørgsmålet som om der bare er brug for en ca. tid - ihvertflad nævnes kun timer og minutter.  I såfald er GetTickCount nok ikke lige hvad der søges.  En anden ting er, at den værdi som GetTickCount anvender internt i Windows er placeret som en 32 bit værdi.  Dette betyder at den på et eller andet tidspunkt vil løbe over (efter 49.7 dage), hvilket man i nogen sammenhænge skal tage hensyn til, fx. i applicationer til servere, der ofte kan stå tændte i sådanne tidsrum.

Delphi har er udemærket system til tidsstyring i TDateTime typen.  Nedenstående eksempel viser således hvorledes en label på en form opdateres med aktuel tid.  Application.onIdle benyttes til opdateringen, så der bruges så og sige ingen systemresourcer.

Bemærk i øvrigt at rutinen TimeTostr benytter den global variable LongTimeFormat til specifikation af hvorledes tiden skal angives.  Denne variabel sættes, når dit program startes, af Delphi Runtime til hvorledes brugeres har specificeret det i control panelet (reginal settings).  Du lader dermed brugeren selv bestemme hvorledes tiden skal skrives - men kan se\'følig overskrive, fx. med:

LongTimeFormat := \'hh:nn\';  // Viser kun timer og minutter.

type
  TForm1 = class(TForm)
    Label1: TLabel;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    FStartTime : TDateTime;

    Procedure IdleHandler(Sender: TObject; var Done: Boolean);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
  FStartTime := Now;
  Application.OnIdle := IdleHandler;
end;

procedure TForm1.IdleHandler(Sender: TObject; var Done: Boolean);
Var
  NowStr : String;
begin
  NowStr := TimeTostr(Now - FStartTime);
  If NowStr<>Label1.Caption Then
    Label1.Caption := NowStr;
end;


Har du brug for også at se dage programmet har kørt, så kan du ændre Nowstr tildelings linien ovenfor til fx.:

NowStr := IntToStr(Round(Int(Now - FStartTime))) + \' - \' + TimeTostr(Now - FStartTime);

Som det ses er der altså vundet flere ting ved at benyttet TDateTime typen:

- Delphis indbyggede converterings rutiner.
- Intet overløb over længere tid.
- Indbygget, simpel beregning fra sekunder til år.


Håber at DET kan bruges (sorry dj...ku\' ik la \'vær)

Peter

Avatar billede dj Nybegynder
19. april 2001 - 19:44 #4
heh, jaja det andet har jeg i det mindste selv beregnet mig frem til i tidernes morgen ;)
Avatar billede chrisx Nybegynder
20. april 2001 - 13:02 #5
Du har ret - det er dit forslag jeg kan bruge, men proceduren \'onIdle\' giver problemer:

1:
Kan det være rigtigt at den skal angives i \'private\' som du skriver?
Der fejlmeldes: unsatisfied forward or external  declaration\'.

2:
Hvordan oprettes samme procedure under \'implemation\' ?
Der fejlmeldes: \'undeclared identifier\'.

Det er vel mit begrænsede kendskab til Delphi som giver mig problemer men hvis du vil angive - \'klippet ud i pap\' hvordan problemet løses, forhøjer jeg med 30 point.
Avatar billede delphi Nybegynder
20. april 2001 - 13:28 #6
Du mener vel proceduren \'IdleHandler\' og ikke \'onIdle\'?  (onIdle er en event pointer defineret i TApplication classen)

1: Ja, det er smartest at placere den under Private.  Der burde ikke umiddelbart være andre class\'er/programdele i dit program, der har brug for at kalde IdleHandler i din form.  MEN hvis du vil kalde den et andet sted fra, så er du velkommen til at placere den under fx. Public delen af din class - herved bliver den synlig for andre class\'er.

Du skriver: \"Der fejlmeldes: unsatisfied forward or external  declaration\'\"

Prøv lige at checkke din kode igen.  Det virker som om du har skrevet forkert.  Det virker fint i den here ende.


2: Med spørgsmålet \"Hvordan oprettes samme procedure under \'implemation\' ?\", går jeg ud fra at du mener som en standard procedure - i modsætning til en metode defineret under en class.

Nej, dette kan ikke lade sig gøre.  Grunden er, at TApplication.onIdle er defineret som en pointer til en object method.

Det du i stedet kan gøre er følgende:

1: Flyt IdleHandler metoden ud af TForm1 class\'en som en standard procedure, der placeres under Implementation linien.  Fjern de parametre der er på proceduren - de benyttes ikke.

2: Fjern følgende linie fra din forms create del:
  Application.OnIdle := IdleHandler;


2: Alle fields fra TForm1, fx. FStartTime, der benyttes i IdleHandler skal flyttes til class\'ens Public eller Protected del, således at de kan ses fra IdleHandler.  Desuden skal alle referencer til disse fields \'qualifies\', dvs. i stedet for at skrive:

  NowStr := TimeTostr(Now - FStartTime);

skal du skrive

  NowStr := TimeTostr(Now - Form1.FStartTime);  // Bemærk Form1.

3: Placer en timer, fra Delphis System palette, på din form.  Sæt timerens Interval property til noget passende.  Jo lavere værdi, jo oftere kaldes dens onTimer method og jo mere belastes CPU\'en.  Hvis du fx. ønsker en opdatering hvert sekund, så sæt propertien til 1000 (mSek\'s).  Hvis en opdatering hvert minut er fint, så sæt værdien til 60000.

4: Dobbelt click på Timeren (For at oprette en onTimer method).  skriv følgende linie i denne methods body:

  IdleHandler;


Done. 

Det færdige program ser nu således ud:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls;

type
  TForm1 = class(TForm)
    Label1: TLabel;
    Timer1: TTimer;
    procedure FormCreate(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    { Private declarations }
  Protected
    FStartTime : TDateTime;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

procedure IdleHandler;
Var
  NowStr : String;
begin
  NowStr := TimeTostr(Now - Form1.FStartTime);
  If NowStr<>Form1.Label1.Caption Then
    Form1.Label1.Caption := NowStr;
end;


{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
  FStartTime := Now;
  IdleHandler;        // Update label text.
end;


procedure TForm1.Timer1Timer(Sender: TObject);
begin
  IdleHandler;
end;

end.

Peter
Avatar billede delphi Nybegynder
20. april 2001 - 13:31 #7
Ok, spørgsmålet er afsluttet, så du har nok fundet ud af det.

Bemærk, at jeg til hver en tid vil vælge den første metode.  Det er ikke smart at anvende timere hvis det kan undgås.  De er en begrænset resource under Windows.

Peter
Avatar billede chrisx Nybegynder
20. april 2001 - 18:16 #8
Hej Peter Delphi...

Jov, du har ret... der var en \'lus\' i koden, og nu virker den 1.ste version - label-componenten viser tiden ved start med 00.00.
Imidlertid skifter tiden ikke før tastatur eller mus aktiveres - altså ikke kontinuerlig display ved stilstand (idle), men omvendt (når aktiv) ?

Hvorfor...

Tak iøvrigt for dine hurtige svar og jeg håber du orker at fix\'e det sidste problem...

Chris
Avatar billede delphi Nybegynder
23. april 2001 - 08:37 #9
Jeg har også bemærket, at Idle eventen kun kaldes ca. hvert tiende sekund, hvis mus/tastatur ikke påvirkes.  Egentligt lidt underligt, idet der netop i denne situation burde være masser af Idle time. 

Hvis mere nøjagtig tidsangivelse er påkrævet, så må du anvende en Timer til opdateringen.

Peter
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