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

 Delphi Discussion :

Remplir la seconde combobox vide la première


Sujet :

Delphi

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Apprenti
    Inscrit en
    Octobre 2011
    Messages
    44
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Apprenti
    Secteur : Enseignement

    Informations forums :
    Inscription : Octobre 2011
    Messages : 44
    Points : 29
    Points
    29
    Par défaut Remplir la seconde combobox vide la première
    Bonjour,

    Je suis chargé de maintenir et d'effectuer des modifications sur un code que je n'ai pas créé, et je sèche sur un souci de combo box.
    Je vous expose le problème, peut-être est-il connu, et si besoin par la suite, j'apporterai des détails sur la manière dont sont remplies ces deux combo box, et que je ne maîtrise pas totalement.

    La première combo box est remplie par une requête qui permet d'afficher les établissements en fonction des droits de l'utilisateur.
    La seconde combo box est remplie par une autre requête, pour afficher des entités, entités dépendant de l'établissement.

    Le souci que je rencontre ne se produit qu'au premier choix. Par défaut, j'ai un établissement sélectionné, quand je clique sur la combo box des entités, j'ai bien la liste de mes entités, et si j'en sélectionne une, la combo box de l'établissement devient vide. Si je retourne sélectionner un établissement, je n'ai alors plus aucun souci. Je vois les entités, je peux les sélectionner sans perdre mon établissement, je peux changer d'établissement...
    J'ai un événement OnClosePopup sur la combo box établissement qui remplit la seconde combo box, celle des entités. Je n'ai aucun événement sur la combo box des entités qui permettrait d'aller vider la combo box des établissements. Et comme en plus, ça ne se produit qu'au premier choix, je suis perplexe.

    Est-ce que quelqu'un aurait une idée de ce qui pourrait provoquer cela ?

    Les deux combo box sont remplies par des livebindings, et j'ai des bindsources différent dans DataSource et FillDataSource. Quelle est la différence entre les deux ? Est-ce que le souci pourrait venir de là ?

    D'avance, merci pour vos réponses.

  2. #2
    Expert confirmé
    Avatar de popo
    Homme Profil pro
    Analyste programmeur Delphi / C#
    Inscrit en
    Mars 2005
    Messages
    2 669
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Analyste programmeur Delphi / C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 2 669
    Points : 5 238
    Points
    5 238
    Par défaut
    Le choix de l'établissement par défaut est-il fait après ou avant le binding ?
    Sinon sans le code derrière ces combos, c'est compliqué de dire où se situe ton anomalie...

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    Apprenti
    Inscrit en
    Octobre 2011
    Messages
    44
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Apprenti
    Secteur : Enseignement

    Informations forums :
    Inscription : Octobre 2011
    Messages : 44
    Points : 29
    Points
    29
    Par défaut
    Ici, le code pour l'établissement. Pour la combo box établissement, j'ai le FillDataSource qui est sur qryEtablissement, et le DataSource sur qryEnteteCde. Lequel des deux remplit la combo box ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    procedure TfrmFicheCommande.FormShow(Sender: TObject);
    var
      chaine, rqt : string;
      sl : TStringList;
      i : integer;
    begin
      // début des requêtes commandes
      rqt := 'select ct_num, ct_intitule from f_comptet where ct_type = 0 and ct_sommeil = 0 ';
      qryEtablissement.SQL.Text := rqt;
      sl := TStringList.Create;
      sl.Delimiter := ';';
      sl.StrictDelimiter := True;
      if (frmAccueilCommandes.qryDroitsEcriture.fieldbyname('listeEtablissement').AsString = '*') then
      begin
        qryEtablissement.Active := true;
      end
      else
      begin
        qryEtablissement.SQL.add('and ct_num in ( ');
        sl.DelimitedText := frmAccueilCommandes.qryDroitsEcriture.fieldbyname('listeEtablissement').AsString;
        for i := 0 to sl.Count - 2 do
        begin
          if (i = sl.Count -2) then
            qryEtablissement.SQL.add(quotedstr(sl[i]))
          else
            qryEtablissement.SQL.add(quotedstr(sl[i]) + ',');
        end;
        if frmAccueilCommandes.qryDroitsEcriture.fieldbyname('listeEntite').AsString = '*' then
        begin
          qryEtablissement.sql.Add(')');
          qryEtablissement.Active := true;
        end
        else
        begin
          qryEtablissement.sql.Add(') or ct_num in (select ct_num from f_livraison where li_no in (');
          sl.DelimitedText := frmAccueilCommandes.qryDroitsEcriture.fieldbyname('listeEntite').AsString;
          for i := 0 to sl.Count - 2 do
          begin
            if (i = sl.Count -2) then
              qryEtablissement.SQL.add(quotedstr(sl[i]))
            else
              qryEtablissement.SQL.add(quotedstr(sl[i]) + ',');
          end;
     
          qryEtablissement.sql.Add('))');
          qryEtablissement.Active := true;
        end;
      end;
    Idem ici : le FillDataSource est sur qryGDV et le DataSource sur qryEnteteCde. Je suppose, dans les deux cas, que c'est le FillDataSource qui remplit (fill) la combo box. Mais à quoi sert le DataSource ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    procedure TfrmFicheCommande.cbEtablissementClosePopup(Sender: TObject);
    var
      chaine, rqt : string;
      sl : TStringList;
      i : integer;
    begin
      qryGDV.Active := false;
      qryGDV.SQL.text := 'select li_no, li_intitule from f_livraison ';
      // On teste les droits aux établissements
      // Si *, droit à tout
      if (frmAccueilCommandes.qryDroitsEcriture.fieldbyname('listeEtablissement').AsString = '*') then
      begin
        qryGDV.SQL.add('where ct_num = ''03''');
        //qryGDV.SQL.add('where ct_num = ' + quotedstr(qryEnteteCde.Fieldbyname('do_tiers').AsString));
        qryGDV.Active := true;
      end
      else
      // Sinon, on récupère la liste de tous les établissements.
      begin
        qryGDV.SQL.add('where (ct_num in ( ');
        sl := TStringList.Create;
        sl.Delimiter := ';';
        sl.StrictDelimiter := True;
        sl.DelimitedText := frmAccueilCommandes.qryDroitsEcriture.fieldbyname('listeEtablissement').AsString;
        for i := 0 to sl.Count - 2 do
        begin
          if (i = sl.Count -2) then
            qryGDV.SQL.add(quotedstr(sl[i]))
          else
            qryGDV.SQL.add(quotedstr(sl[i]) + ',');
        end;
     
        // On teste les droits aux entités
        // Si *, droit à tout
        if frmAccueilCommandes.qryDroitsEcriture.fieldbyname('listeEntite').AsString = '*' then
        begin
          qryGDV.sql.Add(')) and ct_num = ' + quotedstr(qryEnteteCde.Fieldbyname('do_tiers').AsString));
          qryGDV.Active := true;
        end
        else
        // Sinon, on récupère la liste de toutes les entités
        begin
          qryGDV.sql.Add(') and li_no in (');
          sl.DelimitedText := frmAccueilCommandes.qryDroitsEcriture.fieldbyname('listeEntite').AsString;
          for i := 0 to sl.Count - 2 do
          begin
            if (i = sl.Count -2) then
              qryGDV.SQL.add(quotedstr(sl[i]))
            else
              qryGDV.SQL.add(quotedstr(sl[i]) + ',');
          end;
          {// Code original : juste le code du else.
          //if qryEnteteCde.Fieldbyname('do_tiers').AsString = '' then
          //begin
            qryEtablissement.Filter := 'ct_intitule = ' + quotedstr(cbEtablissement.Selected.Text);
            qryEtablissement.Filtered := True;
            qryGDV.sql.Add('))and ct_num = ' + quotedstr(qryEtablissement.FieldByName('ct_num').AsString));
            //qryEtablissement.Filtered := False;
          //end
          //else
          //  qryGDV.sql.Add(')) and ct_num = ' + quotedstr(qryEnteteCde.Fieldbyname('do_tiers').AsString));
          }
          qryGDV.sql.Add(')) and ct_num = 03');
          qryGDV.Active := true;
        end;
      end;
    end;
    En base, nous avons, pour chaque droit, une colonne listeEtablissement et listeEntite, qui contient "*" quand on a accès à tout, ou des nombres, séparés de ";" quand on est limité.

  4. #4
    Nouveau membre du Club
    Homme Profil pro
    Apprenti
    Inscrit en
    Octobre 2011
    Messages
    44
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Apprenti
    Secteur : Enseignement

    Informations forums :
    Inscription : Octobre 2011
    Messages : 44
    Points : 29
    Points
    29
    Par défaut
    J'ai fait un test en simplifiant le code : j'ai mis directement, pour le choix de l'établissement, comme pour le choix de l'entité, un truc en dur dans le code.
    Même résultat.
    Les choix ne fonctionnent correctement qu'à partir du moment où je resélectionne un établissement.

    Ma cbGDV :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
        object cbGDV: TComboBox
          Position.X = 520.000000000000000000
          Position.Y = 8.000000000000000000
          Size.Width = 241.000000000000000000
          Size.Height = 25.000000000000000000
          Size.PlatformDefault = False
          TabOrder = 0
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
        object LinkFillControlToField2: TLinkFillControlToField
          Category = 'Liaisons rapides'
          DataSource = BindSourceDB4
          FieldName = 'li_no'
          Control = cbGDV
          Track = True
          FillDataSource = BindSourceDB6
          FillValueFieldName = 'li_no'
          FillDisplayFieldName = 'li_intitule'
          AutoFill = True
          FillExpressions = <>
          FillHeaderExpressions = <>
          FillBreakGroups = <>
        end
    Ma cbEtablissement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
        object cbEtablissement: TComboBox
          Position.X = 112.000000000000000000
          Position.Y = 8.000000000000000000
          Size.Width = 241.000000000000000000
          Size.Height = 25.000000000000000000
          Size.PlatformDefault = False
          TabOrder = 1
          OnClosePopup = cbEtablissementClosePopup
        end
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
        object LinkFillControlToField1: TLinkFillControlToField
          Category = 'Liaisons rapides'
          DataSource = BindSourceDB4
          FieldName = 'do_tiers'
          Control = cbEtablissement
          Track = True
          FillDataSource = BindSourceDB3
          FillValueFieldName = 'ct_num'
          FillDisplayFieldName = 'ct_intitule'
          AutoFill = True
          FillExpressions = <>
          FillHeaderExpressions = <>
          FillBreakGroups = <>
        end
    Est-ce que l'un d'entre vous pourrait m'expliquer la différence entre DataSource et FillDatasource ? J'avais l'impression que le DataSource, c'est ce qui permet de remplir la combobox, tandis que FillDataSource, c'est une datasource qui est rempli à partir de la combobox, mais je suis plus convaincu.

    Est-ce qu'il y a un moyen de savoir si un composant est utilisé quelque part dans le code ? J'ai l'impression que le BindSourceDB3 n'est pas utilisé, mais je n'en suis pas certain, est-ce que j'ai un moyen de m'en assurer ?

    D'avance, merci pour vos réponses.

    EDIT :
    J'ai fait un autre test : j'ai mis en commentaire le cbEtablissementClosePopup, et je l'ai mis sur un bouton.
    J'ai mis à ma cbGDV deux valeurs en dur, TOTO et TATA.
    Si je sélectionne TOTO ou TATA, ma cbEtablissement ne se vide pas.
    Puis je clique sur le bouton, pour exécuter cbEtablissementClosePopup. J'ai bien TATA et TOTO qui disparaissent, au profit des bonnes entités.
    Sauf que, dès que je sélectionne une entité, paf, mon établissement disparaît.
    Et quand je resélectionne mon établissement, tout va bien.

    Donc c'est le fait d'exécuter le cbEtablissementClosePopup qui a l'air de poser un souci.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    procedure TfrmFicheCommande.cbEtablissementClosePopup(Sender: TObject);
    var
      chaine, rqt : string;
      sl : TStringList;
      i : integer;
    begin
      qryGDV.Active := false;
      qryGDV.SQL.text := 'select li_no, li_intitule from f_livraison ';
      // On teste les droits aux établissements
      // Si *, droit à tout
      if (frmAccueilCommandes.qryDroitsEcriture.fieldbyname('listeEtablissement').AsString = '*') then
      begin
        qryEtablissement.Filter := 'ct_intitule = ' + quotedstr(cbEtablissement.Selected.Text);
        qryEtablissement.Filtered := True;
        qryGDV.sql.Add('where ct_num = ' + quotedstr(qryEtablissement.FieldByName('ct_num').AsString));
        qryEtablissement.Filtered := False;
        //qryGDV.SQL.add('where ct_num = ' + quotedstr(qryEnteteCde.Fieldbyname('do_tiers').AsString));
        qryGDV.Active := true;
      end
      else
      // Sinon, on récupère la liste de tous les établissements.
      begin
        qryGDV.SQL.add('where (ct_num in ( ');
        sl := TStringList.Create;
        sl.Delimiter := ';';
        sl.StrictDelimiter := True;
        sl.DelimitedText := frmAccueilCommandes.qryDroitsEcriture.fieldbyname('listeEtablissement').AsString;
        for i := 0 to sl.Count - 2 do
        begin
          if (i = sl.Count -2) then
            qryGDV.SQL.add(quotedstr(sl[i]))
          else
            qryGDV.SQL.add(quotedstr(sl[i]) + ',');
        end;
     
        // On teste les droits aux entités
        // Si *, droit à tout
        if frmAccueilCommandes.qryDroitsEcriture.fieldbyname('listeEntite').AsString = '*' then
        begin
          qryGDV.sql.Add(')) and ct_num = ' + quotedstr(qryEnteteCde.Fieldbyname('do_tiers').AsString));
          qryGDV.Active := true;
        end
        else
        // Sinon, on récupère la liste de toutes les entités
        begin
          qryGDV.sql.Add(') and li_no in (');
          sl.DelimitedText := frmAccueilCommandes.qryDroitsEcriture.fieldbyname('listeEntite').AsString;
          for i := 0 to sl.Count - 2 do
          begin
            if (i = sl.Count -2) then
              qryGDV.SQL.add(quotedstr(sl[i]))
            else
              qryGDV.SQL.add(quotedstr(sl[i]) + ',');
          end;
          // Code original : juste le code du else.
          //if qryEnteteCde.Fieldbyname('do_tiers').AsString = '' then
          //begin
            qryEtablissement.Filter := 'ct_intitule = ' + quotedstr(cbEtablissement.Selected.Text);
            qryEtablissement.Filtered := True;
            qryGDV.sql.Add('))and ct_num = ' + quotedstr(qryEtablissement.FieldByName('ct_num').AsString));
            qryEtablissement.Filtered := False;
          //end
          //else
            //qryGDV.sql.Add(')) and ct_num = ' + quotedstr(qryEnteteCde.Fieldbyname('do_tiers').AsString));
     
          //qryGDV.sql.Add(')) and ct_num = 03');
          qryGDV.Active := true;
        end;
      end;
    end;
    Spontanément, j'ai envie de croire que ce n'est pas le code qui pose souci, mais les différents BindSource.

    Tests supplémentaires :
    Si j'enlève, dans ma cbEtablissement, le BindSourceDB4 du DataSource, ça fonctionne correctement (même si je n'ai plus, par défaut, le premier établissement qui est sélectionné). Et ce BindSourceDB4, c'est celui qui fait un lien entre un edit qui contient le nom de l'établissement en lecture, et qui n'est pas visible en écriture, quand c'est la cb qui devient visible.

    Solution de contournement trouvée : cbEtablissement.ItemIndex := -1, l'utilisateur change l'établissement, et tout fonctionne... A noter que si je rajoute ensuite ItemIndex := 0 ensuite, rebelote.
    Donc il faut vraiment que le cbEtablissement soit utilisé à la main pour que tout fonctionne...

  5. #5
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 036
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 036
    Points : 40 941
    Points
    40 941
    Billets dans le blog
    62
    Par défaut
    Bonjour,

    je dois avouer avoir du mal à accrocher, peut-être à cause du trop d'informations ou de la pertinence de celles-ci.

    Je résume,
    vous avez donc deux boites de choix, liées par livebindings (donc il s'agit d'une version récente de Delphi et peut-être d'un programme FMX ?)
    une des deux boites est dépendante (Entités) de la première (Etablissements)

    Après, franchement, je m'y perd dans les requêtes, je ne suis pas très enthousiaste lorsque les requêtes ne sont pas paramétrées (risque d'injection SQL).
    De même, tout ces SQL.Add me donne le tournis (s'il s'agit de Firedac, utiliser des macros pourrait être un plus).

    Est-ce que l'un d'entre vous pourrait m'expliquer la différence entre DataSource et FillDatasource ?
    Hum, il faudrait que je m'y repenche sérieusement, je me souviens avoir écrit quelque chose aux sujets des combobox et relation maitre détail dans mon blog qui devrait répondre à ça, mais cela indique t-il la différence entre les deux j'avoue il faudrait que je me relise.
    En tout cas c'est comme cela que j'aurais réglé le problème de la seconde combo (d'où ma préférence aux requêtes paramètrées )
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  6. #6
    Nouveau membre du Club
    Homme Profil pro
    Apprenti
    Inscrit en
    Octobre 2011
    Messages
    44
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Apprenti
    Secteur : Enseignement

    Informations forums :
    Inscription : Octobre 2011
    Messages : 44
    Points : 29
    Points
    29
    Par défaut
    C'est bien du FMX, avec Delphi 10.3.
    En fait, le souci ne vient pas des deux requêtes, mais du fait que le précédent développeur a superposé un edit et une combobox, et affiche l'edit quand la page est en lecture, et la combobox quand la page est en écriture. Et il utilise des bindsource pour remplir les edit en fonction des combobox. Et comme les combobox dépendent aussi l'une de l'autre, ça crée un joyeux truc un peu chelou. Du coup, je n'ai plus de données sélectionnées par défaut, et j'arrive à tricher un peu comme ça. C'est juste un peu con, parce que si l'utilisateur a droit à un seul établissement et une seule entité, il doit quand même sélectionner les deux.

    Pour ce qui est des requêtes, comment pourrais-je faire mieux ? Qu'appelez-vous macro ?
    Les requêtes sont créées comme cela, car en fonction des droits de l'utilisateur, la requête va être un peu différente. S'il a droit à tous les établissement, et à toutes les entités, cela donne une requête. Sinon, s'il n'a droit qu'à un établissement, mais à toutes les entités, c'est différent, pareil s'il a droit à tous les établissement mais pas toutes les entités... Et quand on interroge la base de données, on récupère en même temps les numéros des entités/établissements auxquels on a droit, et c'est pourquoi la requête est créée au fil de l'eau.

  7. #7
    Membre confirmé
    Inscrit en
    Janvier 2005
    Messages
    529
    Détails du profil
    Informations forums :
    Inscription : Janvier 2005
    Messages : 529
    Points : 464
    Points
    464
    Par défaut
    bonjour,
    je crois que le plus simple et de mettre le code de l'événement OnClosePopup dans l'événement Onchange et mettre dans événement OnClosePopup une simple appel de la procedure onchange(sender).
    Merci.Bonne chance.
    Deux, n'apprendront pas; le timide et l'arrogant

Discussions similaires

  1. test conditionne en fonction d'un combobox vide
    Par oscar.cesar dans le forum Macros et VBA Excel
    Réponses: 4
    Dernier message: 24/02/2008, 23h34
  2. Remplir toutes les combobox d'un doc Word
    Par nerim dans le forum VBA Word
    Réponses: 3
    Dernier message: 24/01/2008, 21h48
  3. ComboBox vide lors de l'execution
    Par Yein-Yein dans le forum Interfaces Graphiques en Java
    Réponses: 3
    Dernier message: 14/10/2007, 16h04
  4. [XSL -PHP] Test si vide... et première valeur inférieure
    Par mamat- dans le forum XSL/XSLT/XPATH
    Réponses: 7
    Dernier message: 06/08/2005, 18h57

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