Friday, December 22, 2006


SecurityCopy

Permet automatitzar còpies de seguretat de fitxers.

unit SecurityCopy;

interface

uses Windows, Classes, SysUtils, Forms, IniFiles, FileCtrl,
DsgnIntf, ShellAPI, ExtCtrls, Consts, TtLogFile, TtDBFilePathEd;

type
  TDebugOptions = class(TPersistent)
    private
      FActive: boolean;
      FFileName: string;
      FSaveDate: boolean;
      FSaveHour: boolean;
    public
      constructor Create;
    published
      property Active: boolean read FActive write FActive;
      property FileName: string read FFileName write FFileName;
      property SaveDate: boolean read FSaveDate write FSaveDate;
      property SaveHour: boolean read FSaveHour write FSaveHour;
  end;

type
  TSecurityCopy = class(TComponent)
    private
      FTimer: TTimer;
      FActive: boolean;
      FOverwrite: boolean;
      FOnlyModified: boolean;
      FSourcePath: string;
      FTargetPath: string;
      FExtension: string;
      FInterval: integer; //in seconds
      FLogFile: TTtLogFile;
      FDebugOptions: TDebugOptions;
      FIncludeSubfolders: boolean;
      procedure SetActive(AActive: boolean);
      procedure SetInterval(AInterval: integer);
      procedure SetDebugOptions(ADebugOptions: TDebugOptions);
      procedure OnTimer(Sender: TObject); virtual;
      procedure DoSecurityCopy(Source: string; Target: string);
    public
      constructor Create(AOwner:TComponent); override;
      destructor Destroy; override;
      procedure Loaded; override;
      procedure ExecuteSecurityCopy;
    published
      property Active: boolean read FActive write SetActive;
      property Overwrite: boolean read FOverwrite write FOverwrite;
      property OnlyModified: boolean read FOnlyModified write FOnlyModified;
      property Interval: integer read FInterval write SetInterval;
      property SourcePath: string read FSourcePath write FSourcePath;
      property TargetPath: string read FTargetPath write FTargetPath;
      property Extension: string read FExtension write FExtension;
      property DebugOptions: TDebugOptions read FDebugOptions write SetDebugOptions;
      property IncludeSubfolders: boolean read FIncludeSubfolders write FIncludeSubfolders;
  end;
type
  TSecurityCopy = class(TSecurityCopy);

procedure Register;

implementation

constructor TDebugOptions.Create;
begin
  FActive := False;
  FSaveDate := False;
  FSaveHour := False;
  FFileName := 'noname.log';
end;

constructor TSecurityCopy.Create(AOwner:TComponent);
begin
  FTimer := TTimer.Create(Self);
  FTimer.Enabled := False;
  FInterval := 60000;
  FActive := False;
  FOverwrite := True;
  FExtension := '*.*';
  FOnlyModified := True;
  FIncludeSubfolders := False;
  FTimer.OnTimer := OnTimer;
  FDebugOptions := TDebugOptions.Create;
  FLogFile := TTtLogFile.Create(Self);
  inherited Create(AOwner);
end;

procedure TSecurityCopy.Loaded;
begin
  SetDebugOptions(FDebugOptions);
  inherited Loaded;
end;

procedure TSecurityCopy.SetActive(AActive: boolean);
begin
  FActive := AActive;
  FTimer.Enabled := AActive;
  FTimer.Interval := FInterval;
end;

procedure TSecurityCopy.SetInterval(AInterval: integer);
begin
  FInterval := AInterval;
  FTimer.Interval := AInterval;
end;

procedure TSecurityCopy.SetDebugOptions(ADebugOptions: TDebugOptions);
begin
  FDebugOptions.Active := ADebugOptions.Active;
  FDebugOptions.SaveDate := ADebugOptions.SaveDate;
  FDebugOptions.SaveHour := ADebugOptions.SaveHour;
  FDebugOptions.FileName := ADebugOptions.FileName;
  FLogFile.SaveDate := FDebugOptions.SaveDate;
  FLogFile.SaveHour := FDebugOptions.SaveHour;
  FLogFile.FileName := FDebugOptions.FileName;
  FLogFile.Active := FDebugOptions.Active;
end;

function FileTimeToDateTime(FileTime: TFileTime): TDateTime;
var
  SysTime: TSystemTime;
begin
  if not FileTimeToSystemTime(FileTime,SysTime) then
    raise EConvertError.CreateFmt('FileTime to SystemTime failed. Error code %d',[GetLastError]);
  with SysTime do
  begin
    Result := EncodeDate(wYear,wMonth,wDay) + EncodeTime(wHour,wMinute,wSecond,wMilliseconds);
  end;
end;

procedure TSecurityCopy.DoSecurityCopy(Source: string; Target: string);
var
  SearchRec,SRDest: TSearchRec;
  flDate,lastCopyDate: TDateTime;
begin
  //if target directory no exists creates it
  if not DirectoryExists(Target) then
    ForceDirectories(Target);

  if (FindFirst(Source+'\'+FExtension,faAnyFile,SearchRec)=0) then
  begin
    flDate := FileTimeToDateTime(SearchRec.FindData.ftLastWriteTime);
    try
      if (FindFirst(Target+'\'+SearchRec.Name,faArchive,SRDest)=0) then
      begin
        lastCopyDate := FileTimeToDateTime(SRDest.FindData.ftLastWriteTime);
        if (lastCopyDate<flDate) or (FOnlyModified=False) then
        begin
          CopyFile(PChar(Source+'\'+SearchRec.Name),PChar(Target+'\'+SearchRec.Name),not FOverwrite);
          FLogFile.SaveToFile(SearchRec.Name+' copied');
        end;
      end
      else
      begin
        CopyFile(PChar(Source+'\'+SearchRec.Name),PChar(Target+'\'+SearchRec.Name),not FOverwrite);
        FLogFile.SaveToFile(SearchRec.Name+' copied');
      end;
      if FIncludeSubFolders then
      begin
        if (shortint(SearchRec.Attr)=faDirectory) and (SearchRec.Name<>'.') and (SearchRec.Name<>'..') then
        begin
          DoSecurityCopy(Source+'\'+SearchRec.Name,Target+'\'+SearchRec.Name);
        end;
      end;
    except
      FLogFile.SaveToFile(SearchRec.Name+' failed to copy');
    end;
  while (FindNext(SearchRec)=0) do
  begin
    flDate := FileTimeToDateTime(SearchRec.FindData.ftLastWriteTime);
    try
      if (FindFirst(Target+'\'+SearchRec.Name,faArchive,SRDest)=0) then
      begin
        lastCopyDate := FileTimeToDateTime(SRDest.FindData.ftLastWriteTime);
        if (lastCopyDate<flDate) or (FOnlyModified=False) then
        begin
          CopyFile(PChar(Source+'\'+SearchRec.Name),PChar(Target+'\'+SearchRec.Name),not FOverwrite);
          FLogFile.SaveToFile(SearchRec.Name+' copied');
        end;
      end
      else
      begin
        CopyFile(PChar(Source+'\'+SearchRec.Name),PChar(Target+'\'+SearchRec.Name),not FOverwrite);
        FLogFile.SaveToFile(SearchRec.Name+' copied');
      end;
      if FIncludeSubFolders then
      begin
        if (shortint(SearchRec.Attr)=faDirectory) and (SearchRec.Name<>'.') and (SearchRec.Name<>'..') then
        begin
          DoSecurityCopy(Source+'\'+SearchRec.Name,Target+'\'+SearchRec.Name);
        end;
      end;
    except
      FLogFile.SaveToFile(SearchRec.Name+' failed to copy');
    end;
  end;
  FindClose(SearchRec);
  end;
end;

procedure TSecurityCopy.ExecuteSecurityCopy;
begin
  DoSecurityCopy(FSourcePath,FTargetPath);
end;

procedure TSecurityCopy.OnTimer(Sender: TObject);
begin

  if ComponentState=[csDesigning] then
    Exit;

  FTimer.Enabled := False;
  DoSecurityCopy(FSourcePath,FTargetPath);
  FTimer.Enabled := True;
end;

destructor TSecurityCopy.Destroy;
begin
  FLogFile.Free;
  FTimer.Free;
  FDebugOptions.Create;
  inherited Destroy;
end;

procedure Register;
begin
  RegisterComponents('Components Delphi', [TSecurityCopy]);
end;

end.


Les propietas SourcePath i TargetPath determinen els directoris origen i final de la còpia. Podem, mitjançant la propietat Extension filtrar el tipus de fitxers a copiar. La propietat Active ens permet desactivar la còpia. Interval ens indica cada quan volem fer còpia, en milisegons. Amb OnlyhModified, només copiem si el fitxer s'ha modificat des de l'última còpia. Overwrite indica si reemplaçar el fitxer destí si ja existeix. IncludeSubfolders fa còpia recursiva de directoris continguts en SourcePath. Finalment, amb DebugOptions podem fer que es generi un arxiu que registri les operacions de còpia. A part d'executar-se la còpia cada vegada que es compleixi el temps que hem triat a Interval, la podem forçar amb el mètode ExecuteSecurityCopy.

Thursday, December 21, 2006


IntEdit

Aquest component és una caixa d'edicíó que només permet l'entrada de nombre sencers.

unit IntEdit;

interface

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

type TIntEditEd = class(TDefaultEditor)
  procedure ExecuteVerb(Index: integer); override;
  function GetVerb(Index: integer): string; override;
  function GetVerbCount: integer; override;
  end;

type
  TIntEdit = class(TCustomEdit)
  private
    { Private declarations }
    FAlignment: TAlignment;
    FValue: LongInt;
    FMaxValue: LongInt;
    lDelPressed: boolean;
    procedure SetAlignment(AAlignment: TAlignment);
    function GetFieldValue: LongInt;
    procedure SetFieldValue(iNewVal: LongInt);
    function GetAsInteger: LongInt;
    procedure SetAsInteger(lnVal: LongInt);
    function GetAsString: string;
    procedure SetAsString(strVal: string);
    procedure SetMaxValue(Value: LongInt);
    procedure CMEnter(var Message: TCMEnter); message CM_ENTER;
  protected
    { Protected declarations }
    procedure CreateParams(var Params: TCreateParams); override;
    procedure KeyPress(var Key: Char); override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure KeyUp(var Key: Word; Shift: TShiftState); override;
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
    property AsInteger: LongInt read GetAsInteger write SetAsInteger;
    property AsString: string read GetAsString write SetAsString;
  published
    { Published declarations }
    property Value: LongInt read GetFieldValue write SetFieldValue;
    property MaxValue: LongInt read FMaxValue write SetMaxValue;
    property Alignment: TAlignment read FAlignment write SetAlignment default taRightJustify;
    property Anchors;
    property AutoSelect;
    property AutoSize default True;
    property BorderStyle;
    property Color;
    property Ctl3D;
    property DragCursor;
    property DragMode;
    property Enabled;
    property Font;
    property HideSelection;
    property ParentColor;
    property ParentCtl3D;
    property ParentFont;
    property ParentShowHint;
    property PopupMenu;
    property ReadOnly;
    property ShowHint;
    property TabOrder;
    property Visible;
    (* General events properties *)
    property OnChange;
    property OnClick;
    property OnDblClick;
    property OnDragDrop;
    property OnDragOver;
    property OnEndDrag;
    property OnEnter;
    property OnExit;
    property OnKeyDown;
    property OnKeyPress;
    property OnKeyUp;
    property OnMouseDown;
    property OnMouseMove;
    property OnMouseUp;
  end;
type
  TIntEdit = class(TIntEdit);

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Components Delphi', [TIntEdit]);
end;

constructor TIntEdit.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FAlignment := taRightJustify;
  FValue := 0;
  Text := IntToStr(FValue);
  FMaxValue := 2147483647;
  lDelPressed := False;
end;

procedure TIntEdit.SetAlignment(AAlignment: TAlignment);
begin
  if FAlignment <> AAlignment then
  begin
    FAlignment := AAlignment;
    if not (csDesigning in ComponentState) then
      RecreateWnd;
    if Focused then
      SelectAll;
  end;
end;

function TIntEdit.GetFieldValue: LongInt;
begin
  Result := FValue;
end;

procedure TIntEdit.SetFieldValue(iNewVal: LongInt);
begin
    if iNewVal<=FMaxValue then
    begin
      Text := IntToStr(iNewVal);
      FValue := iNewVal;
    end;
    if Focused then
    begin
      SelStart := Length(Text);
      SelectAll;
    end;
end;

procedure TIntEdit.SetMaxValue(Value: LongInt);
begin
  FMaxValue := Value;
end;

procedure TIntEdit.SetAsInteger(lnVal: LongInt);
begin
  Value := lnVal;
end;

function TIntEdit.GetAsInteger: LongInt;
begin
  Result := Value;
end;

procedure TIntEdit.SetAsString(strVal: string);
begin
  Value := StrToInt(strVal);
end;

function TIntEdit.GetAsString: string;
begin
  Result := IntToStr(Value);
end;

procedure TIntEdit.KeyPress(var Key: Char);
begin
    if not (Key in [#27, '0'..'9', #8, #13]) then
    begin
      Key := #0;
      Exit;
    end;
    try
      if not (Key in [#27, #8, #13]) then
        FValue := StrToInt(Text+Key);
      inherited;
    except
      Key := #0;
    end;
  inherited KeyPress(Key);
end;

procedure TIntEdit.KeyDown(var Key: Word; Shift: TShiftState);
begin
  ClearSelection;
  inherited KeyDown(Key,Shift);
end;

procedure TIntEdit.KeyUp(var Key: Word; Shift: TShiftState);
begin
  inherited KeyUp(Key,Shift);
  if Text='' then
  begin
    Text := '0';
    SelStart := Length(Text);
    SelectAll;
  end;
  FValue := StrToInt(Text);
end;


procedure TIntEdit.CreateParams(var Params: TCreateParams);
var
{$ifdef VER120}
  lnStyle: LongWord;
{$else}
  lnStyle: LongInt;
{$endif}
begin
  inherited CreateParams(Params);
  case Alignment of
    taLeftJustify:
      lnStyle := ES_LEFT;
    taRightJustify:
      lnStyle := ES_RIGHT
    else
      lnStyle := ES_CENTER;
  end;
  with Params do
    Style := Style or DWORD(lnStyle);
end;

procedure TIntEdit.CMEnter(var Message: TCMEnter);
begin
  if AutoSelect and not ReadOnly then
    SelectAll
  else
    if not ReadOnly then
    begin
      SelStart := Length(Text);
    end;
  Refresh;
  inherited;
end;

end.

El nombre introduït s'obté en la propietat Value. La propietat MaxValue ens permet limitar el màxim nombre a introduir. Tenim també la propietat Alignment, per alinear el text a la dreta de la caixa d'edició.

Wednesday, December 20, 2006


WinStartUp

Si posem aquest component en un formulari de l'aplicació podem fer que a l'arrancar Windows s'executi la nostra aplicació.

unit WinStartUp;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Registry;

type
  TWinStartUp = class(tcomponent)
  private
    { Private declarations }
    FStartWithWin: boolean;
    FEnabled : boolean;
    procedure SetRegistryData(RootKey: HKEY; Key, Value: string;
      RegDataType: TRegDataType; Data: variant); protected
    function GetRegistryData(RootKey: HKEY; Key, Value: string): variant;
    function ExistRegistryData(RootKey: HKEY; Key, Value: string): boolean;
    procedure DelRegistryData(RootKey: HKEY; Key, Value: string);
  protected
    { Protected declarations }
  public
    { Public declarations }
    constructor Create(AOwner:TComponent); override;
    destructor Destroy; override;
    procedure Loaded; override;
    procedure StartWithWindows(yes: boolean);
    function IsInStart: boolean;
  published
    { Published declarations }
    property Enabled: boolean read FEnabled write FEnabled;
    property StartWithWin: boolean read FStartWithWin write FStartWithWin;
  end;

procedure Register;

implementation

constructor TWinStartUp.Create(AOwner:TComponent);
begin
  inherited Create(AOwner);
  FStartWithWin := False;
  FEnabled := False;
end;

procedure TWinStartUp.StartWithWindows(yes: boolean);
begin
  if yes then
  begin
    if not ExistRegistryData(HKEY_LOCAL_MACHINE,
      'Software\Microsoft\Windows\CurrentVersion\Run',
      Application.Title) then
    begin
      SetRegistryData(HKEY_LOCAL_MACHINE,
        'Software\Microsoft\Windows\CurrentVersion\Run',
        Application.Title, rdString, Application.ExeName);
    end;
  end
  else
  begin
    if ExistRegistryData(HKEY_LOCAL_MACHINE,
      'Software\Microsoft\Windows\CurrentVersion\Run',
      Application.Title) then
    begin
      DelRegistryData(HKEY_LOCAL_MACHINE,
        'Software\Microsoft\Windows\CurrentVersion\Run',
        Application.Title);
    end;
  end;
end;

function TWinStartUp.IsInStart: boolean;
begin
  Result := ExistRegistryData(HKEY_LOCAL_MACHINE,
      'Software\Microsoft\Windows\CurrentVersion\Run',
      Application.Title);
end;

procedure TWinStartUp.Loaded;
begin
  inherited Loaded;
  if FEnabled then
  begin
    if FStartWithWin then
    begin
      if not ExistRegistryData(HKEY_LOCAL_MACHINE,
        'Software\Microsoft\Windows\CurrentVersion\Run',
        Application.Title) then
      begin
        SetRegistryData(HKEY_LOCAL_MACHINE,
          'Software\Microsoft\Windows\CurrentVersion\Run',
          Application.Title, rdString, Application.ExeName);
      end;
    end
    else
    begin
      if ExistRegistryData(HKEY_LOCAL_MACHINE,
        'Software\Microsoft\Windows\CurrentVersion\Run',
        Application.Title) then
      begin
        DelRegistryData(HKEY_LOCAL_MACHINE,
          'Software\Microsoft\Windows\CurrentVersion\Run',
          Application.Title);
      end;
    end;
  end;
end;

destructor TWinStartUp.Destroy;
begin
  inherited Destroy;
end;

function TWinStartUp.ExistRegistryData(RootKey: HKEY; Key, Value: string): boolean;
var
  Reg: TRegistry;
  s: string;
  res: boolean;
begin
  res := False;
  Reg := nil;
  try
    Reg := TRegistry.Create(KEY_QUERY_VALUE);
    Reg.RootKey := RootKey;
    if Reg.OpenKey(Key, False) then
    begin
      try
        if Reg.ValueExists(Value) then
        begin
          res := True;
        end
      except
        Reg.CloseKey;
        raise;
      end;
      Reg.CloseKey;
    end
    else
      raise Exception.Create(SysErrorMessage(GetLastError));
  except
    Reg.Free;
    raise;
  end;
  Reg.Free;
  Result := res;
end;

procedure TWinStartUp.DelRegistryData(RootKey: HKEY; Key, Value: string);
var
  Reg: TRegistry;
  s: string;
begin
  Reg := nil;
  try
    Reg := TRegistry.Create(KEY_WRITE);
    Reg.RootKey := RootKey;
    if Reg.OpenKey(Key, True) then
    begin
      try
        Reg.DeleteValue(Value);
      except
         Reg.CloseKey;
         raise;
      end;
      Reg.CloseKey;
    end
    else
      raise Exception.Create(SysErrorMessage(GetLastError));
  except
    Reg.Free;
    raise;
  end;
  Reg.Free;
end;

procedure TWinStartUp.SetRegistryData(RootKey: HKEY; Key, Value: string;
    RegDataType: TRegDataType; Data: variant);
var
  Reg: TRegistry;
  s: string;
begin
  Reg := nil;
  try
    Reg := TRegistry.Create(KEY_WRITE);
    Reg.RootKey := RootKey;
    if Reg.OpenKey(Key, True) then
    begin
      try
        if RegDataType = rdUnknown then
          RegDataType := Reg.GetDataType(Value);
        if RegDataType = rdString then
          Reg.WriteString(Value, Data)
        else if RegDataType = rdExpandString then
          Reg.WriteExpandString(Value, Data)
        else if RegDataType = rdInteger then
          Reg.WriteInteger(Value, Data)
        else if RegDataType = rdBinary then
        begin
          s := Data;
          Reg.WriteBinaryData(Value, PChar(s)^, Length(s));
        end
        else
          raise Exception.Create(SysErrorMessage(ERROR_CANTWRITE));
      except
         Reg.CloseKey;
         raise;
      end;
      Reg.CloseKey;
    end
    else
      raise Exception.Create(SysErrorMessage(GetLastError));
  except
    Reg.Free;
    raise;
  end;
  Reg.Free;
end;

function TWinStartUp.GetRegistryData(RootKey: HKEY; Key, Value: string): variant;
var
  Reg: TRegistry;
  RegDataType: TRegDataType;
  DataSize, Len: integer;
  s: string;
begin
  Reg := nil;
  try
    Reg := TRegistry.Create(KEY_QUERY_VALUE);
    Reg.RootKey := RootKey;
    if Reg.OpenKeyReadOnly(Key) then begin
      try
        RegDataType := Reg.GetDataType(Value);
        if (RegDataType = rdString) or
           (RegDataType = rdExpandString) then
          Result := Reg.ReadString(Value)
        else if RegDataType = rdInteger then
          Result := Reg.ReadInteger(Value)
        else if RegDataType = rdBinary then
        begin
          DataSize := Reg.GetDataSize(Value);
          if DataSize = -1 then
          begin
            raise Exception.Create(SysErrorMessage(ERROR_CANTREAD));
          end
          else
          begin
            SetLength(s, DataSize);
            Len := Reg.ReadBinaryData(Value, PChar(s)^, DataSize);
            if Len <> DataSize then
              raise Exception.Create(SysErrorMessage(ERROR_CANTREAD))
            else
              Result := s;
          end
        end
        else
          raise Exception.Create(SysErrorMessage(ERROR_CANTREAD));
      except
        s := '';
        Reg.CloseKey;
        raise;
      end;
      Reg.CloseKey;
    end else
      raise Exception.Create(SysErrorMessage(GetLastError));
  except
    Reg.Free;
    raise;
  end;
  Reg.Free;
end;

procedure Register;
begin
  RegisterComponents('Components Delphi', [TWinStartUp]);
end;

end.


Per a que el component actui, la propietat Enabled ha d'estar a True. Una vegada activat el component, si la propietat StartWithWin val True i executem la nostra aplicació, la pròxima vegada que arranquem Windows, arrancarà l'aplicació. Si la propietat està a False, al tornar a arrancar el sistema operatiu, l'aplicació no arrancarà.

Tuesday, December 19, 2006


VisualTimer

Aquest component és un Timer, però creat a partir d'un TCustomLabel. Té la particularitat de que es veu gràficament com es descompten els segons. El codi és el següent:

unit VisualTimer;

interface

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

type
  TVisualTimer = class(TCustomLabel)
  private
    FSeconds: Cardinal;
    FSecondsIni: Cardinal;
    FWindowHandle: HWND;
    FOnTimer: TNotifyEvent;
    FEnabled: Boolean;
  procedure UpdateTimer;
    procedure SetEnabled(Value: Boolean);
    procedure SetSeconds(Value: Cardinal);
    procedure SetOnTimer(Value: TNotifyEvent);
    procedure WndProc(var Msg: TMessage);
  protected
    procedure Timer; dynamic;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property Enabled: Boolean read FEnabled write SetEnabled default True;
    property Seconds: Cardinal read FSeconds write SetSeconds default 60;
    property OnTimer: TNotifyEvent read FOnTimer write SetOnTimer;
    property Transparent;
    property Align;
    property Alignment;
    property Anchors;
    property AutoSize;
    property Caption;
  end;

procedure Register;

implementation

constructor TVisualTimer.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FEnabled := True;
  FSeconds := 60;
  FWindowHandle := AllocateHWnd(WndProc);
end;

destructor TVisualTimer.Destroy;
begin
  FEnabled := False;
  UpdateTimer;
  DeallocateHWnd(FWindowHandle);
i nherited Destroy;
end;

procedure TVisualTimer.WndProc(var Msg: TMessage);
begin
  with Msg do
  begin
    if Msg = WM_TIMER then
    try
      Dec(FSeconds);
      Caption := IntToStr(FSeconds);
      if FSeconds=0 then
      begin
        FSeconds := FSecondsIni;
        Timer;
      end;
    except
      Application.HandleException(Self);
    end
    else
      Result := DefWindowProc(FWindowHandle, Msg, wParam, lParam);
  end;
end;

procedure TVisualTimer.UpdateTimer;
begin
  KillTimer(FWindowHandle, 1);
  if (FSeconds <> 0) and FEnabled and Assigned(FOnTimer) then
  begin
    if SetTimer(FWindowHandle, 1, 1000, nil) = 0 then
      raise EOutOfResources.Create(SNoTimers);
    FSecondsIni := FSeconds;
  end;
end;

procedure TVisualTimer.SetEnabled(Value: Boolean);
begin
  if Value <> FEnabled then
  begin
    FEnabled := Value;
   UpdateTimer;
  end;
end;

procedure TVisualTimer.SetSeconds(Value: Cardinal);
begin
  if Value <> FSeconds then
  begin
     FSeconds := Value;
     UpdateTimer;
  end;
end;

procedure TVisualTimer.SetOnTimer(Value: TNotifyEvent);
begin
  FOnTimer := Value;
  UpdateTimer;
end;

procedure TVisualTimer.Timer;
begin
  if Assigned(FOnTimer) then FOnTimer(Self);
end;

procedure Register;
begin
  RegisterComponents('Components Delphi', [TVisualTimer]);
end;

end.


La propietat Seconds indica el temps que trigarà a saltar l'event OnTimer. Tot i que él Timer de Delphi té una resolució de milisegons, això a nivell visual seria poc pràctic, per tant he deixat la resolució en segons.
També és podria modificar el component per si el timer supera els 60 segons poder mostrar minuts i segons, i el mateix en el cas de les hores.

This page is powered by Blogger. Isn't yours?