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

Contribuez Discussion :

[FàQ] Comment numéroter les enregistrements d'un [sous-][sous-]formulaire.


Sujet :

Contribuez

  1. #1
    Rédacteur/Modérateur

    Avatar de ClaudeLELOUP
    Homme Profil pro
    Chercheur de loisirs (ayant trouvé tous les jours !)
    Inscrit en
    Novembre 2006
    Messages
    20 596
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 79
    Localisation : Belgique

    Informations professionnelles :
    Activité : Chercheur de loisirs (ayant trouvé tous les jours !)
    Secteur : Finance

    Informations forums :
    Inscription : Novembre 2006
    Messages : 20 596
    Points : 281 917
    Points
    281 917
    Par défaut [FàQ] Comment numéroter les enregistrements d'un [sous-][sous-]formulaire.
    Bonjour,
    Voici un moyen « passe-partout » pour numéroter les enregistrements d’un formulaire quelle que soit sa position dans la hiérarchie : qu’il soit formulaire principal ou sous-formulaire.
    NB ceci s'inspire très largement de GetLineNumber voir : http://support.microsoft.com/kb/120913/fr.

    Pour l’utiliser, il suffit que la source du contrôle de numérotation fasse appel à une fonction privée
    logée dans le code du formulaire :
    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
    Private Function NuméroterLignesFormulaire(NomDuFormulaire As String, _
                 SourceDuContrôle As String, NomDuContrôle)
    'NB ceci s'inspire très largement de GetLineNumber
    ' voir : http://support.microsoft.com/kb/120913/fr
     
    'Exemple pour la source d'un contrôle :
    ' LeContrôlePourNuméroter =NuméroterLignesFormulaire([Nom];"DateAchat";[ztDateAchat])
    ' le premier argument est toujours "[Nom]" quel que soit formulaire
     
    Dim sSQL As String, RS As DAO.Recordset, CountLines As Long
      'construire un Recordset égal à celui de la source du formulaire
    If Left(Me.RecordSource, 6) = "SELECT" Then 'la source est une requête
       sSQL = Me.RecordSource
    Else                                                             'la source est une table
       sSQL = "SELECT * FROM " & Me.RecordSource & ";"
    End If
    Set RS = CurrentDb.OpenRecordset(sSQL)
       'Rechercher le type de donnée pour choisir la bonne syntaxe de comparaison
    Select Case RS.Fields(SourceDuContrôle).Type
     
        Case DB_INTEGER, DB_LONG, DB_CURRENCY, DB_SINGLE, DB_DOUBLE, DB_BYTE   'c'est donc numérique
             RS.FindFirst "[" & SourceDuContrôle & "] = " & NomDuContrôle
     
        Case DB_DATE          'c'est une date
             RS.FindFirst "[" & SourceDuContrôle & "] = #" & Format(NomDuContrôle, "mm/dd/yy") & "#"
        Case DB_TEXT 'si c'est du texte (le texte ne peut contenir de double quotes (")
                     'par contre, l'apostrophe (') est permise
             RS.FindFirst "[" & SourceDuContrôle & "] = """ & NomDuContrôle & """"
    End Select
             ' remonter jusqu'au début en comptant les lignes.
    Do Until RS.BOF
         CountLines = CountLines + 1
         RS.MovePrevious
    Loop
             '  on restitue le résultat
    NuméroterLignesFormulaire = CountLines
        ' Fermeture du Recordset
    RS.Close
    End Function
    Démo en annexe.

  2. #2
    Membre expérimenté
    Avatar de Papy Turbo
    Homme Profil pro
    Développeur Office/VBA
    Inscrit en
    Mars 2004
    Messages
    822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Office/VBA
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2004
    Messages : 822
    Points : 1 709
    Points
    1 709
    Par défaut
    Intéressant.

    Quelques remarques :
    1- je n'ai pas pu ouvrir le lien MS à cause du "." à la fin

    2- tu pourrais accélérer ta routine en remplaçant la boucle du compteur par un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    CountLines = RS.AbsolutePosition
    3-je me pose la question de savoir quel "numéro de ligne" tu veux afficher ?
    - soit tu veux afficher toujours, comme ici, la position d'un enregitrement dans la table d'origine, triée sur sa clé,
    - soit tu veux toujours un n° de 1 à LOF, quel que soit le tri de la table. Auquel cas, tu peux remplacer ton Recordset par
    4-enfin, le pinailleur de service te fait remarquer que :
    - soit ta routine est PUBLIC, tu as besoin en 1er argument du nom du Formulaire à traiter, et il faudra remplacer Me par Forms("NomFormulaire")
    - soit elle est PRIVATE, et tu peux le supprimer.

    En tout cas, continue

  3. #3
    Rédacteur/Modérateur

    Avatar de ClaudeLELOUP
    Homme Profil pro
    Chercheur de loisirs (ayant trouvé tous les jours !)
    Inscrit en
    Novembre 2006
    Messages
    20 596
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 79
    Localisation : Belgique

    Informations professionnelles :
    Activité : Chercheur de loisirs (ayant trouvé tous les jours !)
    Secteur : Finance

    Informations forums :
    Inscription : Novembre 2006
    Messages : 20 596
    Points : 281 917
    Points
    281 917
    Par défaut
    Bonjour Papy Turbo,

    Merci pour tes remarques.
    1- je n'ai pas pu ouvrir le lien MS à cause du "." à la fin
    Pas compris ta remarque.
    Ma source d'inspiration :
    http://support.microsoft.com/kb/120913/fr
    Est-ce cela le lien MS dont tu parles ?
    2- tu pourrais accélérer
    Je modifie.
    3-je me pose la question de savoir quel "numéro de ligne" tu veux afficher ?
    C'est utilisé en général dans un formulaire en continu.
    Je souhaite que les lignes soient numérotées en partant de 1, par pas de 1 sauf en cas d'ex aequo. (soyons honnête, je n'ai pas trouvé de solution pour les éviter ... et j'essaie de m'en accommoder en disant que cela a du sens d'attribuer le même numéro en cas d'ex aequo)
    je remplace mon code actuel par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Set RS = Me.RecordsetClone
    et j'obtiens le résultat attendu.
    4-enfin, l'expert de service te fait remarquer que
    Cela m'avait échappé : J'avais d'abord essayé avec une public function mais je ne suis pas parvenu à la faire fonctionner quel que soit le rang du formulaire.
    Si tu as le temps, j'ai coincé sur un problème de syntaxe ... qui n'est pas résolu. Dans ce cas précis, j'ai pu contourner le problème et (par hasard) en simplifiant la solution. (On peut être beau et avoir de la chance !)
    http://www.developpez.net/forums/d97...bleme-syntaxe/
    J'ai modifié en conséquence.

    Merci encore pour ton intervention.

  4. #4
    Membre expérimenté
    Avatar de Papy Turbo
    Homme Profil pro
    Développeur Office/VBA
    Inscrit en
    Mars 2004
    Messages
    822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Office/VBA
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2004
    Messages : 822
    Points : 1 709
    Points
    1 709
    Par défaut
    Bonjour, Claude,

    D'abord, j'ai vu ton nouvel exercice. Ça marche

    Réponses dans l'ordre :
    1- le lien : sur ton message #1, tu as mis un "." à la fin du lien. Clique dessus : ça plante. Le lien du #3 est correct. Toujours tester, même les liens !
    3- le pinailleur te fait remarquer que tu n'as même pas besoin de la variable RS.
    Par contre un bon
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    WITH Me.RecordsetClone
        [...]
    END WITH
    serait le bienvenu (encore un tout petit petit peu de vitesse).
    4- je me permets d'insister : la fonction PRIVATE est copiée 3 fois. Si tu veux y apporter la moindre amélioration, il faudra le faire 3 fois --> perte de temps, bugs... Une seule fonction PUBLIC supprimera ces inconvénients.
    Pour passer chaque formulaire dans l'appel à la fonction publique, je te réponds sur ton post, dans le forum.
    Tu vas être déçu

    Enfin, just for fun, ton pb de doublons : tu peux les numéroter dans l'ordre si tu utilises :
    - une variable STATIC PreviousNumber As Long (par exemple)
    - à chaque pas, elle prend la même valeur que le compteur de ligne,
    - tu testes si la nouvelle valeur (.AbsolutePosition) = la précédente (stockée dans PreviousNumber)
    - si Oui, tu incrémentes les 2...
    Ça va ralentir, un tout petit peu... À voir ?
    À tester, déboguer, surtout avec les 3 sous-sous-forms !...

  5. #5
    Rédacteur/Modérateur

    Avatar de ClaudeLELOUP
    Homme Profil pro
    Chercheur de loisirs (ayant trouvé tous les jours !)
    Inscrit en
    Novembre 2006
    Messages
    20 596
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 79
    Localisation : Belgique

    Informations professionnelles :
    Activité : Chercheur de loisirs (ayant trouvé tous les jours !)
    Secteur : Finance

    Informations forums :
    Inscription : Novembre 2006
    Messages : 20 596
    Points : 281 917
    Points
    281 917
    Par défaut
    Bonjour Papy Turbo,
    1- le lien :
    3- je corrige.

    Enfin, just for fun, ton pb de doublons : tu peux les numéroter dans l'ordre si tu utilises :
    - une variable STATIC PreviousNumber As Long (par exemple)
    - à chaque pas, elle prend la même valeur que le compteur de ligne,
    - tu testes si la nouvelle valeur (.AbsolutePosition) = la précédente (stockée dans PreviousNumber)
    - si Oui, tu incrémentes les 2...
    Génial et simple (c'est surtout çà qui est génial !)

    Pour passer chaque formulaire dans l'appel à la fonction publique, je te réponds sur ton post, dans le forum.
    Tu vas être déçu
    Cela m'étonnerait : je suis impatient de te lire.

    Encore merci.

  6. #6
    Responsable Access

    Avatar de Arkham46
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    5 865
    Détails du profil
    Informations personnelles :
    Localisation : France, Loiret (Centre)

    Informations forums :
    Inscription : Septembre 2003
    Messages : 5 865
    Points : 14 526
    Points
    14 526
    Par défaut
    bjr

    une idée pour une fonction publique et juste le contrôle en paramètre :

    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
     
    Option Explicit
     
    Public Function NuméroterLignesFormulaire(NomDuContrôle As Control)
    'NB ceci s'inspire très largement de GetLineNumber
    ' voir : http://support.microsoft.com/kb/120913/fr
     
    'Exemple pour la source d'un contrôle :
    ' LeContrôlePourNuméroter =NuméroterLignesFormulaire([ztDateAchat])
     
    Dim sSQL As String, RS As DAO.Recordset, CountLines As Long
    Dim loParent As Object
    ' Recherche le formulaire parent
    ' Boucle nécessaire au cas où le parent du contrôle soit
    '       un contrôle à onglet par exemple
    Set loParent = NomDuContrôle
    Do
        Set loParent = loParent.Parent
        If TypeOf loParent Is Access.Form Then
            Exit Do
        End If
    Loop
      'construire un Recordset égal à celui de la source du formulaire
    If Left(loParent.RecordSource, 6) = "SELECT" Then 'la source est une requête
       sSQL = loParent.RecordSource
    Else                                                             'la source est une table
       sSQL = "SELECT * FROM " & loParent.RecordSource & ";"
    End If
    Set RS = CurrentDb.OpenRecordset(sSQL)
       'Rechercher le type de donnée pour choisir la bonne syntaxe de comparaison
    Select Case RS.Fields(NomDuContrôle.ControlSource).Type
     
        Case DB_INTEGER, DB_LONG, DB_CURRENCY, DB_SINGLE, DB_DOUBLE, DB_BYTE   'c'est donc numérique
             RS.FindFirst "[" & NomDuContrôle.ControlSource & "] = " & NomDuContrôle
     
        Case DB_DATE          'c'est une date
             RS.FindFirst "[" & NomDuContrôle.ControlSource & "] = #" & Format(NomDuContrôle, "mm/dd/yy") & "#"
        Case DB_TEXT 'si c'est du texte (le texte ne peut contenir de double quotes (")
                     'par contre, l'apostrophe (') est permise
             RS.FindFirst "[" & NomDuContrôle.ControlSource & "] = """ & NomDuContrôle & """"
    End Select
             ' remonter jusqu'au début en comptant les lignes.
    Do Until RS.BOF
         CountLines = CountLines + 1
         RS.MovePrevious
    Loop
             '  on restitue le résultat
    NuméroterLignesFormulaire = CountLines
        ' Fermeture du Recordset
    RS.Close
    End Function

  7. #7
    Rédacteur/Modérateur

    Avatar de ClaudeLELOUP
    Homme Profil pro
    Chercheur de loisirs (ayant trouvé tous les jours !)
    Inscrit en
    Novembre 2006
    Messages
    20 596
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 79
    Localisation : Belgique

    Informations professionnelles :
    Activité : Chercheur de loisirs (ayant trouvé tous les jours !)
    Secteur : Finance

    Informations forums :
    Inscription : Novembre 2006
    Messages : 20 596
    Points : 281 917
    Points
    281 917
    Par défaut
    S I D E R A N T !


    Merci Arkham46

  8. #8
    Membre expérimenté
    Avatar de Papy Turbo
    Homme Profil pro
    Développeur Office/VBA
    Inscrit en
    Mars 2004
    Messages
    822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Office/VBA
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2004
    Messages : 822
    Points : 1 709
    Points
    1 709
    Par défaut
    Hello, Thierry.

    Très bel algo !
    Mais auquel, hélas, je trouve 1 défaut majeur : la routine d'origine est déjà très très lente. L'exemple avec 3 sous-form. met plusieurs secondes à s'afficher sur un quad !
    J'aime bien l'astuce ".ControlSource" qui supprime un argument.

    Par contre, j'aurai plutôt tendance, au vu des tests, à
    - renier ce que j'ai dit plus tôt en considérant ce cas comme une exception à la règle,
    - revenir à une copie PRIVATE de la routine dans chaque (sous-) formulaire,
    - supprimer au cas par cas le Select case pour ne garder que le strict essentiel,
    - supprimer carrément TOUT argument pour ne rien compiler à la volée, en mettant le nom du champ directement dans le code.
    Ça me donne pour le 1er cas (tri par DateAchat) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Private Function NumeroterLignes() As Long
    'NB ceci s'inspire très largement de GetLineNumber
    ' voir : http://support.microsoft.com/kb/120913/fr
        With Me.RecordsetClone
            .FindFirst "[DATEACHAT] = #" & Format([DATEACHAT], "mm/dd/yy") & "#"
            NumeroterLignes = .AbsolutePosition + 1
        End With
    End Function

  9. #9
    Membre expérimenté
    Avatar de Papy Turbo
    Homme Profil pro
    Développeur Office/VBA
    Inscrit en
    Mars 2004
    Messages
    822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Office/VBA
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2004
    Messages : 822
    Points : 1 709
    Points
    1 709
    Par défaut
    Bonjour, Claude,

    Je préfère répondre à ta question concernant les N°s en doublon ici, pour ne pas mélanger les forums.
    Citation Envoyé par ClaudeLELOUP Voir le message
    [...]
    Je bute sur la numérotation des ex æquo.
    J’espérais appliquer ta suggestion qui consiste à tenir la comptabilité des numéros déjà attribués (PreviousNumber).

    1° Si un seul formulaire est ouvert, ça fonctionne à moitié. Access exécute la routine d’attribution de N° au fur et à mesure que nécessaire pour afficher ses données à l’écran donc perturbation si l’on navigue dans le formulaire.
    Si la position relative (+ 1) ne correspond pas à la valeur de PreviousNumber (+1), on croit qu’il s’agit d’un doublon et on attribue le PreviousNumber suivant.

    2° Si plusieurs formulaires sont à l’écran, c’est pire : la numérotation commence par les enregistrements affichés du formulaire le plus bas dans la hiérarchie et continue (sans repartir à 1) avec les enregistrements affichés des formulaires suivants.
    Si je trouvais un algorithme qui me permet de résoudre le 1°, je crois pouvoir résoudre le 2° en tenant la comptabilité des N° attribués dans chacun des formulaires affichés.

    Je suis actuellement sur cette piste pour le 1° :
    - Calculer le N° seulement si le champ est encore vierge
    - à l’ouverture, avant de passer la main à l’utilisateur, provoquer un affichage systématique de tous les enregistrements pour déclencher le calcul. (Je t’entends d’ici pour les nanosecondes !)
    Seuls, les tests donneront la bonne solution. Avant de m'y lancer, j'aimerais voir ton code ?
    À ta place, je crois que j'essayerais d'autres types de tests de doublons (voir ta condition ci-dessus). Par exemple :
    Si la position relative est égale à PreviousNumber, on est sur un doublon...

  10. #10
    Rédacteur/Modérateur

    Avatar de ClaudeLELOUP
    Homme Profil pro
    Chercheur de loisirs (ayant trouvé tous les jours !)
    Inscrit en
    Novembre 2006
    Messages
    20 596
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 79
    Localisation : Belgique

    Informations professionnelles :
    Activité : Chercheur de loisirs (ayant trouvé tous les jours !)
    Secteur : Finance

    Informations forums :
    Inscription : Novembre 2006
    Messages : 20 596
    Points : 281 917
    Points
    281 917
    Par défaut
    Bonjour Papy Turbo,
    Merci pour ton intérêt.
    Voici la réécriture de ma proposition initiale. Elle tient compte tes remarques et de Arkham46.

    Je bute sur la numérotation des ex æquo.
    J’espérais appliquer la suggestion de Papy Turbo qui consiste à tenir la comptabilité des numéros déjà attribués dans une variable (PreviousNumber). Le principe : si la position relative (+ 1) ne correspond pas à la valeur de PreviousNumber (+1), on déduit qu’il s’agit d’un doublon et on attribue le PreviousNumber suivant.

    MAIS :
    1° Si un seul formulaire est ouvert, ça fonctionne à moitié. Access exécute la routine d’attribution de N° au fur et à mesure que nécessaire pour afficher ses données à l’écran donc perturbation si l’on navigue dans le formulaire avant de l’avoir exploré entièrement dans sa séquence normale.
    Ex : si à l’ouverture du formulaire, 5 enregistrements s’affichent correctement et que va directement au 50ème record, le système va lui attribuer le N° 6 !

    2° Si plusieurs formulaires sont à l’écran, c’est pire : la numérotation commence par les enregistrements affichés du formulaire le plus bas dans la hiérarchie et continue (sans repartir à 1) avec les enregistrements affichés des formulaires suivants.

    Ayant constaté que faire défiler manuellement chaque enregistrement aboutissait à une numérotation correcte,
    j’ai essayé cette piste :
    - à l’ouverture, avant de passer la main à l’utilisateur, provoquer un affichage systématique de tous les enregistrements pour déclencher le calcul.
    - ensuite éviter de recalculer .

    Avec le code suivant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    Private Sub Form_Open(Cancel As Integer)
    Dim i As Integer
    PreviousNumber = 0 'réinitialiser le contrôle des doublons éventuels
    For i = 1 To Me.RecordsetClone.RecordCount
     
     DoCmd.GoToRecord , , acNext
     Me.N°Ligne.Requery
    Next i
    DoCmd.GoToRecord , , acGoTo, 1
    End Sub
    J’ai pu faire effectivement défiler le formulaire mais le champ N°Ligne n’était pas aménagé (malgré le requery ajouté après coup)
    J’ai contrôlé (avec un debug.print) : la fonction n’est pas sollicitée.

    Je n’ai pas compris pourquoi.

    Je suis aussi demandeur d’un autre algorithme, car même si je parviens à faire fonctionner mon idée : çà risque de ralentir le démarrage.

    Au plaisir de lire vos remarques et suggestions.

  11. #11
    Membre expérimenté
    Avatar de Papy Turbo
    Homme Profil pro
    Développeur Office/VBA
    Inscrit en
    Mars 2004
    Messages
    822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Office/VBA
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2004
    Messages : 822
    Points : 1 709
    Points
    1 709
    Par défaut
    Bon, mot de rire

    On a tous raté le coche : il y a une solution, avec 4 lignes de code par formulaire, aucun argument dans l'appel, dont 2 pour le With...End with.

    Hint : il faut qu'une table soit correctement structurée, avec une clé primaire.

    Ensuite, tu pourras utiliser l'algo d'Arkham pour remettre les 3 routines dans une seule publique, avec contrôle dans l'argument, mais faut voir les performances ???
    En tout cas, je garde cet algo pour tous accès ponctuels à un formulaire, en ne passant qu'un contrôle quelconque.

    Je te souhaite de belles nuits blanches (tu as tout le weekend).

  12. #12
    Rédacteur/Modérateur

    Avatar de ClaudeLELOUP
    Homme Profil pro
    Chercheur de loisirs (ayant trouvé tous les jours !)
    Inscrit en
    Novembre 2006
    Messages
    20 596
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 79
    Localisation : Belgique

    Informations professionnelles :
    Activité : Chercheur de loisirs (ayant trouvé tous les jours !)
    Secteur : Finance

    Informations forums :
    Inscription : Novembre 2006
    Messages : 20 596
    Points : 281 917
    Points
    281 917
    Par défaut
    Bonjour Papy Turbo,

    Pas mieux : j’ai 13 lignes !

    Mes contraintes :
    - la source du formulaire doit contenir un champ numérique à valeur unique
    - le contrôle pour numéroter :
    ** Propriété Nom : N°Ligne
    ** Propriété Source : =RechDom("N°Ligne";"Numérotation";"Formulaire = """ & [Nom] & """ and id = " & [N°Ligne].Remarque)
    ** Propriété Remarque : le nom du champ à valeur unique entre crochets (ex : [|id|] )
    - Ajouter une table « Mumérotation » avec 3 champs : Formulaire, id, N°Ligne.

    L’idée :
    A l’ouverture du formulaire :
    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
    Private Sub Form_Open(Cancel As Integer)
    Dim rst As Recordset, i As Integer, sql As String
    ' purge de la table Numérotation
    DoCmd.SetWarnings False
    DoCmd.RunSQL ("DELETE Numérotation.Formulaire FROM Numérotation WHERE (((Numérotation.Formulaire)=""" & Me.Name & """));")
    ' réalimentation de la table Numérotation
    Set rst = Me.RecordsetClone
           Do Until rst.EOF
               i = 1 + i
               sql = "INSERT INTO Numérotation ( Formulaire, id, N°Ligne ) SELECT """ _
                    & Me.Name & """ AS Expr1, " & rst(Me.N°Ligne.Tag) _
                    & " AS Expr2, " & i & " AS Expr3;"
               DoCmd.RunSQL sql
               rst.MoveNext
           Loop
    DoCmd.SetWarnings True
    End Sub
    Et ça roule, mais c’est lent. Dans mon cas, ce n’est pas trop grave : mes journées sont longues, je dois donc faire un minimum de choses en un maximum de temps !
    Vivement lundi qu’on gagne encore 9 lignes.
    Et, en attendant : bon week-end.

  13. #13
    Membre expérimenté
    Avatar de Papy Turbo
    Homme Profil pro
    Développeur Office/VBA
    Inscrit en
    Mars 2004
    Messages
    822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Office/VBA
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2004
    Messages : 822
    Points : 1 709
    Points
    1 709
    Par défaut
    Soir, Claude

    Bon, j'ai craqué, pas pu résister !
    je te propose donc 2 solutions :
    Citation Envoyé par ClaudeLELOUP Voir le message
    - la source du formulaire doit contenir un champ numérique à valeur unique
    Et ta table VINS contient déjà un [Id] qui est unique puisqu'AutoNum. Ça ne fera pas de mal d'en faire la clé primaire, tu en auras besoin pour lier à d'autres tables (producteurs, caves, buveurs : tu peux m'inscrire pour tout ce qui va du Chassagne au Gigondas, en passant par le Condrieu ?)
    Du moment que ta recherche porte sur un champ unique, le résultat sera unique, comme tu l'as mis en oeuvre dans ta dernière version.

    Donc, la version la plus courte en code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
        With Me.RecordsetClone
            .FindFirst "[id] = " & id.Value
            NumeroterLignes = .AbsolutePosition + 1
        End With
    Cette version a
    - l'avantage d'être dynamique : un simple .Requery renumérotera tout après une insertion, suppression, changement du champ de tri...
    - inconvénient : elle est lente ou surtout, du fait qu'Access calcule en asynchrone, il lui arrive d'oublier de le faire, jusqu'à ce que la souris passe au-dessus du champ à calculer. Ce qui donne l'impression d'être très lent !

    Si tu veux une solution sans aucune lenteur de défilement, c'est ta dernière solution qui est la bonne :
    - tu enregistres dans une table les n°s de ligne au démarrage du formulaire,
    - il n'y a plus qu'à s'en servir tels quels, dans la requête source du formulaire.
    Inconvénient : ralentissement au démarrage + soit, ton formulaire est en lecture seule, soit il faut refaire tout le calcul après chaque insertion, suppression, modification, ce qui serait casse-bonbon.
    Tu peux l'optimiser en ne créant pas de table séparée, mais 3 champs de NoLigne_Date, NoLigne_Description, NoLigne_Stock, directement dans la table des vins ?

    Défi : qui peut remplacer la boucle DAO par une requête SQL qui numérote chaque ligne ? Possible ? + rapide ?

    Dernier point : dans les exemples ci-joint, j'ai
    - supprimé tout accent dans les noms de champs (y compris l'horribilissime "N°" !)
    - renommé le formulaire DATE en VINS_DATE. Pendant que je testais la requête, il me mettait la date du jour à la place du nom du formulaire !!!!
    - j'ai pas résisté à l'envie d'ajouter 10 lignes de code pour 2 petits form_resize. Sorry

    Bon dimanche.
    Fichiers attachés Fichiers attachés

  14. #14
    Rédacteur/Modérateur

    Avatar de ClaudeLELOUP
    Homme Profil pro
    Chercheur de loisirs (ayant trouvé tous les jours !)
    Inscrit en
    Novembre 2006
    Messages
    20 596
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 79
    Localisation : Belgique

    Informations professionnelles :
    Activité : Chercheur de loisirs (ayant trouvé tous les jours !)
    Secteur : Finance

    Informations forums :
    Inscription : Novembre 2006
    Messages : 20 596
    Points : 281 917
    Points
    281 917
    Par défaut
    Bonsoir Papy Turbo,

    Tu avais dit lundi, 2 nuits blanches.
    Donc j'ai travaillé à l'aise ... mais longtemps.
    J'ai aussi une solution depuis ce midi.
    Je peaufine la présentation.
    Je lirai ton post en détail quand j'aurai terminé.
    Mais, à 1ère vue je suis dans la ligne de ce que tu expliques.
    ... et j'adapterai le nom de mes champs.
    A lundi, au plus tard.

    Merci pour l'intérêt que tu portes à ce sujet.

  15. #15
    Rédacteur/Modérateur

    Avatar de ClaudeLELOUP
    Homme Profil pro
    Chercheur de loisirs (ayant trouvé tous les jours !)
    Inscrit en
    Novembre 2006
    Messages
    20 596
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 79
    Localisation : Belgique

    Informations professionnelles :
    Activité : Chercheur de loisirs (ayant trouvé tous les jours !)
    Secteur : Finance

    Informations forums :
    Inscription : Novembre 2006
    Messages : 20 596
    Points : 281 917
    Points
    281 917
    Par défaut
    Bonjour Papy Turbo,

    tu peux m'inscrire pour tout ce qui va du Chassagne au Gigondas, en passant par le Condrieu ?
    Noté. Pour ta gouverne, j’aide ma fille dans la gestion administrative de son resto. C’est de sa cave qu’il s’agit. Moi, j’achète le bag-in-box qui est en promotion dans ma grande surface …

    Pour ta 1ère solution.

    Plus court, tu meurs !
    Il faut toutefois, que l’utilisateur appelle « Id » son champ à valeur unique et que ce soit du mumérique ! Si non, il doit intervenir dans le code pour la syntaxe de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    .FindFirst "[id] = " & id.Value
    A priori ce n’est pas une contrainte très forte, mais enfin, elle est là.

    Pour ta 2ème solution.

    C’est dans cette voie-là que j’ai travaillé.
    Il me semble que j’ai pu résoudre une grande partie des inconvénients que tu signales.


    Défi : qui peut remplacer la boucle DAO par une requête SQL qui numérote chaque ligne ? Possible ? + rapide ?
    Merci. J’ai rempli mon quota de nuits blanches.

    j'ai supprimé tout accent dans les noms de champs (y compris l'horribilissime "N°" !)
    Abracadantesque aurait dit ton ancien Président.
    Je n’ai pas une affinité particulière, pour les noms de champs standardisés. J’aime que leur nom soit, pour moi, explicite et, tant qu’à faire orthographié au mieux. Mais je ne suis allergique à rien, je peux m’adapter. Peux-tu me conseiller un tuto sur le sujet ?

    j'ai pas résisté à l'envie d'ajouter 10 lignes de code pour 2 petits form_resize
    .

    Merci pour le tuyau. Je n’ai pas encore analysé en détail mais ça coince sur mon PC pour le formulaire à 3 niveaux
    err 2100 Contrôle ou sous-formulaire trop grand (sans doute mon écran trop petit ! Excuse-moi).

    Merci en tout cas et bonne semaine.

    ps Je mets en forme ma proposition de solution je posterai d'ici quelques heures.

  16. #16
    Rédacteur/Modérateur

    Avatar de ClaudeLELOUP
    Homme Profil pro
    Chercheur de loisirs (ayant trouvé tous les jours !)
    Inscrit en
    Novembre 2006
    Messages
    20 596
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 79
    Localisation : Belgique

    Informations professionnelles :
    Activité : Chercheur de loisirs (ayant trouvé tous les jours !)
    Secteur : Finance

    Informations forums :
    Inscription : Novembre 2006
    Messages : 20 596
    Points : 281 917
    Points
    281 917
    Par défaut
    Bonsoir,

    Le but

    Trouver un moyen « passe-partout » pour numéroter les enregistrements d’un formulaire (souvent en continu).
    Quelle que soit la position de ce formulaire dans la hiérarchie ([sous]-[sous]…[formulaire]
    Quel soit le nombre de formulaires numérotés ouverts.
    Que l’on puisse consulter, mettre à jour, supprimer, ajouter ou modifier les filtres.
    Avec un maximum de facilité pour l’implanter dans une DB (en tout cas à partir de [Access2000])
    Ceci parce que j’étais frappé par le nombre de fois que cette question revient dans le Forum.

    Consignes d’utilisation

    le formulaire doit contenir un contrôle dont la source correspond à une valeur sans doublon. Quel qu’en soit le type donc pas nécessairement un autonum ni une clé. Indifféremment du numérique, du texte ou une date. Mais UNIQUE.
    le contrôle de numérotation aura comme source :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    =NumDeLaLigne([Nom];[NomDuContrôleQuiContientLaValeurUnique])
    le 1er paramètre est toujours [Nom]
    le second serait par exemple [ztDENOMINATION]) si, dans ce formulaire, le champ à valeur sans doublon est logé dans la zone de texte ztDENOMONATION

    Evénement sur ouverture du formulaire le code suivant

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Call ChargerMatriceNumérotation([LeNomDuContrôleDeNumérotation])
    Si d’autres événements (Après insertion, Après MàJ, Après suppression, …) le code

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Me.RecordSource = Me.RecordSource
    Call Call ChargerMatriceNumérotation([LeNomDuContrôleDe Numérotation])
    NB J’ignore pourquoi un Me.requery ne donne pas un résultat correct.

    Dans un module, les 2 fonctions suivantes :

    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
    71
    72
    73
    74
    75
    76
    Public NumLignes() As String
    Public Sub ChargerMatriceNumérotation(ContrôleRecherché As Access.Control)
     
    Dim sSQL As String, loParent As Object, i As Integer, Num As Integer
    Dim ArrCtlValUnique() As String, NomValUnique As String
    On Error GoTo Erreur1er
     ' Recherche le formulaire parent
    Set loParent = ContrôleRecherché
       Do  ' Boucle nécessaire au cas où le parent du contrôle soit un contrôle à onglet par exemple
           Set loParent = loParent.Parent
           If TypeOf loParent Is Access.Form Then
                 Exit Do  'loParent = l'objet formulaire contenant le contrôle donné en paramètre
           End If
       Loop
    'rechercher la clé unique = 2ème argument de l'appel
    ArrCtlValUnique = Split(ContrôleRecherché.ControlSource, ",")  '---> [Zt1Appellation])
    ArrCtlValUnique(1) = Left(ArrCtlValUnique(1), Len(ArrCtlValUnique(1)) - 1) '---> [Zt1Appellation]]
    NomValUnique = loParent(ArrCtlValUnique(1)).ControlSource
    '-----------
    With loParent
    'initialiser la 1ère ligne de NumLignes : garantir qu'elle est occupée (<>"")
    Ini1ère:
     NumLignes(0) = "bidon"   'tombe en erreur 9 au 1er passage,
                              'ce qui permet de dimensionner NumLignes au plus juste
    'redimensionnement de NumLignes
        'purger NumLignes ses lignes éventuelles de ce formulaire
             ' Rien la 1ère fois mais utile après modif des données en cours d'utilisation
        For i = 1 To UBound(NumLignes)
               If NumLignes(i) Like .Name & "*" Then NumLignes(i) = ""
        Next i
        'préparer la dimension de NumLignes
           '1° Place utile actuellement
        For i = 0 To UBound(NumLignes)
            If NumLignes(i) <> "" Then i = i + 1 'i = nbre actuel de lignes utiles +1
        Next i
           '2° Ajouter la place pour accueillir les nouveaux
        ReDim Preserve NumLignes(i - 1 + .RecordsetClone.RecordCount)
        ' [ré]alimentation de NumLignes
        'se positionner sur le
        Num = 1
     
             Do Until .RecordsetClone.EOF
                  'Chercher une lignes libre
                   Do While NumLignes(i) <> ""
                         i = i + 1         '---> i = ligne blanche
                   Loop
                   'écrire la ligne
                        NumLignes(i) = loParent.Name _
                           & "|" & .RecordsetClone(NomValUnique) _
                           & "|" & Num
                   'passer à l'enregistrement suivant
                        Num = Num + 1
                        .RecordsetClone.MoveNext
             Loop
    End With
    Exit Sub
     
    Erreur1er:
    If Err.Number = 9 Then 'NumLignes n'a pas encore été dimensionnée
      ReDim Preserve NumLignes(1)
      Resume Ini1ère
    End If
     
    End Sub
     
     
    Public Function NumDeLaLigne(NomDuFormulaire As String, NomDuCtlClé As String)
    Dim i As Integer, ArrNuméro() As String
    For i = 1 To UBound(NumLignes)
      If NumLignes(i) Like NomDuFormulaire & "|" & NomDuCtlClé & "*" Then
         ArrNuméro = Split(NumLignes(i), "|")
         NumDeLaLigne = ArrNuméro(2)
     
      End If
    Next i
    End Function
    L’idée
    A l’ouverture du formulaire la Sub « ChargerMatriceNumérotation » garnit un tableau interne avec autant de lignes qu’il y a d’enregistrements en jeu dans tous les formulaires qui ont été ouverts.
    Cette ligne a la structure :
    Nom du Formulaire|Valeur du champ unique|N°d’ordre dans le Recordset exemple
    DENOMINATIONS|Château Beychevelle|10

    La source du contrôle de numérotation est alimentée par la fonction « NumDeLaLigne » qui, avec le nom du formulaire [Nom] (1er paramètre) et la valeur contenue dans le contrôle de référence [NomDuContrôleQuiContientLaValeurUnique] (2ème paramètre) en l’occurrence ici : Château Beychevelle va restituer la 3ème composante « 10 » (C’était le rang occupé par cet enregistrement dans le RecordSet).

    J’ai abondement commenté le code de ces fonctions pour rendre les algorithmes aussi clairs que possible.
    Questions et remarques bienvenues.

    En pièce jointe un exemple d’utilisation en [Access2000].
    Le formulaire « DENOMINATIONS » permet de voir le fonctionnement Suppression, Ajout et MàJ
    Le formulaire « Appellations » est basé sur une requête
    Le formulaire « Ex2èmeniveau » montrent un sous-formulaire qui évolue en fonction d’un champ dans le formulaire principal.
    Le formulaire « Ex3èmeniveau » la même chose avec 3 niveaux.
    Vous pouvez les ouvrir tous en même temps.
    Sur ma machine (petit budget), ça roule à bonne vitesse…

    J’ai tenu la plume, mais les solutions viennent de Papy Turbot, Arkham46 et aussi ceci :
    http://support.microsoft.com/kb/120913/fr
    T’as vu Papy Turbo : y a pas de point. Cette fois j’ai testé !

    Merci à eux.

    A bientôt.

  17. #17
    Membre émérite
    Homme Profil pro
    tripatouilleur de code pour améliorer mon quotidien boulistique
    Inscrit en
    Février 2008
    Messages
    939
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : tripatouilleur de code pour améliorer mon quotidien boulistique
    Secteur : Enseignement

    Informations forums :
    Inscription : Février 2008
    Messages : 939
    Points : 2 287
    Points
    2 287
    Par défaut
    Bonjour

    Pour ce qui est du tutoriel, voici Les conventions typographiques en VBA (illustrées sur Access) qui est une bonne base.

    Pierre

  18. #18
    Rédacteur/Modérateur

    Avatar de ClaudeLELOUP
    Homme Profil pro
    Chercheur de loisirs (ayant trouvé tous les jours !)
    Inscrit en
    Novembre 2006
    Messages
    20 596
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 79
    Localisation : Belgique

    Informations professionnelles :
    Activité : Chercheur de loisirs (ayant trouvé tous les jours !)
    Secteur : Finance

    Informations forums :
    Inscription : Novembre 2006
    Messages : 20 596
    Points : 281 917
    Points
    281 917
    Par défaut
    Bonjour et merci Pierre.
    Vite un coup d'oeil sur le lien.
    Eh bien ... Y a du boulot !
    Bonne journée

  19. #19
    Membre expérimenté
    Avatar de Papy Turbo
    Homme Profil pro
    Développeur Office/VBA
    Inscrit en
    Mars 2004
    Messages
    822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Office/VBA
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2004
    Messages : 822
    Points : 1 709
    Points
    1 709
    Par défaut
    Bonjour, Claude

    J'ai testé ta dernière solution. Elle marche, ce qui est essentiel. Mais je la trouve très compliquée.
    Je ne vais pas revenir sur les diverses solutions abordées jusqu'ici : tout a été dit + haut. J'ai surtout l'impression que tu sombres dans un piège bien connu : le nez dans le code, on cherche des solutions de plus en plus sophistiquées... et on passe à côté du plus simple. Je te conseillerai simplement de laisser ce sujet de côté pendant une bonne semaine, puis de relire le tout et faire ton choix.

    Conventions de typo :
    Merci, Pierre, pour le lien.
    Je n’ai pas une affinité particulière, pour les noms de champs standardisés. J’aime que leur nom soit, pour moi, explicite et, tant qu’à faire orthographié au mieux. Mais je ne suis allergique à rien, je peux m’adapter.
    Entièrement d'accord. Mais explicite ne veut pas dire que tu dois avoir des problèmes plus tard. Et tu en auras si tu mets des accents, des espaces et autres caractères non ASCII pur (a-z, 0-9) dans tes variables, arguments, noms de champs, de tables et autres objets.
    Pour les champs, tu tomberas toujours sur un problème dans une requête SQL ou un calcul. Et ça peut prendre des heures avant de l'identifier. Donc, conseil :
    - mettre le nom explicite en bon français dans la Légende,
    - mettre un nom "strict", sans accent ni espace... dans le nom du champ.
    Voir tuto d'Argy pour détails.

    Form_Resize
    ça coince sur mon PC pour le formulaire à 3 niveaux
    err 2100 Contrôle ou sous-formulaire trop grand (sans doute mon écran trop petit ! Excuse-moi).
    Pas d'excuse Juste un brin de débogage. Access dira ça à chaque fois que tu (que ton code) essaies d'attribuer une valeur négative à une dimension : .Width = -15 il sait pas faire.
    C'est pour ça que tu trouveras dans le code des tests : If Newwidth > 0 Then...
    En tout cas, tu as une erreur : il manque un test.
    - quelle ligne exacte plante ?
    - quelle valeur, sur cette ligne, est négative (ou trop grande, genre formulaire.width > 55 cm !!) ? Utiliser Shift+F9
    - quel test peut empêcher que ça se reproduise ?

  20. #20
    Rédacteur/Modérateur

    Avatar de ClaudeLELOUP
    Homme Profil pro
    Chercheur de loisirs (ayant trouvé tous les jours !)
    Inscrit en
    Novembre 2006
    Messages
    20 596
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 79
    Localisation : Belgique

    Informations professionnelles :
    Activité : Chercheur de loisirs (ayant trouvé tous les jours !)
    Secteur : Finance

    Informations forums :
    Inscription : Novembre 2006
    Messages : 20 596
    Points : 281 917
    Points
    281 917
    Par défaut
    Bonsoir Papy Turbo

    Mais je la trouve très compliquée.
    Je suis d’accord avec toi et il m’a fallu de nombreuses heures pour le mettre au point. J’ai absolument voulu éviter la création d'une table externe (mon but : solution passe-partout pour utilisateur non expérimenté --> minimiser ses interventions dans une DB existante). Et pour rencontrer tes remarques sur la lenteur, je me suis efforcé de réduire la dimensions du tableau interne en réutilisant les lignes redevenues blanches suite à un re-calcul des numéros (éviter de scanner une flopée de records à blanc lors de la recherche du numéro).

    de laisser ce sujet de côté pendant une bonne semaine, puis de relire le tout et faire ton choix.
    C’est dans doute paradoxal, mais je ne suis pas concerné par ce problème : aucun de mes formulaires n’est à numéroter. J’ai actuellement du temps libre et il m’a semblé que la question revenait quelquefois sur le forum. Le défi m’a passionné …Aucun regret.

    Tes remarques sur le nommage. Ok. pour le futur.

    Form_Resize
    ssfStock.Top = .Top + .Height + VERT_MARGIN ont respectivement 2.803, 345, 2.642 et 200
    contexte : bd1.Form_FormulaireNiveau2.Form_Resize
    A toute chose, malheur est bon : je connaissais pas Shift+F9.

    Merci pour ta sympathique collaboration.
    A la prochaine.

Discussions similaires

  1. Réponses: 1
    Dernier message: 29/07/2014, 17h41
  2. comment numéroter les onglets sous excel 2000
    Par PtiteNanou dans le forum Excel
    Réponses: 1
    Dernier message: 17/03/2008, 11h52
  3. [TRichEdit] Comment numéroter les lignes ?
    Par ARDILLER dans le forum Composants VCL
    Réponses: 1
    Dernier message: 27/03/2006, 15h43
  4. comment concaténer les enregistrements d'un champ donné ???
    Par c_moi_c_moi dans le forum SAP Crystal Reports
    Réponses: 7
    Dernier message: 23/03/2006, 16h11
  5. Réponses: 3
    Dernier message: 22/03/2006, 09h47

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