DBGrid et Calculated field

Résolu
prehistoric Messages postés 19 Date d'inscription vendredi 6 avril 2007 Statut Membre Dernière intervention 6 mai 2009 - 10 avril 2009 à 16:20
cs_cantador Messages postés 4720 Date d'inscription dimanche 26 février 2006 Statut Modérateur Dernière intervention 31 juillet 2021 - 17 avril 2009 à 14:59
Bonjour à tous.
Mon dataset principale est une TOraTable et est du type:
field1 field2 ... ChoixTaille...

ChoixTaille appartenant à (Petite, Moyenne, Grande)

La dataset secondaire contient:
field1 field2 ... PetiteTaille MoyenneTaille GrandeTaille....

Mon but est d'afficher le champ taille dans une colonne de JvDBGRID, avec une combo contenant (PetiteTaille,MoyenneTaille,GrandeTaille).

La picklist de la colonne est donc fonction de la ligne où on est: jusque là pas de problème, je réagis à l'évènement "AfterScroll" pour réactulaiser la picklist. Pour initialiser, j'implémente OnCalcFields et tout marche bien.
Le problème c'est qu'un click sur la combo affiche la liste des valeurs possibles, mais le choix de la valeur en question n'est pas pris en compte. En fait la seule façon d'agir sur la valeur est de modifier celle ChoixTaille(qui ne doit pas etre visible).

NB:Pour créer la colonne, je dois la relier à un field, j'ai donc choisi un calculated field: première erreur? (En regardant je vois que le field.canmodify (propriété readonly) est à false)

24 réponses

prehistoric Messages postés 19 Date d'inscription vendredi 6 avril 2007 Statut Membre Dernière intervention 6 mai 2009
16 avril 2009 à 20:10
Bon j'ai créé cette table, 'TChoixImmersionTable':

IDBOUEE  SCHOIXIMMERSION     LIBELLEIMMERSION        IMMERSION
1                                 C                                     Courte                            30
1                                 I                                    Intermédiaire                     50
1                                 L                                     Longue                            300
2                                 C                                     Courte                            350

2                                 I                                    Intermédiaire                     500

2                                 L                                     Longue                            500
3                                 C                                     Courte                            300

3                                 I                                    Intermédiaire                     310

3                                 L                                     Longue                            320
.......

J'ai créé un DBLookupCombo paramétré comme suit:
DataSource->TReserve
DataField->SchoixImmersion
KeyField->SchoixImmersion
ListSource->TChoixImmersionTable
ListFields->LIBELLEIMMERSION;  IMMERSION

En m'inspirant largement de ce site:
http://delphi.about.com/od/usedbvcl/l/aa092703a.htm

La lookup influe directement sur la colonne 'SchoixImmersion' même si cette dernière est invisible. En gardant le calculated field défini dans les premiers post, j'arrive enfin à ce que je voulais. 
Ah oui la table  TChoixImmersionTable est filtré sur le AfterScroll de TReserv pour afficher uniquement les bonnes valeurs dans la lookup.

On a ce résultat, pour IDBOUEE =1:

Courte              30
Intermédiaire     50
longue               300
 
Lors du choix et '30' comme affichage si on choisit courte par exemple.
Est-ce que c'est une super solution? Probablement pas, mais ça marche très bien.

Merci donc à Cantador pour son aide inestimable.

   
3
prehistoric Messages postés 19 Date d'inscription vendredi 6 avril 2007 Statut Membre Dernière intervention 6 mai 2009
10 avril 2009 à 16:21
J'ai juste oublié de dire merci à tous ceux qui éventuellement me fileront un coup de main!
0
cs_cantador Messages postés 4720 Date d'inscription dimanche 26 février 2006 Statut Modérateur Dernière intervention 31 juillet 2021 13
11 avril 2009 à 12:05
bonjour,

il faut différencier les opération réalisées en mode "lecture seule" qui peuvent déboucher sur des sélections particulières et les autres celles effectuées en mode "edition" qui elles doivent subir un traitement spécial (post, commit, rollback etc..) afin d'être stockées définitivement.

cantador
0
prehistoric Messages postés 19 Date d'inscription vendredi 6 avril 2007 Statut Membre Dernière intervention 6 mai 2009
14 avril 2009 à 14:22
Merci de ta réponse, ça a pu relancer ma réflexion.

Juste pour repartir du début: ai-je raison d'utiliser un Calculated Field?

Si oui, voici le code que j'ai fait dans onCalcFields (pas en entier, en fin de page).
Le "if fisrtload" est censé faire l'initialisation, et ça semble marcher: les données sont bien écrites, affichées dans le grid, et accessibles ailleurs, mais ça crée une sorte de relation de dépendance, qui fixe de manière permanente la colonne "immersion" par la valeur de "SchoixImmersion", pas juste à l'initialisation. Le "else" n'est jamais rappelé (et même si c'est le cas, ça ne donne pas le résultat escompté: ça vide simplement la colonne "Immersion").

 A noter aussi que l'évènement "Onchange" du field immersion n'est jamais lancé non plus.
Ah, une mise en edit du dataset relance OnCalcFields, et là plus de valeurs dans le champ "Immersion".

J'ai l'impression, mais je me gourre surement, que le calculated field est forcément esclave mais pas maître d'un autre champ (c'est ce que je voudrais faire, commander la valeur de SchoixImmersion en fonction de celle de Immersion).

Merci de ta patience.

procedure TDMEmport.TBsouteCalcFields(DataSet: TDataSet);
var idbouee:integer;
begin
if firstload then
begin
if DataSet.FieldValues['SCHOIXIMMERSION']='C' then
DataSet.FieldValues['Immersion']:=DMEmport.QryImmersionDureeVieValues.FieldValues['SIMMERSIONCOURTE']
else if DataSet.FieldValues['SCHOIXIMMERSION']='I' then
DataSet.FieldValues['Immersion']:=DMEmport.QryImmersionDureeVieValues.FieldValues['SIMMERSIONINTERMEDIAIRE']
else if DataSet.FieldValues['SCHOIXIMMERSION']='L' then
DataSet.FieldValues['Immersion']:=DMEmport.QryImmersionDureeVieValues.FieldValues['SIMMERSIONLONGUE'];

else
begin

if DataSet.FieldValues['Immersion']=DMEmport.QryImmersionDureeVieValues.FieldValues['SIMMERSIONCOURTE'] then
DataSet.FieldValues['SCHOIXIMMERSION']:='C'
else if DataSet.FieldValues['Immersion']=DMEmport.QryImmersionDureeVieValues.FieldValues['SIMMERSIONINTERMEDIAIRE'] then
DataSet.FieldValues['SCHOIXIMMERSION']:='I'
else if DataSet.FieldValues['Immersion']=DMEmport.QryImmersionDureeVieValues.FieldValues['SIMMERSIONLONGUE'] then
DataSet.FieldValues['SCHOIXIMMERSION']:='L' ;

end;
0

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

Posez votre question
cs_cantador Messages postés 4720 Date d'inscription dimanche 26 février 2006 Statut Modérateur Dernière intervention 31 juillet 2021 13
14 avril 2009 à 14:41
Non, au vu du code, la méthode est mauvaise.
on ne fait jamais autant de tests dans un OnCalcFields..
->>> beaucoup trop lourd

Quand on a ce type de problème c'est que l'analyse a été insuffisante.
Alors on essaie de compenser ce manque de manière artificielle..

Autrement dit, il existe sûrement une table cachée que tu n'as pas vue :

il faut donc traiter ce souci en créant une table avec tous les cas de figure se présentant et établir une relation (peut-être 1-N) entre celle-ci et la table principale.
et dans ce cas, il n'y a plus rien à traiter puisque l'information s'affichera automatiquement en fonction de la règle établie entre ces tables.

cantador
0
prehistoric Messages postés 19 Date d'inscription vendredi 6 avril 2007 Statut Membre Dernière intervention 6 mai 2009
14 avril 2009 à 15:41
Si j'ai bien compris ce que j'ai lu (oui premier projet en BD sans formation...), la relation 1-N dont tu parles est déjà en place.
Je m'explique:
Base principale = réserve de bouées:
fields: IDRES IDBOUEE .... SCHOIXIMMERSION ....

contrainte sur SCHOIXIMMERSION :appartient à (C,I,L) pour (Court, intermmediaire, long)

Base secondaire= liste des bouées
fields: IDBOUEE .... IMMERSIONCOURTE    IMMERSIONMINTERMEDIAIRE   IMMERSIONLONGUE

Quand on est sur un enregistrement de la réserve, on a tout ce qu'il faut pour aller rechercher la valeur voulue de l'immersion. Ce que je fait d'ailleurs en chargeant la picklist en fct de la ligne courante, ou en initialisant la valeur de Immersion.

Peut-être suggères tu qu'avoir un système du type "Schoix..." qui renvoie à choisir entre trois paramètres n'est pas du tout standard ou propre? Si c'est le cas je dois malheureusement faire avec .

Suggères-tu une table supplémentaire de type:
fields: IDBOUEE   SCHOIXIMMERSION   IMMERSION ?
Je crois en effet que ça me faciliterai les choses.

Merci pour tes réponses, apprendre à manier delphi et les BD en même temps c'est un peu hard...
0
cs_cantador Messages postés 4720 Date d'inscription dimanche 26 février 2006 Statut Modérateur Dernière intervention 31 juillet 2021 13
14 avril 2009 à 16:37
qui renvoie à choisir entre trois paramètres



Est ce que choix dépend uniquement de l'initiative de l'utilisateur (en fonction du contexte bien sûr) ou d'autres critères ?

cantador
0
cs_cantador Messages postés 4720 Date d'inscription dimanche 26 février 2006 Statut Modérateur Dernière intervention 31 juillet 2021 13
14 avril 2009 à 16:41
pourrais-tu faire un logigramme?

cantador
0
prehistoric Messages postés 19 Date d'inscription vendredi 6 avril 2007 Statut Membre Dernière intervention 6 mai 2009
14 avril 2009 à 17:47
Je t'ai envoyé des mp, ainsi que mon adresse mail pour me faciliter la vie : j'arrive pas a ajouter de pièce jointe à mon texte.
0
prehistoric Messages postés 19 Date d'inscription vendredi 6 avril 2007 Statut Membre Dernière intervention 6 mai 2009
14 avril 2009 à 18:16
J'ai réussi!
Pour ceux que ça intéresserait:

il faut bien une table du type:
fields: IDBOUEE SCHOIXIMMERSION IMMERSION

On crée un champ "lookup" dans la table principale qui vise IMMERSION, avec comme clé SCHOIXIMMERSION.

Sur le "AfterScroll" On filtre la table créée avec le bon IDBOUEE (récupéré de la table principale) pour avoir la bonne picklist (les valeurs seront bonnes mais la picklist contiendra toutes les valeurs d'immersion, sans filtrer par IDBOUEE)

Si vous ne pouvez pas créer de nouvelle table (comme moi d'ailleurs), l'objet "VirtualTable" fera peut-être l'affaire.
0
prehistoric Messages postés 19 Date d'inscription vendredi 6 avril 2007 Statut Membre Dernière intervention 6 mai 2009
15 avril 2009 à 11:04
Bon j'avais pas validé parce que je soupçonnais qqch et effectivement, ça ne marche pas!

L'étape de filtrage sur le "AfterScroll" est une belle bêtise car alors toutes les lignes non concernées prennent aussi la valeur filtrée (en gros toutes les lignes courtes affichent la même valeur, idem pour les longues...)
0
cs_cantador Messages postés 4720 Date d'inscription dimanche 26 février 2006 Statut Modérateur Dernière intervention 31 juillet 2021 13
15 avril 2009 à 11:18
Revois ma première réponse sur ton post.
Attention, à bien faire le distinguo entre un affichage résultant de données stockées dans une table (celui ne doit pas bouger) et une saisie avec un choix possible avec derrière une validation.
un champ calculé, ce n'est que de l'affichage..

cantador
0
prehistoric Messages postés 19 Date d'inscription vendredi 6 avril 2007 Statut Membre Dernière intervention 6 mai 2009
15 avril 2009 à 11:42
Pour le coup, on est plus avec un champ calculé mais avec un "lookup".
Le problème est qu'un lookup classique, c'est un ID présent dans les deux qui te permet d'aller chercher ton résultat. Moi c'est IDBOUEE + SCHOIXIMMERSION qui me permettent d'identifier la valeur de IMMERSION dans la table nouvellement créée. J'ai essayé de mettre plusieurs champs en clé du lookup mais ça plante.

J'ai donc fait un lookup classique avec comme clé SCHOIXIMMERSION et j'ai cherché un moyen faire un second "filtrage" : si le Dbgrid "sait" quelle est la valeur de l'IDBOUEE correspondant à la ligne, la picklist contient quand même toutes les valeurs de IMMERSION. Pour l'instant sans succès.

Au bilan pour l'instant:
-Avec un calculated field, impossibilité de modifier la valeur directement cliquant un élément de la picklist (obligé de commander via SCHOIXIMMERSION)
-Avec un lookup, impossibilité de restreindre la picklist ce qui m'a conduit à essayer pas mal de bêtises.
0
cs_cantador Messages postés 4720 Date d'inscription dimanche 26 février 2006 Statut Modérateur Dernière intervention 31 juillet 2021 13
15 avril 2009 à 11:56
qui me permettent d'identifier la valeur de IMMERSION dans la table

Est-ce que cette valeur doit être stockée ou volatile ?

cantador
0
prehistoric Messages postés 19 Date d'inscription vendredi 6 avril 2007 Statut Membre Dernière intervention 6 mai 2009
15 avril 2009 à 12:05
Et bien la construction de la table virtuelle ne semble pas gêner au niveau performances, je peux donc travailler avec cet objet comme s'il s'agissait d'une table classique.

La valeur est donc stockée dans la table virtuelle, qui est construite à chaque chargement de l'application (pour le moment). Cette table ne sert qu'à lire, on n'y écrit rien.

Seule la valeur de SCHOIXIMMERSION est modifiée en base principale. Mais jamais les valeurs possibles de IMMERSION (IMMERSIONCOURTE, IMMERSIONINTERMEDIAIRE, IMMERSIONLONGUE) ne seront modifiées (et donc la table virtuelle non plus).
0
cs_cantador Messages postés 4720 Date d'inscription dimanche 26 février 2006 Statut Modérateur Dernière intervention 31 juillet 2021 13
15 avril 2009 à 14:10
Hou là là attention au vocabulaire !

La valeur est donc stockée
dans la table virtuelle, qui est construite à chaque chargement de l'application (pour le moment). Cette table ne sert qu'à lire, on n'y écrit rien.



Tu dis tout et son contraire, ce n'est donc pas un stockage !

Seule la valeur de SCHOIXIMMERSION est modifiée en base principale.
là, on comprend qu'il y a stockage..

et quand tu parles de table vituelle (ça n'existe pas..)
si tu stockes des données dans un  items par exemple
on parle de Table interne.

Déjà que tu n'a fourni aucune explication sur le contexte...

Il faut d'abord bien expliquer ce à quoi on veut arriver et non déjà fournir une solution qui embrouille plus qu'autre chose..

Je sais c'est pas facile...

cantador
0
prehistoric Messages postés 19 Date d'inscription vendredi 6 avril 2007 Statut Membre Dernière intervention 6 mai 2009
15 avril 2009 à 14:46
Pour les erreurs de vocabulaire, désolé je ne suis pas du tout spécialiste des BD : pour moi quand on met des valeurs dans un variable (en l'occurrence la table interne), on "stocke". Je vais essayer d'améliorer ça mais honnêtement c'est pas gagné (je serai toujours pas spécialiste des BD ce soir ou demain).

Par contre pour les deux autres remarques, je voudrais un peu plus d'explications:

------Déjà que tu n'a fourni aucune explication sur le contexte...
Il y a le langage (Delphi), la description des tables (pas assez précise?), le type d'objet utilisé(TOraTable, JVDbGrid). A ce niveau je ne vois pas d'informations que j'utiliserai que je n'ai pas fourni. Que te manque-t-il?

---------Il faut d'abord bien expliquer ce à quoi on veut arriver
Il me semble l'avoir fait mais je vais reprendre (avec des screens ce serait plus facile mais je n'arrive pas à les mettre). C'est sur que vu que j'ai tout devant les yeux toute la journée j'omets peut etre des trucs.

J'ai une table représentant ma réserve de bouées qui contient entre autre champs:
-IBRES:l'id de la bouée dans la réserve.
-IDBOUEE: l'id de la bouée dans sa propre table
-CHOIXIMMERSION: appartient à (C,I,L): sert à déterminer si la valeur d'immersion utilisée devra être 'immersioncourte' 'immersionintermediaire' 'immersionlongue'

J'ai une autre qui contient tous les types de bouées:
-IDBOUEE: l'id de la bouée
-immersioncourte
-immersionintermediaire
-immersionlongue


Je lie un JvDBGRID à la table réserve, et j'affiche donc une liste de bouées dans une réserve. Entre autres colonnes, on a le champ "SChoixImmersion", qui est un lookup, où on peut choisir entre C, I, ou L pour chaque bouee.

Ce que je veux c'est remplacer cette colonne par une ou on choisirait entre 'immersioncourte', 'immersionintermediaire' ou 'immersionlongue'. Ces valeurs dépendront bien sûr de la ligne où on se trouve puisqu'on est pas toujours sur le même type de bouée la même. Un chooix sur cette nouvelle colonne devra mettre a jour 'SChoixImmersion' pour permmettre son stockage.

-----et non déjà fournir une solution qui embrouille plus qu'autre chose..
Si j'arrive en disant, "j'ai besoin de faire ça, vous pouvez me le faire?", c'est réellement mieux? Après je comprends que ça biaise ton approche et que je t'empêche de créer une solution en t'enfermant peut-être dans un truc voué à l'échec.

Merci encore de ta sollicitude, ça commence à me filer le bourdon ce pb...
0
cs_cantador Messages postés 4720 Date d'inscription dimanche 26 février 2006 Statut Modérateur Dernière intervention 31 juillet 2021 13
15 avril 2009 à 14:55
Bon je modélise le tout et je te fais signe...

cantador
0
cs_cantador Messages postés 4720 Date d'inscription dimanche 26 février 2006 Statut Modérateur Dernière intervention 31 juillet 2021 13
15 avril 2009 à 15:41
Voilà le modèle pas compliqué hein..

mais rien que là, on voit de suite que la même info est à deux endroits..
car ChoixImmersion  = TypeBouee


Donc, il faut virer le choixImmersion dans TReserve et ajouter un autre champ dans TTypeBouee comme ceci :


IdBouee ->> clé primaire integer
TypeBoue->> champ texte (Varchar de 1) qui contiendra C, I ou L
et
LibelleTypeBouee ->>> VarChar de 25 qui contiendra (Immersion courte, immersion intermédiaire, immersion longue)
la table TTypeBouee a donc 3 enregistrements.


Que reste t-il à faire ?


Mettre en place dans le DBGrid un DBlookupComboBox qui fait apparaître en MODE EDITION et sur le clic
une liste déroulante montrant à la fois le type de bouée et son libellé juste à côté :


type de bouée    libellé type bouee
C                      Immersion courte 
I                       Immersion intermédiaire 
L                      Immersion longue

ex :


facilitant ainsi la saisie de l'utilisateur et ce n'est donc plus le choix en toutes lettres qui est stocké dans la table TReserve mais l'ID de type bouee (c'est-à-dire 1, 2 ou 3 dans ton cas de figure)


Ce qui laisse une grande souplesse quant à la rédaction des libellés entre autre..

avec un TcxGrid le dbLookupCombox se fait très simplement.
avec un TDBGrid qui est pauvre c'est un peu plus compliqué..

cantador
0
prehistoric Messages postés 19 Date d'inscription vendredi 6 avril 2007 Statut Membre Dernière intervention 6 mai 2009
15 avril 2009 à 16:58
Je suis désolé, je suis un peu pommé, et je vais malheureusement poser des questions bêtes.


La table TTypeBouee est une nouvelle ou c'est la meme que celle qui contient tous les types de bouée?
(cf message précédent :
-IDBOUEE: l'id de la bouée
-immersioncourte
-immersionintermediaire
-immersionlongue )
Je vais supposer que c'est une nouvelle sinon la suite n'a pas de sens pour moi

------LibelleTypeBouee ->>> VarChar de 25 qui contiendra (Immersion courte, immersion intermédiaire, immersion longue)

Il s'agit bien de stocker les valeurs correspondantes et non le texte 'Immersion courte, immersion intermédiaire, immersion longue'? Je dois concaténer les trois valeurs dans un seul champ, ou tu voulais dire appartient à l'une des trois valeurs?

au final, la liste déroulante doit ressembler par exemple à:
type de bouée libellé type bouee
C 30
I 50
L 100

avec dans l'exemple 'immersioncourte'=30, 'immersion intermediare'=50, 'immersion longue'=100 pour l'IDBOUEE correspondant à la sélection dans le Grid.

-------la table TTypeBouee a donc 3 enregistrements.
Moi j'aurai dit qu'il y a trois enregistrements (soit trois "lignes") par IDBouee différent (un pour C, un pour I, un pour L) mais si tu as souligné c'est que justement c'est pas ça...

Je vais te donner un exemple de data pour les tables de départ, tu peux mettre la table TTypesBouées correspondante stp, parce que j'ai du mal à me la représenter (surtout avec seulement trois enregistrements)?

Voici la table réserve, sauf que tu proposes d'en retirer choiximmersion.
TReserve:
IRES IDBOUEE CHOIXIMMERSION
1 3 C
2 3 I
3 3 C
4 5 L

Voici les types de bouee comme je les ai actuellement:
TLesBouees:
IDBOUEE IMMERSIONCOURTE IMMERSIONINTERMEDIAIRE IMMERSIONLONGUE
1 ... ... ...
2 ... ... ...
3 30 50 100
4 ... ... ...
5 200 300 400
0
Rejoignez-nous