Modifier une caption à partir d'une variable [Résolu]

Messages postés
123
Date d'inscription
dimanche 29 octobre 2006
Dernière intervention
15 septembre 2018
- 8 avril 2013 à 13:02 - Dernière réponse :
Messages postés
4304
Date d'inscription
samedi 16 octobre 2004
Dernière intervention
9 mars 2018
- 13 avril 2013 à 15:20
J'écris un programme qui contient beaucoup de labels. Je suis tout le temps en train d'écrire Label1.caption=ceci, label2.caption=cela... Je voudrais bien me simplifier la tâche en écrivant tout simplement c1:=ceci, c2:=cela ou à la rigueur c1^:=ceci c2^:=cela. Et bien sûr, les captions prendraient les valeurs données à c1 et c2.

Delphi me permet d'écrire: Addr(Label1) mais ça ne m'apporte rien. Si je pouvais écrire Addr(label1.caption), ce serait facile mais ça, Delphi ne l'accepte pas, c'est bien normal.

Avec quelques recherches, je peux trouver combien d'octets séparent le début de Label1 de sa caption (on peut appeler ça le décalage, l'offset) mais je ne vois pas comment je pourrais m'en servir.

En résumé: si je connais A, adresse de Label1, comment lire et modifier le contenu de [(adresse pointée par A) + offset de la caption)]. En Turbo-Pascal, on avait le mot Mem[adresse] qui permettait de faire tout ce qu'on voulait, y compris de grosses bêtises, mais Delphi me semble s'être cuirassé contre la possibilité de lire ou de modifier une adresse mémoire autrement qu'en y accédant par une variable.
Afficher la suite 

Votre réponse

25 réponses

Meilleure réponse
Messages postés
1293
Date d'inscription
mardi 28 octobre 2003
Statut
Contributeur
Dernière intervention
3 juillet 2015
- 8 avril 2013 à 13:37
3
Merci
Remarque : Attention, je crois me souvenir que "FindComponent" est sensible à la casse... (A vérifier)

Simon

Merci sp40 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 88 internautes ce mois-ci

Commenter la réponse de sp40
Messages postés
1293
Date d'inscription
mardi 28 octobre 2003
Statut
Contributeur
Dernière intervention
3 juillet 2015
- 8 avril 2013 à 13:36
0
Merci
Salut,

Alors, je ne suis pas sûr d'avoir bien compris ta question. Excuse moi donc si je réponds à côté.

Si c'est juste une histoire de taper moins sur ton clavier, tu peux te faire une procédure (mais ton code perd en compréhension) :
procedure TMyForm.c(iNumero : integer; sValeur : string);
begin
     if FindComponent('Label'+ IntToStr(iNumero)) <> nil 
        then TLabel(FindComponent('Label'+ IntToStr(iNumero))).Caption := sValeur;
end;


Simon
Commenter la réponse de sp40
Messages postés
123
Date d'inscription
dimanche 29 octobre 2006
Dernière intervention
15 septembre 2018
- 8 avril 2013 à 14:33
0
Merci
Merci pour ta réponse. Tu as fort bien compris et je t'avoue que peu après avoir envoyé mon message, j'ai eu exactement la même idée: écrire une procédure ayant un nom très court et j'ai pensé moi aussi que le mieux était de l'appeler C. Et voilà: il me suffit d'écrire: C(1,ceci); C(2,cela).
En lecture, il me suffit d'écrire une fonction du même style et c'est gagné.

Mais tout de même, pour la beauté de la chose (et parce que ça m'arrangerait, ce serait trop long d'expliquer pourquoi), je pense que je vais continuer à chercher une solution qui me permettrait de représenter les captions par des raccourcis. Je vais chercher du côté des composants. J'imagine de créer un composant non visible pour ne pas me compliquer la vie, avec un nom très court et avec des propriétés qui s'appelleront c1,c2,etc... Pour chacune de ces propriétés, il y aura une procedure write et une fonction read dans laquelle, je pourrai faire ce que je voudrai. Le boulot à faire m'effraie un peu mais ce serait un bon exercice.

Et malgré tout, si certains ont des idées pour faire ça en passant par des manipulations de la mémoire, ce serait la solution la plus élégante. J'ai un label qui pointe vers une adresse A. À l'adresse pointée par A commence la description de mon label. Imaginons que l'offset de la caption est égal à 0. Le problème est simple: il me faut modifier le contenu de cette adresse pointée. Si seulement, je pouvais écrire MonPointeur: = Label1 (ce qui ne me parait pas absurde puisqu'en fait, un Label, c'est un pointeur), il me suffirait d'écrire: Monpointeur^:=ceci; Allez, zut, je continue à chercher.
Commenter la réponse de fredelem
Messages postés
1293
Date d'inscription
mardi 28 octobre 2003
Statut
Contributeur
Dernière intervention
3 juillet 2015
- 8 avril 2013 à 16:30
0
Merci
hé bé... Bon courage !
Et moi qui me croyais tout seul à me torturer les méninges...


Simon
Commenter la réponse de sp40
Messages postés
308
Date d'inscription
jeudi 29 septembre 2005
Dernière intervention
17 septembre 2013
- 8 avril 2013 à 19:05
0
Merci
Bonsoir,

ou aussi :

procedure setCaption(label: TLabel; const caption: string);
begin
  label.Caption := caption;
end;

....
....

procedure TForm1.toto;
begin
  // ALabel est un TLabel
  // Edit1 est un TEdit
  setCaption(ALabel, Edit1.Text);
end;


Luc.
Commenter la réponse de beckerich
Messages postés
123
Date d'inscription
dimanche 29 octobre 2006
Dernière intervention
15 septembre 2018
- 8 avril 2013 à 19:51
0
Merci
Merci Luc, mais je ne vois pas très bien comment utiliser cette procedure Toto. J'avais pensé à une procédure de ce genre mais plus étoffée pour tout mettre à jour d'un coup:
c1:= ceci;
c2:= cela;
toto;

La procedure toto étant:
..
procedure TForm1.toto;
begin
. setCaption(Label1,c1);
. setCaption(Label2,c2);
. etc...
end;

PS: j'aurais bien aimé mettre ma portion de programme sur fond gris comme tu l'as fait et aussi conserver l'indentation sans ajouter un point.. Tu peux me dire le secret ?

Fred
Commenter la réponse de fredelem
Messages postés
308
Date d'inscription
jeudi 29 septembre 2005
Dernière intervention
17 septembre 2013
- 8 avril 2013 à 20:06
0
Merci
Commenter la réponse de beckerich
Messages postés
308
Date d'inscription
jeudi 29 septembre 2005
Dernière intervention
17 septembre 2013
- 8 avril 2013 à 20:12
0
Merci
re,

non, toto n'est pas à suivre, mais quand tu as besoin de changer le caption d'un des tlabel, tu appelles la procedure setCaption avec comme premier paramètre le TLabel en question et en second paramètre le texte à afficher.

Ce n'est qu'un petit exemple de la façon de regrouper certaines actions répétitives. Tu pourrais aussi gérer un tableau de TCaption et afficher le tout dans une boucle, ...

Luc
Commenter la réponse de beckerich
Messages postés
123
Date d'inscription
dimanche 29 octobre 2006
Dernière intervention
15 septembre 2018
- 8 avril 2013 à 20:54
0
Merci
Eh bien merci à tous les deux, j'aurai appris pas mal de choses aujourd'hui.

Fred
]
Commenter la réponse de fredelem
Messages postés
4304
Date d'inscription
samedi 16 octobre 2004
Dernière intervention
9 mars 2018
- 10 avril 2013 à 13:41
0
Merci
Attention "label" est un mot réservé du pascal


Code Delphi :
procedure setCaptions(aControls: array of TControl; aCaptions: array of string; const aRefresh: boolean= false);
var X,LC,LS: integer;
begin
  LC := Length(aControls);
  LS := Length(aCaptions);

  for X := 0 to LC-1 do
    aControls[X].SetTextBuf(PChar(aCaptions[X mod LS]));
  if aRefresh then
    Application.processMessages;
end;

{ exemples : }
setCaptions([lbl1], ['A']); // lbl1 = "A"
setCaptions([lbl1, btn1], ['A','B']); // lbl1 = A, btn1 = "B"
setCaptions([lbl1, btn1, pnl2], ['-']); // lbl1 = btn1 = pnl2 = "-"
setCaptions([lbl1, lbl2, lbl3, lbl4], ['+','-']); // lbl1 = lbl3 = "+", lbl2 = lbl4 = "-"


// Et en mode LoL
procedure setCaptionsFmt(aControls: array of TControl; aFormats: array of string; aConsts: array of array of const; const aRefresh: boolean= false);
begin
var X,LCtl,LFmt,LCnt: integer;
begin
  LCtl := Length(aControls);
  LSFmt := Length(aFormats);
  LCnt := Length(aConsts);

  for X := 0 to LCtl-1 do
    aControls[X].SetTextBuf(PChar(format(aFormats[X mod LFmt],aConsts[X mod LCnt)));
  if aRefresh then
    Application.processMessages;
end;

{exemples :}
setCaptionsFmt(
  [lbl1, lbl2], // controls
  ['Progression %d sur %d', 'Total %.2f%%'], // descripteurs de formats
  [
    [PgBar1.Position,PgBar1.Max], [PgBar1.Position/PbBar1.Max*100]
  ] 
); 
// lbl1 = "Progression 27 sur 524"
// lbl2 = "Total 5.15%"


________________________________________________________
Commenter la réponse de f0xi
Messages postés
1293
Date d'inscription
mardi 28 octobre 2003
Statut
Contributeur
Dernière intervention
3 juillet 2015
- 10 avril 2013 à 13:43
0
Merci
ouf ! du lourd !

Pourquoi le mode "LoL" ? (je ne vois pas trop ce qu'il a de drôle... )

Simon
Commenter la réponse de sp40
Messages postés
123
Date d'inscription
dimanche 29 octobre 2006
Dernière intervention
15 septembre 2018
- 10 avril 2013 à 17:17
0
Merci
Merci pour cette portion de programme nettement plus savante que ce que je fais habituellement. Je vais la tester ce soir même. Je n'y vois pas de pointeurs. Mais c'est pas plus mal.

Le mot Lol m'est inconnu mais tant mieux, c'est comme ça qu'on progresse.

J'étais parti sur la fabrication d'un composant ayant c1,c2,etc... comme propriétés privées et j'avais écrit:

property c1 read getc1 write setc1;

et bien sûr dans la procedure setc1, je comptais mettre un label1.caption:=...

Mais de toutes façons, même si d'autres procédés me donnent satisfaction, j'essaierai de faire quelque chose avec des pointeurs.

@Simon: Findcomponent n'est pas sensible à la casse. Je trouve ça plutôt normal.

Rendez-vous demain pour que je vous dise où j'en suis.


PS: Bien que pas très savant, j'aimerais bien être informé des questions qui arrivent sur ce forum. Que faut-il faire pour cela?
Commenter la réponse de fredelem
Messages postés
1293
Date d'inscription
mardi 28 octobre 2003
Statut
Contributeur
Dernière intervention
3 juillet 2015
- 10 avril 2013 à 18:12
0
Merci
Tu coches "M'envoyer un mail lorsqu'il y a une réponse à cette discussion." juste en dessus du bouton "envoyer le message"

Simon
Commenter la réponse de sp40
Messages postés
123
Date d'inscription
dimanche 29 octobre 2006
Dernière intervention
15 septembre 2018
- 10 avril 2013 à 19:53
0
Merci
OK, j'ai coché cette case bien sûr mais elle ne concerne que ma petite question. Il y a peut-être eu d'autres questions qui ont été posées aujourd'hui et qui sait, j'aurais peut-être pu apporter des réponses. Je ne vois nulle part comment s'inscrire en tant que secouriste occasionnel.
Commenter la réponse de fredelem
Messages postés
1293
Date d'inscription
mardi 28 octobre 2003
Statut
Contributeur
Dernière intervention
3 juillet 2015
- 11 avril 2013 à 08:48
0
Merci
Bé il faut venir régulièrement sur le forum ou te charger un flux rss... Sur un sujet, même si tu n'interviens pas, tu as une option "suivre cette discussion"

Simon
Commenter la réponse de sp40
Messages postés
123
Date d'inscription
dimanche 29 octobre 2006
Dernière intervention
15 septembre 2018
- 11 avril 2013 à 09:59
0
Merci
@Simon: bon, je viendrai voir de temps en temps. C'est dommage qu'on ne puisse pas s'inscrire une bonne fois pour toutes et être informé dès qu'il y a quelque chose.

@fOxi: J'ai essayé le programme. Pas de problème, il marche. Mais pour bien le comprendre, je l'ai dépouillé à l'extrême. Je l'ai réduit à ça:

PROCEDURE Tform1.SetCaption(C:TControl; S:String{; Const ARefresh: Boolean= False});
Begin
   C.SetTextBuf(PChar(S));
   //IF ARefresh THEN
   //   Application.ProcessMessages;
End;


Comme ça, ça marche encore et je comprends que les contrôles ont une méthode SetTextBuf qui apparemment sert à écrire leur caption. C'est bon à savoir.
Je découvre qu'il n'est pas forcé que tous les arguments annoncés dans la procédure soient présents dans l'appel de cette procédure. Évidemment pour une constante dont on donne la valeur, ça parait normal.
Je découvre aussi qu'un argument peut être un array dont on ne donne pas les dimensions. Tiens, ça, ça pourrait m'être utile pour autre chose: écrire une procédure Sma Acronyme de (ShowMessageAmélioré) qui me permettrait d'écrire des ShowMessage de façon moins fatigante: la syntaxe serait
Sma('Les valeurs de x et y sont ',x,' et ',y); (Au diable les inttostr !)
Mais je ne comprends pas pourquoi il y a un Application.ProcessMessages. D'autant plus qu'il n'est jamais activé puisque ARefresh est fixé à false.
Pour moi, Application.ProcessMessages, ça veut dire: finis le travail que tu as laissé en plan avant d'aller plus loin. Ici, je n'en vois pas l'utilité. Et d'ailleurs, la procédure fonctionne aussi bien sans ça.
Commenter la réponse de fredelem
Messages postés
1293
Date d'inscription
mardi 28 octobre 2003
Statut
Contributeur
Dernière intervention
3 juillet 2015
- 11 avril 2013 à 10:10
0
Merci
Je découvre qu'il n'est pas forcé que tous les arguments annoncés dans la procédure soient présents dans l'appel de cette procédure
-> Si tu mets une valeur par défaut à un paramètre de ta fonction, le paramètre est en effet facultatif

Évidemment pour une constante dont on donne la valeur, ça parait normal.
-> Non, c'est juste que tu ne peux pas modifier ça valeur dans le corps de ta fonction, le mot "const" ajouté devant un paramètre sert à ça.

Mais je ne comprends pas pourquoi il y a un Application.ProcessMessages. D'autant plus qu'il n'est jamais activé puisque ARefresh est fixé à false.
-> Application.ProcessMessages permet de "dépiler" tous les messages windows en attente de traitement avant de continuer ton programme. Dans le cas présent, ça permet de rafraichir le caption de ton label. Si on reprend cette procedure :

PROCEDURE Tform1.SetCaption(C:TControl; S:String; Const ARefresh: Boolean= False);
Begin
   C.SetTextBuf(PChar(S));
   IF ARefresh THEN
      Application.ProcessMessages;
End;


Tu as 3 façons de l'appeler :
1) SetCaption (Label1, 'Coucou'); -> Paramètre ARefresh = false, donc pas d'appel à Application.ProcessMessages;
2) SetCaption (Label1, 'Coucou', false); -> Idem à 1...
3) SetCaption (Label1, 'Coucou', True); -> Paramètre ARefresh = True, donc pas d'appel à Application.ProcessMessages;

Le const t'interdit juste de faire ça :

PROCEDURE Tform1.SetCaption(C:TControl; S:String; Const ARefresh: Boolean= False);
Begin
   C.SetTextBuf(PChar(S));
   ARefresh := True;  // Là, tu dois avoir des problèmes...
   IF ARefresh THEN
      Application.ProcessMessages;
End;



Simon
Commenter la réponse de sp40
Messages postés
1293
Date d'inscription
mardi 28 octobre 2003
Statut
Contributeur
Dernière intervention
3 juillet 2015
- 11 avril 2013 à 10:12
0
Merci
modifier ça valeur


ouh, c'est vilain... Il fallait lire : "modifier sa valeur", sorry

Simon
Commenter la réponse de sp40
Messages postés
308
Date d'inscription
jeudi 29 septembre 2005
Dernière intervention
17 septembre 2013
- 11 avril 2013 à 10:31
0
Merci
Bonjour,

Application.ProcessMessages permet en effet à l'application de déplier les messages en attente.
Si tu ne désires que rafraîchir ton composant (TControl), tu peux aussi faire :
TControl.Update;


Luc.
Commenter la réponse de beckerich
Messages postés
123
Date d'inscription
dimanche 29 octobre 2006
Dernière intervention
15 septembre 2018
- 11 avril 2013 à 13:05
0
Merci
@Simon: Merci pour toutes ces précisions, je m'étais vraiment mis le doigt dans l'oeil. Dire que j'ai quelques années d'expérience en Delphi et que j'ignorais qu'on pouvait passer un paramètre avec une valeur par défaut. J'avais bien remarqué que Delphi le faisait avec la fonction Booltostr qu'on peut appeler avec 1 seul arguments ou avec 2 mais je ne savais pas que nous, la foultitude, on pouvait faire la même chose.

@Luc: Toi aussi, tu m'apprends quelque chose. Je connaissais Repaint, Refresh mais pas Update.

@FOxi: ton programme m'a fait faire beaucoup de découvertes mais quel est l'avantage d'écrire:
C.SetTextBuf(PChar(S))
plutôt que:
C.Caption:=S; ?
Commenter la réponse de fredelem

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.