Problème de création d'un TVarRec[]

Résolu
JeremyLecouvert Messages postés 139 Date d'inscription mardi 27 novembre 2007 Statut Membre Dernière intervention 10 mai 2010 - 13 oct. 2009 à 09:26
JeremyLecouvert Messages postés 139 Date d'inscription mardi 27 novembre 2007 Statut Membre Dernière intervention 10 mai 2010 - 14 oct. 2009 à 14:13
Bonjour tout le monde,

je galère depuis 3 jours sur un passage de paramètres (pitoyable!).. Je tourne en rond, quelqu'un pourra sûrement m'aider...

Voici la situation: j'ai une Form avec des ComboBox; le but est de charger des données en cascade en fonction des sélections dans les combos précédents..

Je cherche à factoriser au maximum, càd qu'au lieu d'avoir 1 méthode pour chaque combo et chaque requête, une seule méthode se chargera du boulot. Il me faut donc envoyer à cette méthode un nombre de paramètres variable. Je suis parti sur un TVarRec[] plutôt qu'un Variant, mais j'ai un souci sur la construction du TVarRec[].

Voici le code:

type Params = array of TVarRec;
...
function Parametres(anIndex: Integer): Params;
Var
  i: Integer;
  param: Params;
Begin
  SetLength(param, anIndex);
  For i:=0 to anIndex do
    Begin
      If TComboBox(Compos[i]).Name='CboDate' Then 
        Begin
          param[i].VType:=vtExtended;
          param[i].VExtended:=PExtended(StrToDate(TComboBox(Compos[i]).Text));
        End
      Else
        Begin
          param[i].VType:= vtString;
          param[i].VString:= PShortString(TComboBox(Compos[i]).Text);
        End;
    End;
  Result:= param;
End;


Mais voilou, erreur à la compil: "Invalid Typecast" sur "param[i].VExtended:=PExtended(...)".. j'ai essayé avec PExtended, Pointer, Double, @... rien n'y fait. J'ai aussi tenté de modifier ma fct pour renvoyer un Variant, mais j'ai eu d'autres erreurs et en plus je préfèrerais un TVarRec[] parce que le résultat de cette fct servira d'argument à un Format.

Si quelqu'un a une idée, avant que je noie mon désespoir dans le café...

19 réponses

Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
14 oct. 2009 à 13:06
En fait, tu charges des String depuis des champs (des ComboBox), oui ? Y'aura-t-il toujours le même nombre de Strings envoyés à la fonction (ou un maximum raisonnable) ?
Si c'est le cas, alors tu peux faire une structure puis "ajouter à la main" en faisant Format('ton format', [String1, String2, ... StringN])

Cordialement, Bacterius !
3
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
14 oct. 2009 à 13:11
C'est normale ... tu as une variable "S" que tu réaffectes à chaque boucle avec une nouvelle valeur et un nouveau pointeur !!!


P1, P2 Pn: PString;
S: string;

...
S := 'Str1';
P1 := PString(S);

jusque là ça va

S :'Str2'; boum ... P1^ Str2 !!!

si tu fait pointer tous les pointeurs sur une même variable c'est normale que la valeur change à la relecture.

Tu n'as pas saisi la fonction d'un pointeur.
Le pointeur n'est qu'une adresse mémoire de la variable pointée pas la valeur.


donc pour résoudre ton problème il te faut garder une trace de chaque pointeur que tu crées afin, dans un premier temps, de pouvoir récupérer la bonne valeur ... mais surtout de pouvoir libérer tous ces pointeurs à la fin ... sinon gare aux fuites de mémoire

un petit exemple ???
[hr][b]type

  /bTParams  = array of TVarRec;

var  // déclaration d'un tableau de pointeur
  PtrArray: array of Pointer;
function Parametres(anIndex: Integer): TParams;
[b]var
  /bi: Integer;
[b]begin
  /bSetLength(Result, anIndex);
  for I: =  low(Result)  to  High(Result) [b]do
    if /bmod 4  =  0 [b]then
    begin
      /b // ajuste la taille du tableau de pointeur
      SetLength(PtrArray, Length(PtrArray)+1);
      // Crée un nouveau pointeur
      New(Result[I].VExtended);
      // et on mémorise son adresse dans le tableau
      PtrArray[High(PtrArray)] : =  Result[I].VExtended;
      Result[I].VType :=  vtExtended;
      Result[I].VExtended^ := Now;
    [b]end
    else
    if /bI  mod  2  = 0 [b]then
    begin
      /bResult[I].VType :=  vtInteger;
      Result[I].VInteger := I;
    [b]end
    else
    begin
      /b // ajuste la taille du tableau de pointeur
      SetLength(PtrArray, Length(PtrArray)+1);
      // Crée un nouveau pointeur
      New(Result[I].VString);
      // et on mémorise son adresse dans le tableau
      PtrArray[High(PtrArray)] : = Result[I].VString;
      Result[I].VType :=  vtString;
      Result[I].VString^ := 'Valeur PShortString = ' + IntToStr(I);
     end ;

end;

   // on teste simplement
procedure TForm1.Button1Click(Sender: TObject);
[b]var
  /bParam: TParams;
  I: Integer;
[b]begin
  /bParam : = Parametres(8);
  for I :=  low(Param)  to  High(Param) [b]do
  with /bParam[I] [b]do
    case /bVType [b]of
      /bvtInteger : Memo1.Lines.Add(IntToStr(VInteger));
      vtString : Memo1.Lines.Add(VString^);
      vtExtended : Memo1.Lines.Add(DateTimeToStr(VExtended^));
    end;
end;

   // et on oublie pas de tout libérer à la fin ...
procedure TForm1.FormDestroy(Sender: TObject);
[b]var
  /bI: Integer;
[b]begin
  for /bI : = low(PtrArray) to High(PtrArray) [b]do
    /bDispose(PtrArray[I]);
end;
[hr]

voilà ceci devrait t'éclairer

[hr]@+Cirec
3
JeremyLecouvert Messages postés 139 Date d'inscription mardi 27 novembre 2007 Statut Membre Dernière intervention 10 mai 2010 2
13 oct. 2009 à 10:23
Abinvoala....

La solution m'est enfin apparue..

      If TComboBox(Compos).Name='CboDate' Then 
        Begin
          New(param[i].VExtended);
          param[i].VExtended^:=StrToDate(TComboBox(Compos).Text);
        End



Je suis tombé dessus presque par hasard, au moment ou tout semblait perdu...
Bref, ça fonctionne comme ça... mais je ne suis pas sûr de comprendre pourquoi!

Désolé pour la fausse alerte, je ne faisait que passer!
0
JeremyLecouvert Messages postés 139 Date d'inscription mardi 27 novembre 2007 Statut Membre Dernière intervention 10 mai 2010 2
13 oct. 2009 à 16:47
Bon, comment dire... je crois que je m'ai trompé!!
En fait c'est pas résolu, maintenant j'ai un autre souci: au fur et à mesure que je remplis mon tableau de paramètres, certaines données sont remplacées par la dernière donnée entrée.

J'ai modifié mon code comme ça:

...
      If TComboBox(Compos[i]).Name='CboDate' Then 
        Begin
          param[i].VType:= vtAnsiString;
          s:= FormatDateTime('yyyy-mm-dd', StrToDate(TComboBox(Compos[i]).Text));
          param[i].VAnsiString:=PAnsiString(s);
        End
      Else
...


et là, ça merdoie systématiquement quand j'arrive sur le combo date(indice 6): la donnée "s" écrase param[3] mais param[5] reste vide!!

J'avais déjà eu ce genre de problème en utilisant la fonction QuotedStr, et ça faisait la même chose dès la 3° itération (param[2] écrasait param[0])...

J'avoue que je ne comprends pas du tout ce qui ne va pas, j'ai essayé les Dispose(param[i]), Finalize(Args) et autres New(param[i].VAnsiString), mais sans succès... je ne suis même pas sûr que ça vienne d'un pb de libération ou d'allocation mémoire d'ailleurs, C'EST LE FLOU TOTAL!!

Quelqu'un pourra-t-il m'aider à me sortir de là?
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
14 oct. 2009 à 04:21
Le TVarRec c'est une souffrance à implémenter quand on s'y frotte pour la première fois. Moi, je l'aurai plus vu en entrée de fonction, car la plupart des fonctions retournent des éléments similaires, donc callback ou TList.
Sinon, je pense qu'il est possible d'obtenir ce que tu veux faire (si je comprends bien) sans avoir besoin d'un TVarRec. Genre un TList qui pointe sur des éléments contenant un pointeur sur une chaîne et un Extended ?

Cordialement, Bacterius !
0
JeremyLecouvert Messages postés 139 Date d'inscription mardi 27 novembre 2007 Statut Membre Dernière intervention 10 mai 2010 2
14 oct. 2009 à 10:02
Oui, je confirme effectivement que c'est une souffrance!!

J'ai essayé (dans un moment de trop grande souffrance) d'utiliser un Variant à la place, mais j'ai eu d'autres erreurs. Peut-être que le TList serait une solution, le problème c'est que dans la méthode qui va recevoir ces arguments, j'utilise la fonction Format pour paramétrer une requête SQL avec ces arguments. Le problème reste donc le même puisque dans cette fct, il faudra que je transforme le TList (ou ce que j'aurai) en TVarRec pour le passer à Format...
0
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
14 oct. 2009 à 10:06
Donc en fait, tu fournis des arguments à une fonction, qui va effectuer deux trois trucs et puis va ensuite formatter avec Format, puis envoyer la requête ? Le TVarRec est-il utilisé à part la fonction Format (question bête, mais bon) ?

Cordialement, Bacterius !
0
JeremyLecouvert Messages postés 139 Date d'inscription mardi 27 novembre 2007 Statut Membre Dernière intervention 10 mai 2010 2
14 oct. 2009 à 10:26
Non, le TVarRec n'est utilisé que dans Format.

Voilà précisément ce que je veux faire: j'ai plusieurs combos (et Edit) à charger. Dans ma form, je déclare un tableau avec les combos dans l'ordre du filtrage. Ensuite, j'ai une constante tableau qui contient les requêtes, et une fonction qui me renvoie les paramètres en fonction du compo à charger.

Ca se traduit comme ça pour charger la ième donnée:
-on appelle une fonction "Parametres(indexCompo: integer): Params;" qui (doit) nous créer un TVarRec[] avec toutes les données des compos 0 à i-1,
-on appelle une fonction "LoadData(indexCompo: integer; const Args: array of const): TStrings;" qui va exécuter la requête TabSQL[i], formatée avec les paramètres qui vont bien...

Sachant que LoadData est dans une classe métier qui ne connait pas la classe de l'IHM (donc pas d'utilisation directe des compos).
0
JeremyLecouvert Messages postés 139 Date d'inscription mardi 27 novembre 2007 Statut Membre Dernière intervention 10 mai 2010 2
14 oct. 2009 à 11:11
Au pire (ou au mieux!), si tu connais une solution alternative qui pourrait m'affranchir du TVarRec, ça résoudrait aussi mon problème...

Pour l'instant, je suis presque en train de me demander si ce ne serait pas plus simple de redévelopper une méthode semblable à Format qui prendrait d'autres types d'arguments... mais j'hésite encore, je voudrais pas enfoncer des portes ouvertes!!
0
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
14 oct. 2009 à 12:29
Ben déjà dans le premier code, je vois quelque chose d'aberrant :

For i:=0 to anIndex do


Ca serait plutôt :

For i:=0 to anIndex - 1 do


Puisqu'on commence à zéro ... ça peut peut-être résoudre quelque chose ?

Cordialement, Bacterius !
0
JeremyLecouvert Messages postés 139 Date d'inscription mardi 27 novembre 2007 Statut Membre Dernière intervention 10 mai 2010 2
14 oct. 2009 à 12:37
Non, c'est bien anIndex-1.. c'est un pb de copier/coller, désolé! Pareil dans le 2° bout de code j'ai oublié l'indice du combo dans une ligne...
0
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
14 oct. 2009 à 12:46
Il y a juste 1 valeur Extended à stocker, et tout le reste en String ? Si le nombre de champs est bien défini, tu peux passer par une structure, puis formatter en ajoutant chaque champ "à la main" dans Format ?

Cordialement, Bacterius !
0
JeremyLecouvert Messages postés 139 Date d'inscription mardi 27 novembre 2007 Statut Membre Dernière intervention 10 mai 2010 2
14 oct. 2009 à 13:01
Il y a 1 seul Extended, mais au pire celui-là je peux le passer en String tel qu'il apparait ds le combo et le reformatter dans ma classe métier avant l'appel du Format. Je peux m'arranger pour ne passer que des String.

Par contre je ne comprends ce que tu veux dire ensuite, alors je vais essayer de pas répondre à côté:
-Le nombre d'arguments est fonction de l'indice du compo à charger; donc variable d'un compo à l'autre, mais un même compo aura toujours le même nb de paramètres.

-Que veux-tu dire par "en ajoutant chaque champ "à la main" dans Format"?
0
JeremyLecouvert Messages postés 139 Date d'inscription mardi 27 novembre 2007 Statut Membre Dernière intervention 10 mai 2010 2
14 oct. 2009 à 13:35
Le nombre maximum d'arguments est grosso merdo Length(Compos)-1 (certains compos contiennent des données inutilisées dans les requêtes).

Effectivement, je peux faire comme ça... du coup je passerais systématiquement mes n arguments même si la requête ne prend que les 2 ou 3 premiers?! C'est pas con... peut-être pas super propre, mais pas con. Et puis au moins, ça solutionne très simplement le problème!

Juste un peu déçu de devoir m'avouer vaincu face au TVarRec, mais ce n'est que partie remise...

Un grand merci à toi Bacterius, tu viens de mettre fin à 3 jours de souffrance!!
0
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
14 oct. 2009 à 13:38
Cirec te donne la main pour t'aider à vaincre le TVarRec, profites-en !

Cordialement, Bacterius !
0
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
14 oct. 2009 à 13:42
[quote=JeremyLecouvert]Juste un peu déçu de devoir m'avouer vaincu face au TVarRec, mais ce n'est que partie remise...
/quote
je viens de te donner une solution à ton problème de TVarRec !!!!!
[hr]@+Cirec
[hr]
0
JeremyLecouvert Messages postés 139 Date d'inscription mardi 27 novembre 2007 Statut Membre Dernière intervention 10 mai 2010 2
14 oct. 2009 à 13:52
Wouah.. pas le temps de répondre à Bacterius, et voilà une 2° solution qui arrive! Y Pleut des soluces

@Cirec: En fait, j'ai bien compris le principe des pointeur, mais en pratique j'ai un peu plus de mal... et à vrai dire, je les évite quand je peux! Ceci dit, je comprends maintenant où était mon erreur, et cette solution correspond exactement à ce que je voulais au départ.. Gros merci!

Je laisse la réponse de Bacterius validée, parce qu'elle offre une alternative moins complexe à la question.

Merci à tous les 2!
0
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
14 oct. 2009 à 13:58
Euhm en fait la mienne est plus complexe et moins souple ...

Cordialement, Bacterius !
0
JeremyLecouvert Messages postés 139 Date d'inscription mardi 27 novembre 2007 Statut Membre Dernière intervention 10 mai 2010 2
14 oct. 2009 à 14:13
...Moins souple oui, mais moins complexe dans le sens où tu ne travailles pas sur des pointeurs et que tu laisses le système gérer la mémoire.
0
Rejoignez-nous