IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Lazarus Pascal Discussion :

Affichage dans un TDBGrid d'un champ provenant d'un DataSet externe [Lazarus]


Sujet :

Lazarus Pascal

  1. #1
    Membre à l'essai
    Inscrit en
    Avril 2005
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 16
    Points : 16
    Points
    16
    Par défaut Affichage dans un TDBGrid d'un champ provenant d'un DataSet externe
    Bonjour à tous,

    Je développe depuis peu une appli "compagnon" sur Lazarus/FPC chargée d'alimenter une BDD SQLite3 pour une autre appli en C++. Je me heurte à un souci que je n'arrive pas à résoudre.

    Le besoin fonctionnel : (n'hésitez pas à me dire si c'est pas clair )
    J'ai deux recordsets Sqlite3 (TSqlite3DataSet) dans un DataModule, qui pointent sur deux BDD différentes :

    - Un recordset qui pointe sur une table présente dans la BDD "principale", qui regroupe toutes les données de l'appli.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    |    ID     |     Autres     |     Champs     |
    - L'autre recordset qui pointe sur une table "trad", présente dans une autre BDD (chaque langue étant stockée dans un fichier de BDD différente, l'idée étant qu'un autre de mes programmes, qui l'exploite, ne charge que la langue dont il a besoin). La table trad contient trois champs :
    - l'ID de l'élément à traduire (correspond à la clé primaire de mon premier recordset).
    - Un énuméré (integer) qui me permet de faire le lien avec la table à traduire dans la première BDD et qui me sert à filtrer le recordset de trad quand je rentre dans l'écran approprié => toutes les trad sont dans la même table.
    - La chaîne traduite du libellé.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    |    trad_id     |     trad_category     |     trad_label    |
    J'aimerais afficher ce fameux champ libellé dans une colonne de TDBGrid et je ne vois pas comment m'y prendre.

    Ce que j'ai tenté.
    J'ai testé plusieurs approches :

    1. Ne pas paramétrer de fieldDefs sur le recordset principal (donc le laisser construire les champs à partir de la table) puis ajouter un champ calculé à la main.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    Recordset.Open;
    Recordset.FieldDefs.Update; // Pour le forcer à construire ses champs.
    Recordset.Close;
    theField := TStringField.Create(Recordset);
    theField.FieldKind:= fkCalculated;
    theField.Calculated:= true;
    theField.FieldName:= 'libelle';
    theField.DataSet := RecordSet;
    Recordset.OnCalcFields:= @Self.ShowTranslation;
    Puis
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    procedure TAppModel.ShowTranslation(DataSet: TDataSet);
    begin
       str := TSqlite3Dataset(DataSet).PrimaryKey;
       theField := DataSet.FieldByName('libelle');
       myID:= DataSet.FieldByName(str).AsInteger; // Plante en m'indiquant qu'il n'a pas trouvé le champ "id", qui est pourtant dans la table de base puisqu'il s'agit de la clé primaire.
       if RecordsetTrad.Locate('trad_id;trad_category', VarArrayOf([ myID, 12 ]), [ loCaseInsensitive ]) then
       begin
           str := RecordsetTrad.FieldByName('trad_label').AsString;
           theField.AsString:= str;
       end;
    end;
    2. Le même principe mais en renseignant les FieldDefs à la main dans l'inspecteur d'objets plutôt qu'ouvrir une première fois le DataSet pour les remplir automatiquement.

    Là en revanche il parvient à trouver le champ "id", mais pas le champ "libelle"...

    3. Skipper complètement l'aspect recordset et à tenter de paramétrer le champ via le TDBGrid en implémentant l'événement OnDrawCell pour afficher la valeur texte que je souhaite.
    Là j'ai un autre souci : les cellules ne sont tout simplement pas dessinées.

    J'ai clairement le sentiment d'aborder le problème du mauvais sens car ça me paraît "simple" (à priori). Les quelques sujets que j'ai lus sur les champs calculés n'ont fait que me confondre encore davantage.

    Si quelqu'un peut me dépatouiller...

    Merci d'avance !

  2. #2
    Membre éprouvé
    Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2010
    Messages
    469
    Détails du profil
    Informations personnelles :
    Âge : 66
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2010
    Messages : 469
    Points : 1 100
    Points
    1 100
    Par défaut
    Bonjour

    Je ne comprend pas bien ce que tu veux dire avec

    Un énuméré (integer) qui me permet de faire le lien avec la table à traduire dans la première BDD et qui me sert à filtrer le recordset de trad quand je rentre dans l'écran approprié => toutes les trad sont dans la même table.
    Est-ce que la requête suivante, ou similaire, ne retourne pas ce que tu veux obtenir dans ta grille ?

    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT * FROM Base1.Principale P
    JOIN Base2.Trad T ON T.id=P.Id
    WHERE (...)

    Si oui, un seul dataset sur cette requête fera l'affaire, visible dans l'EDI et sans aucun code.

    Et si jamais SQLite est trop "léger" pour permettre les jointures multibases, il y a une solution avec des champs calculés, je te la préciserai si besoin.
    Cordialement,
    Tintinux

    Initiateur de Gestinux, une comptabilité gestion open-source, pour Linux, Windows et Mac OS.
    Une version stable et une autre en développement, avec Lazarus : vous pouvez aider à la tester, la traduire et à la développer.

  3. #3
    Membre expert
    Avatar de e-ric
    Homme Profil pro
    Apprenti chat, bienfaiteur de tritons et autres bestioles
    Inscrit en
    Mars 2002
    Messages
    1 550
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Apprenti chat, bienfaiteur de tritons et autres bestioles

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 550
    Points : 3 916
    Points
    3 916
    Par défaut
    Salut

    J'ai une première question, est-ce le code catégorie est constant au sein du DBGrid (enfin au sein de tous les objets qui font référence à tes ensemble de données) ?
    Dans le cas contraire, je pense qu'il n'y a pas de réelle solution.
    L'utilisation d'un champ calculé dans ta solution ne fonctionne pas car lorsque la valeur du champ est effectivement calculée, l'ensemble de donnée se place dans un état particulier (dsCalcField) où toutes les opérations ne sont pas permises (souvenirs dans Delphi...)

    La solution de Tintinux est correcte si
    - ton DBGrid ne fait que de l'affichage et pas de modification,
    - et effectivement tu peux faire des requêtes multi-base (pas de bol pour SQLite).

    Si j'ai bien compris, tu veux que ta table principale fasse référence à ta table de traduction. Dans ce cas, il ne faut pas utiliser un champ calculé mais un champ de référence (theField.FieldKind := fkLookup) et définir les propriétés qui vont bien (cherche dans la doc), il faut choisir la clé de référence trad_id et le champ qui fait référence ID, cela suppose que tu puisses rendre constant le champ trad_category en ajoutant un critère de sélection supplémentaire à l'ouverture de ton ensemble de données de traduction:

    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
       SELECT trad_id,trad_label
       FROM TRAD_TABLE 
       WHERE trad_category = :TRAD_CAT
    et tu passes 12 au paramètre TRAD_CAT à l'ouverture de ton ensemble de données.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    // Code donné à titre indicatif, pas testé
      rsTrad.ParamByName('TRAD_CAT').AsInteger := 12;
      rsTrad.Open;
    Cela doit fonctionner y compris avec des tables provenant de bases différentes, mais je n'ai pas vérifié.

    @+

    M E N S . A G I T A T . M O L E M
    Debian 64bit, Lazarus + FPC -> n'oubliez pas de consulter les FAQ Delphi et Pascal ainsi que les cours et tutoriels Delphi et Pascal

    "La théorie, c'est quand on sait tout, mais que rien ne marche. La pratique, c'est quand tout marche, mais qu'on ne sait pas pourquoi. En informatique, la théorie et la pratique sont réunies: rien ne marche et on ne sait pas pourquoi!".
    Mais Emmanuel Kant disait aussi : "La théorie sans la pratique est inutile, la pratique sans la théorie est aveugle."

  4. #4
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 844
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 844
    Points : 11 274
    Points
    11 274
    Billets dans le blog
    6
    Par défaut
    Citation Envoyé par e-ric
    La solution de Tintinux est correcte si ... tu peux faire des requêtes multi-bases (pas de bol pour SQLite).
    Grâce à la commande ATTACH, on peut ouvrir plusieurs bases dans SQLite.
    Delphi 5 Pro - Delphi 10.4 Rio Community Edition - CodeTyphon 6.90 sous Windows 10 ; CT 6.40 sous Ubuntu 18.04 (VM)
    . Ignorer la FAQ Delphi et les Cours et Tutoriels Delphi nuit gravement à notre code !

  5. #5
    Membre expert
    Avatar de e-ric
    Homme Profil pro
    Apprenti chat, bienfaiteur de tritons et autres bestioles
    Inscrit en
    Mars 2002
    Messages
    1 550
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Apprenti chat, bienfaiteur de tritons et autres bestioles

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 550
    Points : 3 916
    Points
    3 916
    Par défaut
    je ne savais pas, merci donc à Yves pour cette info. Je n'ai pas fait beaucoup de dév avec SQLite.

    @+

    M E N S . A G I T A T . M O L E M
    Debian 64bit, Lazarus + FPC -> n'oubliez pas de consulter les FAQ Delphi et Pascal ainsi que les cours et tutoriels Delphi et Pascal

    "La théorie, c'est quand on sait tout, mais que rien ne marche. La pratique, c'est quand tout marche, mais qu'on ne sait pas pourquoi. En informatique, la théorie et la pratique sont réunies: rien ne marche et on ne sait pas pourquoi!".
    Mais Emmanuel Kant disait aussi : "La théorie sans la pratique est inutile, la pratique sans la théorie est aveugle."

  6. #6
    Membre à l'essai
    Inscrit en
    Avril 2005
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 16
    Points : 16
    Points
    16
    Par défaut
    Bonjour à tous,

    Avant tout merci pour ces réponses. Je suis parvenu à ce que je désirais en utilisant une jointure multi-base couplée avec la commande ATTACH DATABASE. Effectivement, j'étais loin d'imaginer qu'SQLite permettait ce genre d'opérations. J'ai été agréablement surpris

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    recordset.ExecSQL('ATTACH DATABASE "' + TradDBPath + '" AS tradDB');
    recordset.Open;
    Pour te répondre, e-ric, oui, la catégorie était bel et bien fixe au DataSet, donc j'ai complété avec un WHERE et ça passe. J'aurais probablement tenté de créer un champ lookup si la jointure multi-base n'avait pas marché.

    Dans tous les cas, un grand merci à tous pour votre réactivité

    J'ai, avant de clore le sujet, une question subsidiaire sur les champs calculés / lookup / etc., et la manière de les paramétrer.

    Je m'étais borné, bêtement, dans l'inspecteur d'objets, à voir un "FieldDefs" dans le DataSet qui m'évoquait vaguement la possibilité de définir des champs de manière statique (sans laisser le DataSet les construire automatiquement). En essayant de le compléter je me suis heurté à pas mal de soucis (et notamment le fait qu'il ne me reconnaissait plus mes champs !). J'ai remarqué, un peu tard () qu'un clic-droit sur le DataSet me permettait de rajouter des champs. Quelle est la différence entre les fieldDef et les field ?

    Du coup, si je voulais à l'avenir gérer des champ calculés, quelle méthode devrais-je choisir ? Ajouter mon champ par programmation avec un T***Field.Create puis l'ajouter aux DataSet.Fields ? L'ajouter dans les champs statiquement via le form builder ?

    En vous remerciant d'avance.

  7. #7
    Membre expert
    Avatar de e-ric
    Homme Profil pro
    Apprenti chat, bienfaiteur de tritons et autres bestioles
    Inscrit en
    Mars 2002
    Messages
    1 550
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Apprenti chat, bienfaiteur de tritons et autres bestioles

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 550
    Points : 3 916
    Points
    3 916
    Par défaut
    Salut

    1- Selon l'aide de Lazarus
    TFieldDef = "Class to describe one field in a record in a dataset"
    TField = "Provide access to the contents of a single field in a record"

    En gros, TFieldDef est la description physique du champ sans donner directement accès à son contenu, leur interface est très limitée et il ne permettent pas par exemple de définir des champs de référence. Les TField offrent des services évolués supportés directement par la LCL indépendamment du SGBD sous-jacent (par exemple les champs de référence). Dans le pratique, l'accès par le code applicatif aux TFieldDef est rare, ce sont les TField qui sont importants de ce point de vue.
    En interne, tout TField correspondant à un champ physique de la table est associé à un TFieldDef.

    2- Champ de référence
    Relation entre deux ensemble de données, dstSource et dstReferente (qui utilise la référence), l'ajout du champ de référence se fait au sein de dstReferente, il faut donc définir la table source :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    dstReferente.LookupDataSet := dstSource;
    Il faut ensuite mettre en relation les champs qui définissent la jointure entre ces deux ensembles:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
      dstReferente.KeyFields := 'ID'; // dans ton exemple, cette propriété contient la liste des noms de champs séparés par des ';'.
      dstReferente.LookupKeyFields := 'trad_id'; // dans ton exemple, cette propriété contient la liste des noms de champs séparés par des ';'.
    Attention les deux listes de champs doivent contenir autant de champs et l'ordre de ces champs définit la jointure.
    Enfin, tu définis la propriété:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    dstReferente.LookupResultField := 'trad_label';
    qui est la donnée accessible par le champ ainsi créée.

    3- En ce qui concerne les champs calculés, je ne suis plus trop sûr et je n'ai pas d'exemple immédiatement utilisable pour aller vérifier, je pense qu'il est possible de définir un champ calculé à l'exécution, en s'assurant que l'ensemble de données est fermé (dsInactive). L'ajout statique à la conception est plus pratique mais il nécessite de "figer" l'ensemble de données à ce moment, en effet, la définition de la liste de champs produit des champs persistants manipulables en conception mais cela colle l'objet DataSet à cet ensemble de donnés à l'exécution (je sais pas si mon explication c'est bien clair), cela interdit de changer l'ensemble de données à l'exécution.


    Cdlt

    M E N S . A G I T A T . M O L E M
    Debian 64bit, Lazarus + FPC -> n'oubliez pas de consulter les FAQ Delphi et Pascal ainsi que les cours et tutoriels Delphi et Pascal

    "La théorie, c'est quand on sait tout, mais que rien ne marche. La pratique, c'est quand tout marche, mais qu'on ne sait pas pourquoi. En informatique, la théorie et la pratique sont réunies: rien ne marche et on ne sait pas pourquoi!".
    Mais Emmanuel Kant disait aussi : "La théorie sans la pratique est inutile, la pratique sans la théorie est aveugle."

  8. #8
    Membre éprouvé
    Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2010
    Messages
    469
    Détails du profil
    Informations personnelles :
    Âge : 66
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2010
    Messages : 469
    Points : 1 100
    Points
    1 100
    Par défaut
    Du coup, si je voulais à l'avenir gérer des champ calculés, quelle méthode devrais-je choisir ? Ajouter mon champ par programmation avec un T***Field.Create puis l'ajouter aux DataSet.Fields ? L'ajouter dans les champs statiquement via le form builder ?
    Bonjour,

    Les deux sont possibles, et c'est une force de l'outil !

    En général, il est plus facile d'utiliser le designer pour ajouter tous les champs, y compris ceux qui sont calculés.

    Pour des besoins pointus, il est parfois nécessaire de définir les champs par code, mais à mon avis personnel il faut mieux éviter, surtout quand on débute.
    Cordialement,
    Tintinux

    Initiateur de Gestinux, une comptabilité gestion open-source, pour Linux, Windows et Mac OS.
    Une version stable et une autre en développement, avec Lazarus : vous pouvez aider à la tester, la traduire et à la développer.

  9. #9
    Membre à l'essai
    Inscrit en
    Avril 2005
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 16
    Points : 16
    Points
    16
    Par défaut
    Salut à tous (avec un peu de retard ^^")

    Merci beaucoup pour ces informations, mon souci est résolu

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Left join, champ null et affichage dans etat
    Par catoucat dans le forum Access
    Réponses: 3
    Dernier message: 03/07/2006, 03h58
  2. [Tableaux] affichage dans un champ est tronqué
    Par harlock59 dans le forum Langage
    Réponses: 4
    Dernier message: 21/02/2006, 22h39
  3. Réponses: 5
    Dernier message: 03/02/2006, 11h45
  4. [JTextField] Problème d'affichage dans un champ ...
    Par mitje dans le forum Composants
    Réponses: 2
    Dernier message: 01/02/2006, 16h41
  5. Verifier un champ a l affichage dans un etat
    Par virtuose dans le forum Access
    Réponses: 5
    Dernier message: 19/01/2006, 19h18

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo