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

Messages postés
142
Date d'inscription
mardi 27 novembre 2007
Dernière intervention
10 mai 2010
- 13 oct. 2009 à 09:26 - Dernière réponse :
Messages postés
142
Date d'inscription
mardi 27 novembre 2007
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é...
Afficher la suite 

Votre réponse

19 réponses

Meilleure réponse
Messages postés
3869
Date d'inscription
samedi 22 décembre 2007
Dernière intervention
3 juin 2016
14 oct. 2009 à 13:06
3
Merci
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 !

Merci Bacterius 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 90 internautes ce mois-ci

Commenter la réponse de Bacterius
Meilleure réponse
Messages postés
4229
Date d'inscription
vendredi 23 juillet 2004
Dernière intervention
3 août 2018
14 oct. 2009 à 13:11
3
Merci
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

Merci Cirec 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 90 internautes ce mois-ci

Commenter la réponse de Cirec
Messages postés
142
Date d'inscription
mardi 27 novembre 2007
Dernière intervention
10 mai 2010
13 oct. 2009 à 10:23
0
Merci
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!
Commenter la réponse de JeremyLecouvert
Messages postés
142
Date d'inscription
mardi 27 novembre 2007
Dernière intervention
10 mai 2010
13 oct. 2009 à 16:47
0
Merci
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à?
Commenter la réponse de JeremyLecouvert
Messages postés
3869
Date d'inscription
samedi 22 décembre 2007
Dernière intervention
3 juin 2016
14 oct. 2009 à 04:21
0
Merci
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 !
Commenter la réponse de Bacterius
Messages postés
142
Date d'inscription
mardi 27 novembre 2007
Dernière intervention
10 mai 2010
14 oct. 2009 à 10:02
0
Merci
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...
Commenter la réponse de JeremyLecouvert
Messages postés
3869
Date d'inscription
samedi 22 décembre 2007
Dernière intervention
3 juin 2016
14 oct. 2009 à 10:06
0
Merci
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 !
Commenter la réponse de Bacterius
Messages postés
142
Date d'inscription
mardi 27 novembre 2007
Dernière intervention
10 mai 2010
14 oct. 2009 à 10:26
0
Merci
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).
Commenter la réponse de JeremyLecouvert
Messages postés
142
Date d'inscription
mardi 27 novembre 2007
Dernière intervention
10 mai 2010
14 oct. 2009 à 11:11
0
Merci
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!!
Commenter la réponse de JeremyLecouvert
Messages postés
3869
Date d'inscription
samedi 22 décembre 2007
Dernière intervention
3 juin 2016
14 oct. 2009 à 12:29
0
Merci
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 !
Commenter la réponse de Bacterius
Messages postés
142
Date d'inscription
mardi 27 novembre 2007
Dernière intervention
10 mai 2010
14 oct. 2009 à 12:37
0
Merci
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...
Commenter la réponse de JeremyLecouvert
Messages postés
3869
Date d'inscription
samedi 22 décembre 2007
Dernière intervention
3 juin 2016
14 oct. 2009 à 12:46
0
Merci
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 !
Commenter la réponse de Bacterius
Messages postés
142
Date d'inscription
mardi 27 novembre 2007
Dernière intervention
10 mai 2010
14 oct. 2009 à 13:01
0
Merci
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"?
Commenter la réponse de JeremyLecouvert
Messages postés
142
Date d'inscription
mardi 27 novembre 2007
Dernière intervention
10 mai 2010
14 oct. 2009 à 13:35
0
Merci
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!!
Commenter la réponse de JeremyLecouvert
Messages postés
3869
Date d'inscription
samedi 22 décembre 2007
Dernière intervention
3 juin 2016
14 oct. 2009 à 13:38
0
Merci
Cirec te donne la main pour t'aider à vaincre le TVarRec, profites-en !

Cordialement, Bacterius !
Commenter la réponse de Bacterius
Messages postés
4229
Date d'inscription
vendredi 23 juillet 2004
Dernière intervention
3 août 2018
14 oct. 2009 à 13:42
0
Merci
[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]
Commenter la réponse de Cirec
Messages postés
142
Date d'inscription
mardi 27 novembre 2007
Dernière intervention
10 mai 2010
14 oct. 2009 à 13:52
0
Merci
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!
Commenter la réponse de JeremyLecouvert
Messages postés
3869
Date d'inscription
samedi 22 décembre 2007
Dernière intervention
3 juin 2016
14 oct. 2009 à 13:58
0
Merci
Euhm en fait la mienne est plus complexe et moins souple ...

Cordialement, Bacterius !
Commenter la réponse de Bacterius
Messages postés
142
Date d'inscription
mardi 27 novembre 2007
Dernière intervention
10 mai 2010
14 oct. 2009 à 14:13
0
Merci
...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.
Commenter la réponse de JeremyLecouvert

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.