Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Eigene Timer Komponente aus der MMSystem (https://www.delphipraxis.net/80204-eigene-timer-komponente-aus-der-mmsystem.html)

Zacherl 4. Nov 2006 16:59


Eigene Timer Komponente aus der MMSystem
 
Hi,

ich habe versucht eine eigene Timer Komponente zu basteln, die den MultiMedia Timer aus der Unit MMSystem verwendet ... Leider kommt es immer wieder zu AccessViolations.

Kann mir da jemand helfen:

Delphi-Quellcode:
unit SystemTimer;

interface

uses
  Windows, SysUtils, MMSystem, Classes, SyncObjs;

type
  TSystemTimer = class(TObject)
    private
      TimerID: Longword;
      FOnTimer: TNotifyEvent;
      FInterval: integer;
      procedure SetInterval(Value: integer);
      function GetInterval: integer;
    public
      procedure StartTimer;
      procedure StopTimer;
      constructor Create;
      destructor Destroy; override;
    published
      property Interval: integer read GetInterval write SetInterval;
      property OnTimer: TNotifyEvent read FOnTimer write FOnTimer;
  end;

implementation

var
  Timers: TList;
  IDs: TStringList;
  CS: TCriticalSection;

procedure TSystemTimer.SetInterval(Value: integer);
begin
  FInterval := Value;
end;

function TSystemTimer.GetInterval: integer;
begin
  Result := FInterval;
end;

procedure TimerCallback(uTimerID, uMessage: UINT; dwUser, dw1, dw2: DWORD) stdcall;
begin
  CS.Enter;
  if assigned(TSystemTimer(Timers[IDs.IndexOf(IntToStr(uTimerID))]).OnTimer) then
    TSystemTimer(Timers[IDs.IndexOf(IntToStr(uTimerID))]).OnTimer(TSystemTimer(Timers[IDs.IndexOf(IntToStr(uTimerID))]));
  CS.Leave;
end;

constructor TSystemTimer.Create;
begin
  inherited Create;
end;

destructor TSystemTimer.Destroy;
begin
  inherited Destroy;
end;

procedure TSystemTimer.StartTimer;
begin
  Timers.Add(Pointer(Self));
  TimerID := timeSetEvent(FInterval, 0, TimerCallback, 0, TIME_PERIODIC);
  IDs.Add(IntToStr(TimerID));
end;

procedure TSystemTimer.StopTimer;
begin
  timeKillEvent(TimerID);
  Timers.Delete(IDs.IndexOf(IntToStr(TimerID)));
  IDs.Delete(IDs.IndexOf(IntToStr(TimerID)));
end;

initialization
  IDs := TStringList.Create;
  Timers := TList.Create;
  CS := TCriticalSection.Create;

finalization
  Timers.Free;
  IDs.Free;
  CS.Free;

end.
Florian

SirThornberry 4. Nov 2006 17:12

Re: Eigene Timer Komponente aus der MMSystem
 
Anstelle der globalen Listen würde ich einfach der Callback-Funktion die Instanz mitgeben. Somit kannst du in der globalen Callbackfunktion über den übergebenen Parameter die Methode der Instanz aufrufen.

Zacherl 5. Nov 2006 15:57

Re: Eigene Timer Komponente aus der MMSystem
 
:gruebel: Kannst du mir ein Codebeispiel geben? Ich verstehe nicht so ganz, wie du das meinst.

Florian

stoxx 8. Jun 2007 16:09

Re: Eigene Timer Komponente aus der MMSystem
 
so ...

gruß Stoxx


Delphi-Quellcode:
unit SystemTimerU;
interface

uses
  Windows, SysUtils, MMSystem, Classes;

type

  TMMTimerData = record
    Instanz : TObject;
  end;
  PMMTimerData = ^TMMTimerData;


  TSystemTimer = class(TObject)
    private

      pSelfData : PMMTimerData;
      TimerID: Longword;
      FOnTimer: TNotifyEvent;
      FInterval: integer;
      procedure SetInterval(Value: integer);
      function GetInterval: integer;
    public
      procedure StartTimer;
      procedure StopTimer;
      constructor Create;
      destructor Destroy; override;
    published
      property Interval: integer read GetInterval write SetInterval;
      property OnTimer: TNotifyEvent read FOnTimer write FOnTimer;
  end;


implementation

//==============================================================================
constructor TSystemTimer.Create;
begin
  inherited Create;
  TimerID := 0;
  new(PSelfData);
end;
//==============================================================================
destructor TSystemTimer.Destroy;
begin
  FOnTimer := nil;
  self.stopTimer;
  dispose(PSelfData);
  sleep(50); // eigenartige Abstürze ohne dies
  inherited Destroy;
end;
//==============================================================================

procedure TSystemTimer.SetInterval(Value: integer);
begin
  FInterval := Value;
end;

//==============================================================================

function TSystemTimer.GetInterval: integer;
begin
  Result := FInterval;
end;

//==============================================================================

procedure TimerCallback(uTimerID, uMessage: UINT; dwUser, dw1, dw2: DWORD) stdcall; pascal;
var
   Timer : TSystemTimer;
   selfData : TMMTimerData;

begin

if dwUser <> 0 then begin
    SelfData := pMMTimerData(dwUser)^;
    Timer := TSystemTimer(selfdata.instanz);

    if assigned(Timer.FOnTimer)
      then Timer.FOnTimer(Timer);
    end;
end;

//==============================================================================

procedure TSystemTimer.StartTimer;
begin
  PSelfData.Instanz := Self;

  if TimerID = 0
     then TimerID := timeSetEvent(FInterval, 0, @TimerCallback, Integer(pSelfData), TIME_PERIODIC);
end;

//==============================================================================

procedure TSystemTimer.StopTimer;
begin

  pSelfData.Instanz := nil;
  if TimerID <> 0
   then timeKillEvent(TimerID);
  TimerID := 0;


end;

end.

Whookie 1. Apr 2009 07:37

Re: Eigene Timer Komponente aus der MMSystem
 
Eine überarbeitete Variante ohne Probleme mit Sleep:

Delphi-Quellcode:
unit compFastTimer;

interface

uses
  Windows, SysUtils, MMSystem, Classes;

type
  TFastTimer = class(TComponent)
  private
    fTimerID: Longword;
    fInterval: Integer;

    pSelfData : PMMTimerData;
    FOnTimer: TNotifyEvent;
    fEnabled: Boolean;
    procedure SetInterval(Value: integer);
    function GetInterval: integer;
    procedure SetEnabled(const Value: Boolean);
  public
    constructor Create(Owner: TComponent); Override;
    destructor Destroy; override;

  published
    property Enabled: Boolean read fEnabled write SetEnabled;
    property Interval: integer read GetInterval write SetInterval;
    property OnTimer: TNotifyEvent read FOnTimer write FOnTimer;
  end;


implementation

Const
  TIME_KILL_SYNCHRONOUS  = $0100;


procedure TimerCallback(uTimerID, uMessage: UINT; dwUser, dw1, dw2: DWORD) stdcall; pascal;
var
  ATimer: TFastTimer;
begin
  if dwUser <> 0 then
  begin
    ATimer := TFastTimer(dwUser);

    if Assigned(ATimer.fOnTimer) then
      ATimer.fOnTimer(ATimer);
  end;
end;



{ TFastTimer }

constructor TFastTimer.Create(Owner: TComponent);
begin
  inherited;
  fTimerID := 0;
  fInterval := 1000;
end;

destructor TFastTimer.Destroy;
begin
  Enabled := FALSE;
  inherited;
end;

function TFastTimer.GetInterval: integer;
begin
  Result := fInterval;
end;

procedure TFastTimer.SetInterval(Value: integer);
begin
  fInterval := Value;
end;



procedure TFastTimer.SetEnabled(const Value: Boolean);
begin
  if fEnabled <> Value then
  begin
    fEnabled := Value;
    if fEnabled then
    begin
      // Timer starten ...
      fTimerID := timeSetEvent(fInterval, 0, @TimerCallback, Integer(Self), TIME_PERIODIC Or TIME_KILL_SYNCHRONOUS);
    end
    else
    begin
     timeKillEvent(fTimerID);
     fTimerID := 0;
    end;
  end;
end;


end.
Das ganze könnte dann auch in die Tool-Palette installiert werden, und natürlich auch noch um die eine oder andere Eigenschaft (z.B.: Resolution) erweitert werden.

ACHTUNG!!! Updates der grafischen Oberfläche in OnTimer sind natürlich verboten!! (siehe MSDN-Library durchsuchentimeSetEvent ->Remarks). Mit MSDN-Library durchsuchenPostMessage(...) kann man aber aus OnTimer wieder in den Kontext des Hauptthreads kommen und dann von dort die Oberfläche aktuallisieren.


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:54 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz