Timer non visuel? [Résolu]

Messages postés
123
Date d'inscription
jeudi 10 janvier 2002
Dernière intervention
7 août 2018
- - Dernière réponse : cs_Gerard
Messages postés
123
Date d'inscription
jeudi 10 janvier 2002
Dernière intervention
7 août 2018
- 7 avril 2014 à 04:18
Bonjour,

Est-il possible d'ajouter un timer à un objet qui n'a pas de partie visuelle? (pas de fiche...)

merci...
--
Afficher la suite 

Votre réponse

14 réponses

Messages postés
273
Date d'inscription
samedi 13 juin 2009
Dernière intervention
18 avril 2015
0
Merci
Salut,
Oui, bien sûr, tu peux créer un timer, avec qq' règles simples:
- à condition de ne pas oublier de le supprimer (free)
- créer la proc (evenement) OnTimer dans une form (car elle recoit des messages), initialiser les champs interval et Ontimer à la création. Exemple: Form1, Bouton1 crée le timer, bouton2 le delete:


implementation
var LeTimer : tTimer = nil; // global à l'unité

procedure TForm1.Timer1Timer(Sender: TObject);
// evidem, déclarée dans Form1
beep; // exemple
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
if LeTimer=nil then
LeTimer := tTimer.create(self);
with LeTimer do
begin
OnTimer := Timer1Timer; // l'action
interval:=1000; // la durée
enabled:=true; // lancer
end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
LeTimer.free;
LeTimer := nil;
end;

Cordialement.

solilog
cs_Gerard
Messages postés
123
Date d'inscription
jeudi 10 janvier 2002
Dernière intervention
7 août 2018
-
Merci de la réponse, mais elle semble bien indiquer ce que je redoutais: un objet qui n'a pas de fiche - pas de partie visuelle - ne peut pas avoir de timer. De plus j'ai lu ailleurs que le nombre possible de timers était limité et défini par le système. Comme je peux avoir un très grand nombre d'objets je ne pense pas prendre le risque de développer avec le concept d'un timer par objet.
Commenter la réponse de solilog
Messages postés
273
Date d'inscription
samedi 13 juin 2009
Dernière intervention
18 avril 2015
0
Merci
Re salut,
Oui, tu craignais bien :-). Je vais essayer de trouver un truc ce soir, j'ai une petite idée (á suivre).
solilog
Commenter la réponse de solilog
Messages postés
123
Date d'inscription
jeudi 10 janvier 2002
Dernière intervention
7 août 2018
0
Merci
Oui j'ai vu que le timer appelait des APIs Windows, ce que je pourrais faire. mais c'est aussi là qu'il est dit que leur nombre est limité...
Et comme mes objets sont des joueurs et que leur nombre va croissant... J'en ai eu déjà jusqu'à 55 simultanés, voire plus...
C'est sans doute plusieurs centaines que je vais avoir à terme!
Enfin j'espère...

--
Commenter la réponse de cs_Gerard
Messages postés
273
Date d'inscription
samedi 13 juin 2009
Dernière intervention
18 avril 2015
0
Merci
Une centaine de joueurs avec chacun leur timer ? oublie ca.
Et pourquoi pas un seul timer qui gererait tous les joueurs ?


--
Commenter la réponse de solilog
Messages postés
423
Date d'inscription
samedi 17 mai 2003
Dernière intervention
4 août 2018
0
Merci
Salut,

Il semblerait que l'on puisse aller jusqu'à plusieurs milliers de timers...
http://blogs.msdn.com/b/oldnewthing/archive/2009/08/27/9886147.aspx

Quoi qu'il en soit, à moins que je n'aie pas tout bien compris (vous pouvez répéter la question ?), on peut tout à fait créer un timer dans un composant non visuel.

Démonstration.

Unité contenant le composant avec le timer :

unit Compo;

interface

uses
  SysUtils, Classes, extctrls;

type
  TComponentWithTimer = class(TComponent)
  private
    ATimer: TTimer;
    FTimerEnabled: Boolean;
    procedure SetTimerEnabled(Value: Boolean);
    procedure DoAnything(Sender: TObject);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property TimerEnabled: Boolean read FTimerEnabled write SetTimerEnabled default False;
  end;

implementation

constructor TComponentWithTimer.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  ATimer := TTimer.Create(Self);
  ATimer.OnTimer := DoAnything;
  ATimer.Enabled := False;
end;

destructor TComponentWithTimer.Destroy;
begin
  ATimer.Free;
  inherited Destroy;
end;

procedure TComponentWithTimer.SetTimerEnabled(Value: Boolean);
begin
  ATimer.Enabled := Value;
  FTimerEnabled := ATimer.Enabled;
end;

procedure TComponentWithTimer.DoAnything(Sender: TObject);
begin
  Beep;
end;

end.


Ce composant est utilisé dans une fiche comme ceci :

uses Compo;

var
  ComponentWithTimer: TComponentWithTimer;

procedure TForm1.FormCreate(Sender: TObject);
begin
  ComponentWithTimer := TComponentWithTimer.Create(Self);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  ComponentWithTimer.Free;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  with ComponentWithTimer do
    TimerEnabled := not TimerEnabled;
end;


So ?
Commenter la réponse de korgis
Messages postés
423
Date d'inscription
samedi 17 mai 2003
Dernière intervention
4 août 2018
0
Merci
On peut également créer le TTimer dans une classe, je viens de vérifier.

Le composant contenant le TTimer devient ainsi :

type
  TObjectWithTimer = class
  private
    ATimer: TTimer;
    FTimerEnabled: Boolean;
    procedure SetTimerEnabled(Value: Boolean);
    procedure DoAnything(Sender: TObject);
  public
    constructor Create(AOwner: TComponent);
    destructor Destroy; override;
  published
    property TimerEnabled: Boolean read FTimerEnabled write SetTimerEnabled default False;
  end;

implementation

constructor TObjectWithTimer.Create(AOwner: TComponent);
begin
  ATimer := TTimer.Create(nil);
  ATimer.OnTimer := DoAnything;
  ATimer.Enabled := False;
end;

destructor TObjectWithTimer.Destroy;
begin
  ATimer.Free;
end;

procedure TObjectWithTimer.SetTimerEnabled(Value: Boolean);
begin
  ATimer.Enabled := Value;
  FTimerEnabled := ATimer.Enabled;
end;

procedure TObjectWithTimer.DoAnything(Sender: TObject);
begin
  Beep;
end;


Et on l'utilise de la même manière dans notre fiche :

uses Compo;

var
  ObjectWithTimer: TObjectWithTimer;

procedure TForm1.FormCreate(Sender: TObject);
begin
  ObjectWithTimer := TObjectWithTimer.Create(Self);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  ObjectWithTimer.Free;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  with ObjectWithTimer do
    TimerEnabled := not TimerEnabled;
end;


Là non plus pas de souci, le Timer est libéré au moment de la destruction de "ObjectWithTimer".
korgis
Commenter la réponse de korgis
Messages postés
123
Date d'inscription
jeudi 10 janvier 2002
Dernière intervention
7 août 2018
0
Merci
Cela me parait excellent et je vais l'essayer!
Je vous tiens au courant lorsque j'aurais des résultats.
Aujourd'hui j'utilise un thread, créé lors de la création de l'objet joueur auquel je passe un pointeur qui pointe sur l'objet et ce thread tourne en rond en attendant que le joueur joue avec des appels à la fonction sleep.
Avec votre solution je vais pouvoir activer une méthode régulièrement qui va examiner si le joueur a joué...

--
Commenter la réponse de cs_Gerard
Messages postés
123
Date d'inscription
jeudi 10 janvier 2002
Dernière intervention
7 août 2018
0
Merci
J'ai donc essayé, mais je me suis heurté à quelques difficultés, sans doute parce que je n'ai pas tout compris.
Déjà la property published je ne connaissais pas. Je crois comprendre ce que cela fait: une propriété qui permet d'accéder à des parties privées.
Pourquoi faut-il que le timer soit déclaré dans les parties privées?
Ensuite pourquoi le lancer en différé et ne pas l'activer au moment de sa création?

J'ai donc fait au mieux pour insérer le timer comme indiqué ci-dessus, directement dans le projet.
j'ai déclenché le lancement du timer sur la première action du joueur.
J'ai obtenu l'erreur suivante EoutOfRessources avec le message 'pas assez de timers disponibles'

J'ai alors essayé de le lancer directement lors de sa création. Là je n'ai pas eu de problème (Pas d'erreur signalée), mais pas non plus d'interruptions vers la routine...


Alors j'ai repris depuis le début et refait exactement les deux projets en exemple et cela marche....!

J'essaie de comprendre la différence....
Je vais aussi tourner autour de ces exemples afin de voir ce qu'il ne faut pas faire!
Merci en tout cas!
--
Commenter la réponse de cs_Gerard
Messages postés
423
Date d'inscription
samedi 17 mai 2003
Dernière intervention
4 août 2018
0
Merci
"published" permet d'afficher et de modifier la propriété dans l'inspecteur d'objets (si tu enregistres le composant dans la palette bien sûr).
Donc, si tu n'as pas cette nécessité, tu peux mettre la propriété dans "public" (si tu veux y avoir accès), mais tu peux également la supprimer si tu n'as pas besoin de modifier l'état du Timer en dehors du composant.
Rien ne t'oblige à initialiser la propriété Timer.enabled à false, ce n'est qu'un exemple de fonctionnement.
Bon courage.
Commenter la réponse de korgis
Messages postés
123
Date d'inscription
jeudi 10 janvier 2002
Dernière intervention
7 août 2018
0
Merci
J'ai tourné autour de l'exemple ci-dessus en modifiant effectivement de nombreux points: c'est très robuste et cela marche tout le temps si l'essentiel y est.
Toutefois, je n'ai pas réussi à le faire fonctionner Dans l'objet joueur qui est dans le serveur actuel.
Cet objet joueur est créé lors de la première connexion à un serveur Indy et n'est - apparemment - pas attaché à une fiche quelconque, la connexion pouvant être fermée et le joueur subsister, prêt pour une nouvelle connexion.
serait-ce là l'origine du problème?

--
Commenter la réponse de cs_Gerard
Messages postés
123
Date d'inscription
jeudi 10 janvier 2002
Dernière intervention
7 août 2018
0
Merci
J'ai continué à tourner autour du problème en essayant de me rapprocher de l'exemple qui marche si bien...
Constatant que dans cet exemple, l'objet est créé à partir de la fiche, j'ai fait un modèle à un seul objet/joueur qui est un membre de la fiche.
Lorsqu'un joueur se connecte on crée alors cet objet/joueur.
Et bien cela ne marche toujours pas...
Si je lance le timer à la création du joueur, son gestionnaire d'événement n'est pas appelé, et si je le crée en différé alors j'ai toujours la même erreur 'pas assez de timers disponibles'
Je sèche...
--
Commenter la réponse de cs_Gerard
Messages postés
123
Date d'inscription
jeudi 10 janvier 2002
Dernière intervention
7 août 2018
0
Merci
je progresse..
Comme l'exemple marche, je l'ai directement inséré dans le projet avec création de l'objet avec timer dès la création de la fiche et pour un joueur lors de sa création il lui a été dit que son membre "Objet avec timer" était celui-ci.
Cela a marché pour un joueur!
Restait à passer à plusieurs joueurs simultanés.
essayé de créer l'objet avec timer dans le thread juste avant de créer le joueur: OK pour un joueur, pas pour deux....
J'ai donc créé un tableau d' "objet avec timer" qui est incrémenté à chaque nouveau joueur et le joueur se voit affecté cet 'objet avec joueur'
Et pour l'instant cela marche!
Je vais voir si je peux faire cela avec une liste qui me permettrait de gérer plus facilement les joueurs qui se déconnectent...
mais je tiens le bon bout!
enfin il me semble...


--
Commenter la réponse de cs_Gerard
Messages postés
123
Date d'inscription
jeudi 10 janvier 2002
Dernière intervention
7 août 2018
0
Merci
j'ai oublié de répondre à la suggestion:
Pourquoi pas un timer central qui traite tous les joueurs?
C'est ce qui existe actuellement en gros.
Actuellement, chaque requête déclenche une tâche visant à répondre à la requête: on est purement en gestion événementielle.
par contre il y a un timer central qui surveille l'activité des joueurs et le bon déroulement de l'action.
La particularité du jeu fait que les réponses aux requêtes peuvent prendre jusqu'à 20~30 secondes. Il y a donc beaucoup de scrutations qui sont inutiles et qui doivent être faites sous sections critiques ce qui est particulièrement lourd et risqué car si cela se passe mal on risque d''être planté...
En gros le timer central interroge une flopée de joueurs qui soit ont arrêté de jouer, soit sont dans des réponses à longue échéance alors que le scrutation doit être rapide afin d'assurer lorsque c'est possible un temps de réponse acceptable.
Avec des timers individuels, ceux ci sont suspendus pendant l'élaboration de la réponse et le timer central n'a plus ) parcourir tous les joueurs dont beaucoup aurait fini de jouer ou suspendu leur jeu...



--
Commenter la réponse de cs_Gerard
Messages postés
123
Date d'inscription
jeudi 10 janvier 2002
Dernière intervention
7 août 2018
0
Merci
Voici ce à quoi je suis arrivé et qui marche!


type TTimerPlus= class(TTimer)
public
pPlayer: pointer;
procedure Tasks(Sender: TObject);
constructor create(AOwner: Tcomponent); override;
End;

Type TPlayer: class(Tobject)
....
...
Public
constructor create(Requete: Trequete; AllocatedTimer: TTimerPlus);

End;

Constructor TTimerPlus.create(AOwner: TComponent);
Begin
inherited create(AOwner);
OnTimer:= Tasks;
Enabled:= false;
End;

Constructor TPlayer.create(Requete: Trequete; AllocatedTimer: TTimerPlus);
VAR
....
Begin
...
...
AllocatedTimer.pPlayer:= pointer(self);
AllocatedTimer.Enabled:= true;
End;

destructor Tplayer.destroy;
Begin
...
...
AllocatedTimer.free;
End;

procedure TTimerPlus.tasks(Sender: Tobject);
VAR
Player: TPlayer;
Begin
Enabled:= false;
Player:= TPlayer(pPlayer);
With Player do
try
...
Finally
Enabled:= true;
End;
End;
--
Maintenant pour allouer un timer au joueur, j'ai utilisé un tableau dynamique:

Var
Timers: Array of TTimerPlus;
Et lors de la première connexion d'un joueur on lui crée un timer au besoin et on le lui alloue:

N:=0;
While N< Length(Timers) do
Begin
If Timers[N]= nil then break;
Inc(N);
end;
if N>= Length(Timers) then SetLength(Timers,N+1);
Timers[N]:= TTimerPlus.create(Form1);
player:= Tplayer.create(Requete,Timers[N]);
Requete étant un objet qui permet d'identifier le joueur.

Lors de la destruction du joueur, le timer est libéré, ce qui fait qu'un autre joueur arrivant après peut le reprendre.

Ça marche! Merci!
Commenter la réponse de cs_Gerard

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.