Delphi 2010 a StopWatch

vložil Radek Červinka 1. března 2010 23:49

Než popíši další z nových možností u Delphi 2010, tak aby to majitelům starších Delphi nebylo líto odkáži je na podobnou opensource implementaci třídy TStopWatch - ale přijdete o několik zajímavých novinek. Tak ale zpět k současnosti - zároveň se bude jednat o pěkné jazykové konstrukce ohledně záznamu, včetně operátorů třídy - třeba Vás to bude inspirovat, mně osobně se to zamlouvá.

Delphi 2010 obsahuje unit Diagnostics.pas, který momentálně obsahuje jedinou třídu resp. rozšířený record s názvem TStopWatch, který mimochodem obsahuje pěkné použití rozšířeného recordu a class operatory.

type
  TStopwatch = record
  strict private const TicksPerMillisecond: Int64 = $2710;
  strict private const TicksPerSecond: Int64 = $989680;
  strict private class var TickFrequency: Double;
  strict private
    FElapsed: Int64;
    FRunning: Boolean;
    FStartTimeStamp: Int64;
    function GetElapsed: TTimeSpan;
    function GetElapsedDateTimeTicks: Int64;
    function GetElapsedMilliseconds: Int64;
    function GetElapsedTicks: Int64;
    class procedure InitStopwatchType; static;
  public
    class function Create: TStopwatch; static;
    class function GetTimeStamp: Int64; static;
    procedure Reset;
    procedure Start;
    class function StartNew: TStopwatch; static;
    procedure Stop;
    property Elapsed: TTimeSpan read GetElapsed;
    property ElapsedMilliseconds: Int64 read GetElapsedMilliseconds;
    property ElapsedTicks: Int64 read GetElapsedTicks;
    property IsRunning: Boolean read FRunning;
  public class var Frequency: Int64;
  public class var IsHighResolution: Boolean;
  end;

Základem je velmi šikovný nový typ TTimeSpan definovaný v TimeSpan.pas.

type
  TTimeSpan = record
// vynechány privátní a ne public pole
  public const
    TicksPerMillisecond = 10000;
    TicksPerSecond = 1000 * Int64(TicksPerMillisecond);
    TicksPerMinute = 60 * Int64(TicksPerSecond);
    TicksPerHour = 60 * Int64(TicksPerMinute);
    TicksPerDay = 24 * TIcksPerHour;
  public
    constructor Create(ATicks: Int64); overload;
    constructor Create(Hours, Minutes, Seconds: Integer); overload;
    constructor Create(Days, Hours, Minutes, Seconds: Integer); overload;
    constructor Create(Days, Hours, Minutes, Seconds, Milliseconds: Integer); overload;

    function Add(const TS: TTimeSpan): TTimeSpan; overload;
    function Duration: TTimeSpan;
    function Negate: TTimeSpan;
    function Subtract(const TS: TTimeSpan): TTimeSpan; overload;

    class function FromDays(Value: Double): TTimeSpan; static;
    class function FromHours(Value: Double): TTimeSpan; static;
    class function FromMinutes(Value: Double): TTimeSpan; static;
    class function FromSeconds(Value: Double): TTimeSpan; static;
    class function FromMilliseconds(Value: Double): TTimeSpan; static;
    class function FromTicks(Value: Int64): TTimeSpan; static;

    class function Parse(const S: string): TTimeSpan; static;
    class function TryParse(const S: string; out Value: TTimeSpan): Boolean; static;

    // class operatory
    class operator Add(const Left, Right: TTimeSpan): TTimeSpan;
    class operator Subtract(const Left, Right: TTimeSpan): TTimeSpan;
    class operator Equal(const Left, Right: TTimeSpan): Boolean;
    class operator NotEqual(const Left, Right: TTimeSpan): Boolean;
    class operator GreaterThan(const Left, Right: TTimeSpan): Boolean;
    class operator GreaterThanOrEqual(const Left, Right: TTimeSpan): Boolean;
    class operator LessThan(const Left, Right: TTimeSpan): Boolean;
    class operator LessThanOrEqual(const Left, Right: TTimeSpan): Boolean;
    class operator Negative(const Value: TTimeSpan): TTimeSpan;
    class operator Positive(const Value: TTimeSpan): TTimeSpan;
//!implicitni konverze na string
    class operator Implicit(const Value: TTimeSpan): string;  
    class operator Explicit(const Value: TTimeSpan): string;

    property Ticks: Int64 read FTicks;
    property Days: Integer read GetDays;
    property Hours: Integer read GetHours;
    property Minutes: Integer read GetMinutes;
    property Seconds: Integer read GetSeconds;
    property Milliseconds: Integer read GetMilliseconds;
    property TotalDays: Double read GetTotalDays;
    property TotalHours: Double read GetTotalHours;
    property TotalMinutes: Double read GetTotalMinutes;
    property TotalSeconds: Double read GetTotalSeconds;
    property TotalMilliseconds: Double read GetTotalMilliseconds;

    class property MinValue: TTimeSpan read FMinValue;
    class property MaxValue: TTimeSpan read FMaxValue;
    class property Zero: TTimeSpan read FZero;
  end;

Ale zpět k TStopWatch. Vytvoříme novou aplikaci, na formulář dáme tlačítko a TListBox. U tlačítka napíšeme uvedenou obsluhu.

implementation
uses
  Diagnostics;
{$R *.dfm}

procedure TForm1.btn1Click(Sender: TObject);
var
  sw:TStopWatch;
  xIndex: Integer;
begin
  sw.Reset;
  sw.Start;
  lst1.Clear;
  for xIndex := 0 to 1000 - 1 do
    lst1.Items.Add(IntToStr(Random(1000000)));
  sw.Stop;
  ShowMessage(sw.Elapsed); // poznámka níže
end;

Na řádku 17 se využije právě implicitní konverze na string, viz. class operator Implicit. Sčítání, odčítání atd. je realizováno dalšími operátory.

Ještě bych upozornil, že třída použije QueryPerformanceCounter pokud je volání dostupné, jinak použije klasicky GetTickCount (viz. IsHighResolution).

Tagy: ,

Novinky

Komentáře

22.4.2013 12:38:36 #

Daniel Andraščík

  Jeden cas som sa tiez hral z funkciami QueryPerformanceCounter a QueryPerformanceFrequency. Nepotreboval som vysoke rozlisenie, skor som potreboval 64bitovu funkciu GetTickCount na starsich windowsoch. Fungovalo mi to, ale uz si presne nepamatam ako to presne bolo ale narazil som niekde na forach ze tieto funkcie QueryPerformanceCounter a QueryPerformanceFrequency mali nejaky problem pri nejakych druhoch chipsetov, alebo take nieco. Neviem nakolko to bola pravdiva informacia, sam som s tymito funkciami problem nemal.
  Ale vzhladom na to ze programujem priemyselne scada aplikacie, ktore bezia nezriedka cele mesiace, tak som to neriskoval a vytvoril som si GetTickCount64 pomocou trosku skaredeho riesenia s thread var a clasickou funkciou GetTickCount32 a sledovanim "pretecenia" 32bitov. Este stastie ze novsie windowsi uz maju nativnu GetTickCount64 funkciu.

Daniel Andraščík

22.4.2013 12:48:00 #

Daniel Andraščík

Viem ze moj predchadzajuci komentar je trosku mimo zameru tohto clanku. Pouzitie rozsirenych rekorodov TStopWatch a TTimeSpan je tu fakt zobrazene prikladne. Hned ma vsak zaujimalo akym sposobom rekordy odmeriavaju cas. Zvolena funkcia QueryPerformanceCounter zrejme v dnesnych dobach uz ziadny problem nepredstavuje (a mozno problem nebol ani v minulosti). Ale mozno ze stale ano. Staci dat do googlu "queryperformancecounter problems".

Daniel Andraščík

Komentování ukončeno

Naše nabídka

MVP
Ing. Radek Červinka - Embarcadero MVP
profil na linkedin, Twitter:@delphicz

Nabízím placené poradenství a konzultace v oblasti programování a vývoje SW.
Dále nabízíme i vývoj speciálního software na zakázku.

Neváhejte nás kontaktovat (i ohledně reklamy).

love Delphi

O Delphi.cz

Delphi je moderní RAD nástroj podporující tvorbu nativních aplikací pro platformu Win32, Win64, Mac OSX, Linux a na iPhone a Android.

Delphi.cz je nezávislý portál pro uživatele Delphi. Portál není koncipován pro úplné začátečníky, i když i ti se zde nebudou nudit, ale spíše na programátory, kteří již něco znají a chtějí své znalosti dále rozvíjet a sledovat novinky.

Poslední komentáře

Comment RSS

Dle měsíců