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

IHM Discussion :

Formulaire : requête basée sur le sélecteur


Sujet :

IHM

  1. #21
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    188
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 188
    Points : 98
    Points
    98
    Par défaut
    Bonjour.

    ça fait trois jour que j'essaye des modifs plus ou moins au hazard, et chaque fois, j'ai des resultats plus bizaroïdes les un que les autres.

    J'ai fait des recherches sur le net, et dans des bouquins de VBA, mais je n'ai rien trouvé sur le selecteur, qui, d'après ce que j'ai pu constaté par mes essai, semble avoir sa propre vie, indépendamment du reste des contrôles d'un 'formulaire.

    Ne sachant toujours pas où chercher, voilà ce que j'ai découver ne nouveau.
    Ainsi, si jamais ça parle plus à quelqu'un qui s'y connait qu'à moi...

    Alors voilà.

    La première partie du code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Dim lngSelTop As Long, lngSelHeight As Long
    se place en début de formulaire et permet de créer deux varibales.

    La seconde partie
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Private Sub cmdEnrSelectionnes_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
    ' Aucun bouton ne doit être enfoncé sinon le bouton
    ' a pris le focus, et la sélection a disparue
    If Button = 0 Then
       lngSelTop = Me.SelTop
       lngSelHeight = Me.SelHeight
    End If
    End Sub
    Mémorise deux informations : SelTop qui est le N° de la première ligne d'une selection, ou selon l'aide Access "quelle ligne (enregistrement) figure tout en haut du rectangle de sélection en cours dans la feuille de données d'une table [...]ou quel enregistrement sélectionné figure tout en haut dans un formulaire continu" et SelHeight qui est le nombre de lignes sélectionnées, ou selon l'aide Access "le nombre de lignes sélectionnées (enregistrements) dans le rectangle de sélection en cours [...]ou le nombre d'enregistrements sélectionnés dans un formulaire continu"

    Cette mémorisation est faite de manière continue. c'est à dire que dès que la souris bouge, la mémorisation se fait, même s'il n'y a pas eu de modification de cette sélection.

    J'ai ajouté la commande Beep à cette partie du code, et le crépitement indique que cette mémorisation est renouvelé de manière permanente.

    Ensuite, il y a un bouton
    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
    Private Sub cmdEnrSelectionnes_Click()
    Dim i As Long, strMsg As String
    If lngSelTop = 0 Then lngSelTop = Me.SelTop
    If lngSelHeight = 0 Then lngSelHeight = Me.SelHeight
    If lngSelHeight = 0 Then
       MsgBox "Pas de sélection"
       Exit Sub
    End If
    ' Parcour les enregistrements sélectionnés et lit le contrôle F1
    For i = lngSelTop To lngSelTop + lngSelHeight - 1
       DoCmd.GoToRecord acDataForm, Me.Name, acGoTo, i
       strMsg = strMsg & "Enr " & Format(i, "0000000") & " : " & Me.F1 & vbCrLf
    Next
    ' Restaure la sélection
    Me.SelTop = lngSelTop
    Me.SelHeight = lngSelHeight
    MsgBox strMsg
    End Sub
    Quand on appuie sur ce bouton, la sélection qui est mémorisée, est écrite en dur. Soit dans une messagebox, soit dans une table.

    Si on remplace la seconde partie du code par
    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
    Private Form_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
    Dim i As Long, strMsg As String
    If lngSelTop = 0 Then lngSelTop = Me.SelTop
    If lngSelHeight = 0 Then lngSelHeight = Me.SelHeight
    If lngSelHeight = 0 Then
       MsgBox "Pas de sélection"
       Exit Sub
    End If
    ' Parcour les enregistrements sélectionnés et lit le contrôle F1
    For i = lngSelTop To lngSelTop + lngSelHeight - 1
       DoCmd.GoToRecord acDataForm, Me.Name, acGoTo, i
       strMsg = strMsg & "Enr " & Format(i, "0000000") & " : " & Me.F1 & vbCrLf
    Next
    ' Restaure la sélection
    Me.SelTop = lngSelTop
    Me.SelHeight = lngSelHeight
    MsgBox strMsg
    End Sub
    La seconde partie du code, donc l'écriture "en dur", est exécutée lors du relachement de la souris(en fin de sélection donc)
    Mais le résultat est curieux. Si le nombre de ligne est bon (donc correspond au nombre de lignes de la sélection) son emplacement est généralement faux.
    En effet, le résultat se comporte en "démarrant" à partir de la ligne qui portait le focus avant le début de la sélection.

    Troisième essai
    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
    Private Sub Private Sub Form_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
    Dim i As Long, strMsg As String
    If lngSelTop = 0 Then lngSelTop = Me.SelTop
    If lngSelHeight = 0 Then
    lngSelHeight = Me.SelHeight
    'If lngSelHeight = 0 Then
       'MsgBox "Pas de sélection"
       Exit Sub
    End If
    ' Parcour les enregistrements sélectionnés et lit le contrôle F1
    For i = lngSelTop To lngSelTop + lngSelHeight - 1
       DoCmd.GoToRecord acDataForm, Me.Name, acGoTo, i
       strMsg = strMsg & "Enr " & Format(i, "0000000") & " : " & Me.F1 & vbCrLf
    Next
    ' Restaure la sélection
    Me.SelTop = lngSelTop
    Me.SelHeight = lngSelHeight
    MsgBox strMsg
    End Sub
    J'ai juste désactivé
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    'If lngSelHeight = 0 Then
    'MsgBox "Pas de sélection"
    Et le résultat est qu'il n'y a plus de problème concernant le début de la sélection (le nombre de ligne est bon et commence au bon endroit)
    Mais c'est le déclenchement qui pose un problème.
    En effet, il faut que je fasse la sélection, je relache la souris et il ne se passe rien, et il faut que je reclique sur une des lignes selectionnées dans le selecteur pour déclencher la mémorisation.

    Pour info, je fait toutes les selection en balayage.
    On clique sur la première ligne, et on glisse pour couvrir les lignes que l'on souhaite. En effet, l'evenement MousseUp rend impossible l'utilisation du Shift+Clic, puisqu'il se déclenche sur la première ligne sélectionnée.

    Encore une étrangeté d'ailleurs, car lors de l'utilisation du code d'origine, Access arrive à faire la différence entre un clic sur une ligne seule (on ne veur selectionner qu'une ligne) et le premier clic d'une selection par shift+clic. Comme par miracle, il se souvient qu'il y ait eu un clic sur une première ligne et qu'il faut rajouter toutes les autres jusqu'au shift+clic.
    Pourtant, souvenez-vous, pour aller effectuer le shift+clic, il fautdéplacer la souris et donc mémoriser SelTop et SelHeight.

    En fait, on dirait que bien que la sélection soit mémorisée dans deux variables (première partie du code) et donc ne devrait pas évoluer, l'utilisation qu'on en fait et surtout la façon de déclencher cette utilisation modifie cette sélection.

    PS : J'ai fait une petite base proto pour tester le selecteur, avec des effets bien visibles. Si quelqu'un veut tenter quelquechose je me deamandais si on pouvait la mettre en ligne...

    Encore une fois, je suis convaincu de l'utilité d'une fonction sélection par blocs, comme on pêut le faire dans une liste de fichiers par exemple. Chaque fois qu'il est necessaire de faire des sélections un peu discrètes, on peut avoir besoin de cette fonction.
    Je m'étones que le sujet ne soit pas plus développé.
    Merci

  2. #22
    Expert éminent
    Avatar de LedZeppII
    Homme Profil pro
    Maintenance données produits
    Inscrit en
    Décembre 2005
    Messages
    4 485
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Maintenance données produits
    Secteur : Distribution

    Informations forums :
    Inscription : Décembre 2005
    Messages : 4 485
    Points : 7 759
    Points
    7 759
    Par défaut
    bonjour,

    Ces deux bouts de codes
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Dim lngSelTop As Long, lngSelHeight As Long
    et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Private Sub cmdEnrSelectionnes_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
    ' Aucun bouton ne doit être enfoncé sinon le bouton
    ' a pris le focus, et la sélection a disparue
    If Button = 0 Then
       lngSelTop = Me.SelTop
       lngSelHeight = Me.SelHeight
    End If
    End Sub
    ne sont utiles que dans le contexte de l'utilisation d'un bouton.
    La raison étant que lorsqu'on clique sur le dit bouton, il prend le focus, et du coup la sélection est perdue.

    Vu que tu as changé de stratégie, il n'est plus nécessaire de mémoriser la sélection.
    A priori le focus reste sur le sélecteur, si tu gères l'événement Form_Click() ou Form_MouseUp()
    On peut directement exploiter Me.SelTop et Me.SelHeight.
    Pour ne pas chambouler le code, on peut utiliser des variables locales (déclarées localement dans la sub) lngSelTop et lngSelHeight
    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
    Private Form_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
    Dim lngSelTop As Long, lngSelHeight As Long
    Dim i As Long, strMsg As String
     
    lngSelTop = Me.SelTop
    lngSelHeight = Me.SelHeight
     
    If lngSelHeight = 0 Then
       MsgBox "Pas de sélection"
       Exit Sub
    End If
     
    ' Parcour les enregistrements sélectionnés et lit le contrôle F1
    For i = lngSelTop To lngSelTop + lngSelHeight - 1
       DoCmd.GoToRecord acDataForm, Me.Name, acGoTo, i
       strMsg = strMsg & "Enr " & Format(i, "0000000") & " : " & Me.F1 & vbCrLf
    Next
    ' Restaure la sélection
    Me.SelTop = lngSelTop
    Me.SelHeight = lngSelHeight
    MsgBox strMsg
    End Sub
    A+

  3. #23
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    188
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 188
    Points : 98
    Points
    98
    Par défaut
    Bonsoir.

    Et un très grand merci pour le fait que vous continuez à vous interresser à mon cas.

    J'ai imédiatement recopié ce code et fait un test.

    Evidement, ça marche.

    Le problème, c'est que bien que je crois avoir compris le principe de fonctionnement et la mécanique du code donné, je ne comprends toujours pas pourquoi les évènements et les résultats sont si différents.

    Dans le cas présent trois résultats :

    On clique sur une ligne, on relache, elle est considérée comme sélectionnée.

    On clique sur une ligne, on ballaye vers le bas ou vers le haut, on relache, les lignes balayées sont considérées comme sélectionnées.

    On clique sur une ligne, on relache, elle est considérée comme sélectionnée, on tente un SHIFT+Clic plus bas, ça bogue.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    DoCmd.GoToRecord acDataForm, Me.Name, acGoTo, i
    Surligné.

    Pourquoi est-ce que le Shift+Clic fonctione niquel dans le premier type de code (avec bouton), en dehors du fait que la "matérialisation" de la sélection necessite l'appui sur un bouton, et pourquoi cette fonction n'est plus possible dans la seconde verion du code.

    En fait je sais pourquoi, c'est parceque l'évènement Clic ou MouUp se déclenche dès le premier clic.

    Pourtant, dans le premier exemple, la mémorisation était opérée lors du déplacement de la souris.
    Et pour faire un Shift+clic plus bas, il était necessaire de déplacer la souris.
    Malgrès cela, le sélecteur semblait capable de faire la différence entre un clic seul, et un clic suivi d'un shift+clic.

    Le code m'apparait comme très clair, mais c'est le fonctionnement du sélecteur lui-même que je ne comprends pas, et pour cause, il n'apparait absolument pas dans le code.

    Je vais voir si fort de cette nouvelle configuration, je peut bidouiller quelquechose avec mes connaissances actuelles.

    Encore un grand merci.

  4. #24
    Expert éminent
    Avatar de LedZeppII
    Homme Profil pro
    Maintenance données produits
    Inscrit en
    Décembre 2005
    Messages
    4 485
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Maintenance données produits
    Secteur : Distribution

    Informations forums :
    Inscription : Décembre 2005
    Messages : 4 485
    Points : 7 759
    Points
    7 759
    Par défaut
    Bonjour,

    Je ne pense pas que l'on puisse vraiment comparer la méthode avec bouton, et celle avec événement souris du formulaire.

    Visiblement (je ne sais pas l'expliquer) lorsqu'on maintient le Shift, il faut que l'événement Click() du formulaire soit terminé pour que l'on puisse quitter l'enregistrement actif.
    L'erreur dans le code vient de là.
    Il arrive que, dans le contexte d'une procédure événementielle, certaines actions sur le formulaire ou ses contrôles ne soient pas possibles,
    tant que l'événement n'est pas terminé.

    C'est pas grave, il suffit de ne plus utiliser DoCmd.GoToRecord.
    A la place on va utiliser le clone du recordset du formulaire.
    Cela offre un avantage : on a plus besoin de restaurer la sélection (DoCmd.GoToRecord la faisait disparaî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
    Private Sub Form_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
    Dim lngSelTop As Long, lngSelHeight As Long
    Dim i As Long, strMsg As String
    Dim strChamp As String, rsfm As DAO.Recordset
     
    lngSelTop = Me.SelTop
    lngSelHeight = Me.SelHeight
     
    If lngSelHeight = 0 Then
       MsgBox "Pas de sélection"
       Exit Sub
    End If
     
    ' Quitter si recordset vide
    Set rsfm = Me.RecordsetClone
    If rsfm.RecordCount = 0 Then Exit Sub
     
    ' Quitter si premier enregistrement de la sélection est
    ' au dela du dernier enregistrement
    rsfm.MoveLast
    If lngSelTop > rsfm.RecordCount Then Exit Sub
     
    ' Aller au premier enregistrement de la sélection
    rsfm.MoveFirst
    rsfm.Move lngSelTop - 1
     
    ' Nom du champ lié au contrôle F1
    strChamp = Me.F1.ControlSource
     
    ' Parcourir les enregistrements sélectionnés
    For i = 1 To lngSelHeight
       strMsg = strMsg & "Enr " & Format(rsfm.AbsolutePosition + 1, "0000000") & _
                " : " & rsfm(strChamp) & vbCrLf
       rsfm.MoveNext
       If rsfm.EOF Then Exit For
    Next
     
    MsgBox strMsg
    End Sub
    A+

  5. #25
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    188
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 188
    Points : 98
    Points
    98
    Par défaut
    Bonjour et merci de bosser le Week-end.

    Bon, cette solution fonctionne (bien évidement)

    Cependant, je comprends toujours rien à ce que je fais, et par exemple, au bout de deux heures, je ne suis pas arrivé à trnasformer ce dernier code pour qu'il écrive dans une table (comme le premier).

    J'ai recopié des boût du premier, mais ce n'est même pas la peine que je l'indique ici, car si la table est mise à jour, le shift+clic ne marche plus, et en plus ça crée des doublons.

    Comme on dit, mieux vaut un qui sait que dix qui cherchent, alors qu'en c'est un qui cherche et qui sait pas, c'est pas gagné...

    Je pensais que je pourrais modifier les choses au fur et à mesure pour atteindre mon objectif (pouvoir avoir une selection dynamique avec fonctions CLIC, CLIC+balayage, SHIFT+CLIC, CTRL+CLIC...)

    Mais je vois bien que je suis pas capable d'intervenir la dessus tout seul.

    Les seuls trucs qui marchent sont ceux que j'ai pu recopier tel-quel en changeant juste le nom des champs et des contrôles.

    Si je trouve pas un système "tout cuit", je vais encore y passer une semaine.

    Ou alors, en faisant ça uniquement avec des boutons, et en enchainant les évènements (Souris déplacé, entrée, sur sortie...)

    Alors, si quelqu'un a connaissance d'un code tout fait, visant à exploiter au maximum le selecteur, je suis preneur.

    Encore merci.

  6. #26
    Expert éminent
    Avatar de LedZeppII
    Homme Profil pro
    Maintenance données produits
    Inscrit en
    Décembre 2005
    Messages
    4 485
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Maintenance données produits
    Secteur : Distribution

    Informations forums :
    Inscription : Décembre 2005
    Messages : 4 485
    Points : 7 759
    Points
    7 759
    Par défaut
    Bonjour,

    Je suis allé un peu plus loin que le code précédent.

    J'ai un formulaire "fmSelecteur" en mode continu, basé sur une table "Produits" ayant pour champ clé "Réf produit".
    La table pour sauver la sélection s'appelle tblSelectionFmSelecteur.
    Elle a un seul champ "Réf produit", clé primaire de la table.
    Sur le formulaire "fmSelecteur", dans la section En-tête de formulaire, j'ai une image dont le contrôle s'appelle "imgToucheCtl".
    Elle représente la touche Ctl et sa propriété "Visible" est à "Non"
    Autre chose importante, la propriété "Apperçu des touches" est à "Oui", pour détecter l'état de la touche Ctl.

    J'ai un deuxième formulaire "fmSelection". Celui-ci est en mode continu et est basé sur la table "tblSelectionFmSelecteur".
    Cela me permet d'afficher le contenu de la table, pendant que je change mas sélection.

    Voici maintenant le code du formulaire "fmSelecteur" :
    Code vb : 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
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    Option Explicit
     
    ' Nom de la table dans laquelle on va sauver la sélection
    Const strTableSelection = "tblSelectionFmSelecteur"
    ' Nom du champ dans la table
    Const strChampSelection = "Réf produit"
    ' Nom du contrôle servant de clé pour mémoriser sélection
    Const strCtlCle As String = "F1"
     
    ' Variable pour savoir si la touche "Control" est appuyée
    Dim bToucheCTL As Boolean
     
    Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
    Call ToucheCTL(Shift, True)
    End Sub
     
    Private Sub Form_KeyUp(KeyCode As Integer, Shift As Integer)
    Call ToucheCTL(Shift, False)
    End Sub
     
    Private Sub Form_Load()
    Call ViderSelection
    DoCmd.OpenForm "fmSelection"
    Me.txtEnrSelectionnes = DCount("*", strTableSelection)
    Me.SetFocus
    End Sub
     
    Private Sub Form_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
    Dim lngSelTop As Long, lngSelHeight As Long
    lngSelTop = Me.SelTop: lngSelHeight = Me.SelHeight
     
    If Not bToucheCTL Then Call ViderSelection
    SauverSelection2 lngSelTop, lngSelHeight
    If CurrentProject.AllForms("fmSelection").IsLoaded Then
       Forms("fmSelection").Requery
    End If
    Me.txtEnrSelectionnes = DCount("*", strTableSelection)
    End Sub
     
    Private Sub ToucheCTL(Shift As Integer, bKeyDown As Boolean)
    If (Shift And acCtrlMask) = acCtrlMask Then
       bToucheCTL = bKeyDown
       If Me.imgToucheCtl.Visible <> bToucheCTL Then
          Me.imgToucheCtl.Visible = bToucheCTL
       End If
    End If
    End Sub
     
    Private Sub ViderSelection()
    Dim db As DAO.Database
    Set db = CurrentDb
    db.Execute "DELETE FROM [" & strTableSelection & "]"
    End Sub
     
    Private Sub SauverSelection2(lngSelTop As Long, lngSelHeight As Long)
    Dim i As Long, rsfm As DAO.Recordset, db As DAO.Database, rs As DAO.Recordset
    Dim strChamp As String
     
    If lngSelHeight < 1 Then Exit Sub
     
    ' Quitter si recordset vide
    Set rsfm = Me.RecordsetClone
    If rsfm.RecordCount = 0 Then Exit Sub
     
    ' Quitter si premier enregistrement de la sélection est
    ' au dela du dernier enregistrement
    rsfm.MoveLast
    If lngSelTop > rsfm.RecordCount Then Exit Sub
     
    ' Aller au premier enregistrement lngSelTop
    rsfm.MoveFirst
    rsfm.Move (lngSelTop - 1)
     
    ' Nom du champ lié au contrôle F1
    strChamp = Me.F1.ControlSource
     
    On Error GoTo ErrH:
     
    ' Copier champ clé "réf produit"
    Set db = CurrentDb
    Set rs = db.OpenRecordset(strTableSelection, dbOpenDynaset)
    For i = 1 To lngSelHeight
        rs.AddNew
        rs(strChampSelection) = rsfm(strChamp)
        rs.Update
        rsfm.MoveNext
        If rsfm.EOF Then Exit For
    Next
     
    ExitHere:
    If rs.EditMode <> dbEditNone Then rs.CancelUpdate
    rs.Close
    Exit Sub
     
     
    ErrH:
    Select Case Err.Number
        Case 3022  ' Ignorer les doublons
            rs.CancelUpdate
            Resume Next
        Case Else
            MsgBox Err.Description, , "Erreur N. " & Err.Number & " dans Sub SauverSelection"
            Resume ExitHere
    End Select
     
    End Sub
    Commentaires :
    Le contrôle associé au champ clé peut avoir un nom différent du champ.
    C'est le cas dans mon formulaire "fmSelecteur" où le contrôle lié au champ clé s'appelle "F1".
    D'où la présence dans mon code de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    ' Nom du contrôle servant de clé pour mémoriser sélection
    Const strCtlCle As String = "F1"
    Les deux autres constantes désignent la table et le champ dans lesquels on fait la sauvegarde de la sélection.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    ' Nom de la table dans laquelle on va sauver la sélection
    Const strTableSelection = "tblSelectionFmSelecteur"
    ' Nom du champ dans la table
    Const strChampSelection = "Réf produit"
    ' Nom du contrôle servant de clé pour mémoriser sélection
    Pour plus de modularité j'ai déporté du code dans des Sub.
    ViderSelection() : vide la table de sauvegarde de la sélection
    SauverSelection2() : ajoute la sélection dans la table de sauvegarde. Gère l'erreur en cas de doublons.
    ToucheCTL() : met à jour une variable globale indiquant sur Ctl est enfoncée ou non, et affiche ou masque l'image imgToucheCtl.

    Les événements formulaire gérés sont :
    Sur Chargement <--> Form_Load
    Sur touche appuyée <--> Form_KeyDown
    Sur touche relâchée <--> Form_KeyUp
    Sur souris relâchée <--> Form_MouseUp

    Il reste une chose à gérer : Vider la table de sauvegarde de la sélection quand tu n'en a plus besoin.
    Sinon elle sera vidée si on fait une sélection et que Ctl n'est pas enfoncée.

    A+

  7. #27
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    188
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 188
    Points : 98
    Points
    98
    Par défaut
    Bonjour.

    J'ai une présentation à préparer pour demain après-midi, donc je ne vais pas avoir le temps de m'occuper à fonds de cette nouvelle solution.

    Juste un petit mot tout de même pour indiquer que je ne perds pas le fil...

    J'ai modifié mon système test en remplaçant tous les champs par ceux indiqués dans le code.

    Il faut juste penser à ajouter un champ texte, vraissemblablement dans l'entête du formulaire et lui donner le nom txtEnrSelectionnes. Sinon, le formulaire plante à l'ouverture.

    Ce contrôle indiquera le nombre de lignes sélectionnées. (Ce qui soit disant passant est génial puisque pour la suite j'avais besoin d'un système de ce type).

    Résultat :

    Un immense merci à LedZepII, le Guitar Hero du VBA !

    Voilà ce que ce système permet :

    1) On clique sur une ligne : la ligne est inscrite dans la table sélection.
    2) On clique et on maintient appuyé, on balaye vers le bas ou vers le haut, on relache : les lignes sont inscrites dans la table sélection.
    3) On clique sur une ligne : la ligne est inscrite dans la table sélection
    Puis
    On fait un SHIFT+Clic sur une ligne plus haut ou plus bas : les lignes sont inscrites dans la table sélection.
    4) A tout moment, on enfonce la touche CTRL, l'image apparait, on clique sur une ligne : la ligne est ajoutée dans la table sélection
    5) A tout moment, on enfonce la touche CTRL, l'image apparait, on clique sur une ligne, on maintient appuyé et on balaye : les lignes sont ajoutées dans la table sélection.

    Les opérations 1 à 3 vident la table sélection avant de la remplir.
    Les opérations 4 et 5 ajoutent la sélection (seulement les lignes qui ne osnt pas déja dans la tables sélection) aux lignes déja inscrites dans la table sélection.

    C'est génial !

    Mais je pense qu'il va me faloir un moment pour comprendre tout...

    Vraiment un très grand merci !

    MERCI !
    MERCI !
    MERCI !

  8. #28
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    188
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 188
    Points : 98
    Points
    98
    Par défaut
    Bonjour.
    Présentation en cours d'impression, du coup, je prend le temps de lire le code.

    Bon ça fonctionne, mais je me demande s'il manque pas un point quelque part.

    Genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    ExitHere:
    If rs.EditMode <> dbEditNone Then rs.CancelUpdate
    rs.Close
    Exit Sub
    Ne faut-il pas ecrire db.EditNone

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    If rs.EditMode <> db.EditNone Then rs.CancelUpdate
    Encore merci.

    PS : Ben non en fait faut rien toucher, j'ai voulu faire le malin et ça a planté. Je croyait que db quelquechose fonctionnait comme les rs quelque chose.
    Désolé...

  9. #29
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    188
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 188
    Points : 98
    Points
    98
    Par défaut
    Bon alors, voilà tout ce qu'on peut faire avec le code actuel :

    1) Clic sur une ligne, souris relâchée = la table tblSelectionFmSelecteur est vidée, la ligne est ajoutée à la table tblSelectionFmSelecteur.

    2) Clic sur une ligne, souris maintenue, balayage vers le haut ou vers le bas = la table tblSelectionFmSelecteur est vidée, toutes les lignes sélectionnées sont ajoutées à la table tblSelectionFmSelecteur.

    3) Clic sur une ligne, souris relâchée = la table tblSelectionFmSelecteur est vidée, la ligne est ajoutée à la table tblSelectionFmSelecteur (comme pour cas N°1)
    Puis
    Shift+Clic sur une ligne plus haut ou plus bas = la table tblSelectionFmSelecteur est vidée, toutes les lignes entre la première sélectionnée avec clic et la dernière sélectionnée avec Shift+Clic sont ajoutées à la table tblSelectionFmSelecteur

    4) N'importe quel type de sélection (Cas N°1 ou Cas N°2 ou cas N°3) = la table tblSelectionFmSelecteur est vidée, la(les) ligne(s) est(sont) ajoutée(s) à la table tblSelectionFmSelecteur (comme pour cas N°1, N°2 ou N°3)
    Puis
    CTRL+Clic sur une ligne, souris relâchée = La ligne sélectionnée est ajoutée à la table tblSelectionFmSelecteur si elle ne s'y trouve pas déjà.

    5) N'importe quel type de sélection (Cas N°1 ou Cas N°2 ou cas N°3) = la table tblSelectionFmSelecteur est vidée, la(les) ligne(s) est(sont) ajoutée(s) à la table tblSelectionFmSelecteur (comme pour cas N°1, N°2 ou N°3)
    Puis
    CTRL+Clic sur une ligne, souris maintenue, balayage vers le haut ou vers le bas = Les lignes les lignes sélectionnées sont ajoutées à la table tblSelectionFmSelecteur si elles ne s'y trouvent pas déjà.

    Pour ces cas de figure, rien à dire, sauf merci LedZepII

    J'ai fait la modif suivante :

    Le formulaire fmSelecteur est maintanant basé sur une requête :
    Code vb : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     SELECT Produits.[Réf produit], Produits.PRPRTR_DNMNTN, Produits.PRPRTR_DNMNTN_CPLMNTR, Produits.PRPRTR_DT_NSSNC, Produits.PRPRTR_ADRSS_RUE, Produits.PRPRTR_ADRSS_CMPLT_RUE, Produits.PRPRTR_ADRSS_CD_PSTL, Produits.PRPRTR_ADRSS_CMMN, IIf([tblSelectionFmSelecteur]![Réf produit] Is Not Null,"S","N") AS [Select]
    FROM Produits LEFT JOIN tblSelectionFmSelecteur ON Produits.[Réf produit] = tblSelectionFmSelecteur.[Réf produit];

    Le champ Select est ajouté dans le détail du formulaire. Il est formaté pour être en arrière plan et occuper toute la hauteur et la largeur de la ligne.

    Grâce à la requête ci-dessus, ce champ prends la valeur "S" quand un enregistrement du formulaire se trouve aussi dans la table tblSelectionFmSelecteur.

    Une mise en forme auto me permet d'attribuer une couleur différente au champ.

    Du coup, les lignes incluses dans la table tblSelectionFmSelecteur sont de couleur différente, comme en surbrillance…

    Je sais pas si c'est la bonne ou la meilleure méthode, mais c'est la seule que je sais faire tout seul.

    Problèmes :
    1) Pour que cela fonctionne, il faudrait un Me.requery qui se déclencherait après la mise à jour de la table tblSelectionFmSelecteur

    J'ai tenté de le mettre en fin de Sub SauverSelection2
    Code vb : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     If rs.EditMode <> dbEditNone Then rs.CancelUpdate
    rs.Close
    Me.Requery
    Exit Sub
    Conséquence :
    tout marche et les lignes que je sélectionne sont pour ainsi dire en sur brillance de manière auto, ce qui facilite des ajout de sélection (par CTRL+Clic par exemple) et qui est très utile pour la phase 2 (le problème 2, plus exactement), mais la fonction de sélection par Shift+clic ne fonctionne plus (c'est normal, puisque le Me.Requery se déclenche au premier Clic et annihile la possibilité de faire le Shift pour le second clic, qui du coup est traité comme un clic unique)

    Solution (comprenez : Ma solution qui marche pas)
    J'ai ajouté un code équivalent à celui utilisé pour la touche CTRL, mais basé sur la touche Shift, avec image imgToucheShift et tout.
    Code vb : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    'En entête de formulaire
    Dim bToucheShift As Boolean
    Code vb : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
    Call ToucheCTL(Shift, True)
    Call ToucheShift(Shift, True)
    End Sub
    Private Sub Form_KeyUp(KeyCode As Integer, Shift As Integer)
    Call ToucheCTL(Shift, False)
    Call ToucheShift(Shift, False)
    End Sub
    Code vb : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     Private Sub ToucheShift(Shift As Integer, bKeyDown As Boolean)
    If (Shift And acShiftMask) = acShiftMask Then
       bToucheShift = bKeyDown
       If Me.imgToucheShift.Visible <> bToucheShift Then
       Me.imgToucheShift.Visible = bToucheShift
       End If
    End If
    End Sub
    Du coup en fin de Private Sub SauverSelection2
    Code vb : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    ExitHere:
    If rs.EditMode <> dbEditNone Then rs.CancelUpdate
    rs.Close
        'Bidouille
        If Not bToucheShift Then
        Me.Requery
        End If
    Exit Sub
    Résultat : ça n'a fait que déplacer le problème, c'est maintenant le Requery qui ne marche plus sur Shift+Clic et en plus il faut aussi faire Shift+Clic lors du premier Clic d'une combinaison Clic suivi de Shift+Clic (cas N°3)


    1bis) La sélection multiple c'est bien, mais quand on à plus de tentes lignes éparses et qu'en plus on a décidé de mettre un Requery pour faire de la sur brillance (c'est bien connu, On est un con, et y'a bien que les lignes qui soient brillantes…), il se produit un phénomène désagréable : le focus revient toujours en début de tableau.

    Du coup pour sélectionner 4 ou 5 lignes éparses, il faut à chaque sélection refaire le défilement du tableau. Ce serait mieux le focus restait sur la dernière ligne sélectionnée.

    Ce devrait être possible en mettant un N° auto dans la table tblSelectionFmSelecteur et en demandant au focus de ce placer sur l'enregistrement du fmSelecteur correspondant au Max de ce N° auto (ce que je ne sais pas faire bien sur, sinon je serais pas en train de l'écrire…)


    2) Un système que je pense avoir compris empêche la création de doublon lorsque les enregistrements sont recopiés dans la table tblSelectionFmSelecteur.

    En fait, comme les deux tables on une clé primaire, si on essai de copier dans la table tblSelectionFmSelecteur un enregistrement qui s'y trouve déjà, une erreur se produit.
    Code vb : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    ErrH:
    Select Case Err.Number
        'Erreur présence de doublons
        Case 3022
        'Ne pas mettre à jour la table pour cette ligne
            rs.CancelUpdate
            Resume Next
        'Dans tous les autres cas d'erreur
        Case Else
            'Message box avec N° d'erreur
            MsgBox Err.Description, , "Erreur N. " & Err.Number & " dans Sub SauverSelection"
            Resume ExitHere
    End Select
    End Sub
    Le système abandonne la mise à jour pour la ligne concernée par ce type d'erreur.

    Dans les systèmes de sélection, et du moins dans celui que je cherche à mettre en place, quand on sélectionne de nouveau une ligne sélectionnée, elle est retirée de la sélection.

    Dans le cas présent, il faudrait que le système , au lieu d'abandonner la mise à jour, supprime la ligne de la table tblSelectionFmSelecteur.

    Je m'excuse pour la longueur, mais je continue mes recherches, convaincu que cette fonctionnalité sera utile à un paquet de gens. Aussi j'essaye de donner un max d'info pour que si quelqu'un a des bribes de solution, on finisse par y arriver.

    Donc pour résumer :

    Le dernier code proposé par LedZepII est le bon, et son système de fonctionnement est très satisfaisant. Il y manque juste deux choses :

    Un Me.requery, ou tout autre chose (si possible ne faisant appel ni à une case à cocher, ni à un bouton radio, c'est trop illisible…)pour que les lignes sélectionnées soient visibles comme telles dans le formulaire fmSelecteur. (En fait, si j'ai bien compris, le formulaire fmSelection ne sert que pour la démo, mais j'ai déjà vu des logiciels où la fenêtre était divisée en deux, avec d'un coté zone de sélection et de l'autre liste résultat. Je pense que cette config. pourrait en intéresser certains).

    Remplacer l'annulation de la mise à jour en cas de doublon (la ligne n'est donc pas rajouté en double) par une suppression de la ligne en question dans la table tblSelectionFmSelecteur.
    Ainsi quand on re-cliquera sur une ligne déjà dans la table tblSelectionFmSelecteur à l'aide du présent CTRL+Clic, ou de CTRL+CLI maintenu suivi d'un balayage, cette ligne ou ces lignes seront retirées de la table tblSelectionFmSelecteur et donc considérées comme ne faisant plus partie des lignes à traiter.

    Une fois cette étape réglée, il me suffira de rajouter des boutons qui déclencheront les actions souhaitées à partir de la table tblSelectionFmSelecteur ainsi constituée (copier, mettre à jour, éditer des états…)

    Bien sur, si LedZepII, qui semble fabriquer du code comme moi je dis des c**neries, veut absolument griller la priorité à tout le monde et donner de suite la solution… Je ne pourrais que le remercier…Encore…

    Encore un grand merci.

  10. #30
    Expert éminent
    Avatar de LedZeppII
    Homme Profil pro
    Maintenance données produits
    Inscrit en
    Décembre 2005
    Messages
    4 485
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Maintenance données produits
    Secteur : Distribution

    Informations forums :
    Inscription : Décembre 2005
    Messages : 4 485
    Points : 7 759
    Points
    7 759
    Par défaut
    Bonjour,

    J'ai essayé de faire ce que tu voulais.
    - Mise en évidence des enregistrements sélectionnés.
    - Utilisation de la touche Shift.
    - Désélection des enregistrements déjà sélectionnés, sauf si Shift est appuyé.
    - Repositionnement après Requery.

    Il y effectivement un problème pour gérer Ctl et Shift en même temps.
    Je me suis apperçu que le paramètre Shift dans l'événement KeyUp ne donne pas l'état réel des touches Ctl et Shift.

    Ma section Déclaration est maintenant celle-ci
    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
    Option Explicit
     
    ' Fonction et constantes API pour lire l'état d'une touche
    Const VK_LSHIFT As Long = &HA0
    Const VK_RSHIFT As Long = &HA1
    Const VK_LCONTROL As Long = &HA2
    Const VK_RCONTROL As Long = &HA3
    Private Declare Function GetKeyState Lib "user32.dll" (ByVal nVirtKey As Integer) As Byte
     
    ' Nom de la table dans laquelle on va sauver la sélection
    Const strTableSelection = "tblSelectionFmSelecteur"
    ' Nom du champ dans la table
    Const strChampSelection = "Réf produit"
    ' Nom du contrôle servant de clé pour mémoriser sélection
    Const strCtlCle As String = "F1"
     
    ' Variable pour savoir si la touche "Control" est appuyée
    Dim bToucheCTL As Boolean
    ' Variable pour savoir si la touche "Shift" est appuyée
    Dim bToucheShift As Boolean
    J'ai ajouté la déclaration d'une fonction de l'API pour lire l'état des touche Ctl et Shift, et une variable pour mémoriser l'état de la touche Shift.

    Les procédure KeyDown et KeyUp sont inchangées.
    Voici le nouveau code la procédure ToucheCTL :
    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
    Private Sub ToucheCTL(Shift As Integer, bKeyDown As Boolean)
    bToucheCTL = False
    bToucheShift = False
    If bKeyDown Then
       If (Shift And acCtrlMask) = acCtrlMask Then bToucheCTL = True
       If (Shift And acShiftMask) = acShiftMask Then bToucheShift = True
    Else
       ' Dans l'événement KeyUp la variable Shift ne réflète pas
       ' l'état réel des touches Ctl, Shift.
       ' On utilise donc la fonction de l'API GetKeyState
       If (GetKeyState(VK_LCONTROL) And &H80) = &H80 Then bToucheCTL = True
       If (GetKeyState(VK_RCONTROL) And &H80) = &H80 Then bToucheCTL = True
       If (GetKeyState(VK_LSHIFT) And &H80) = &H80 Then bToucheShift = True
       If (GetKeyState(VK_RSHIFT) And &H80) = &H80 Then bToucheShift = True
    End If
    ' Affichage/Masquage Image touches
    ' Pour éviter scintillement, on teste s'il y a vraiment
    ' lieu de changer la propriété Visible
    If Me.imgToucheCtl.Visible <> bToucheCTL Then
       Me.imgToucheCtl.Visible = bToucheCTL
    End If
    If Me.imgToucheShift.Visible <> bToucheShift Then
       Me.imgToucheShift.Visible = bToucheShift
    End If
    End Sub
    Le formulaire comporte un nouveau contrôle image : imgToucheShift.

    Dans la procédure SauverSelection2 j'ai changé la gestion d'erreur relative aux doublons
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    ErrH:
    Select Case Err.Number
        Case 3022  ' Ignorer les doublons
            rs.CancelUpdate
            If Not bToucheShift Then
               rs.FindFirst "[" & strChampSelection & "]=" & rsfm(strChamp)
               If Not rs.NoMatch Then rs.Delete
            End If
            Resume Next
        Case Else
            MsgBox Err.Description, , "Erreur N. " & Err.Number & " dans Sub SauverSelection"
            Resume ExitHere
    End Select
    En cas de doublon :
    - Si la touche Shift est enfoncé on annule l'ajout.
    - Si elle est relâchée, on annule l'ajout et on suprime l'enregistrement correspondant (désélection).

    J'ai modifié la procédure Form_MouseUp. Elle appelle une procédure ActualiserFormulaire qui va faire le Requery,
    se repositionner sur le bon enregistrement, et rétablir la sélection.
    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
    Private Sub Form_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
    Dim lngSelTop As Long, lngSelHeight As Long
    Dim lngCurrRec As Long, lngCurrSecTop As Long
     
    lngCurrRec = Me.CurrentRecord
    lngCurrSecTop = Me.CurrentSectionTop
    lngSelTop = Me.SelTop: lngSelHeight = Me.SelHeight
     
    If Not bToucheCTL Then Call ViderSelection
        SauverSelection2 lngSelTop, lngSelHeight
        If CurrentProject.AllForms("fmSelection").IsLoaded Then
           Forms("fmSelection").Requery
        End If
        ActualiserFormulaire lngSelTop, lngSelHeight, lngCurrRec, lngCurrSecTop
    Me.txtEnrSelectionnes = DCount("*", strTableSelection)
    End Sub
    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
    Sub ActualiserFormulaire(lngSelTop As Long, lngSelHeight As Long, _
                             lngCurrRec As Long, lngCurrSecTop As Long)
    Dim lngDetailHeight As Long, lngHeaderHeight As Long
    Dim lngRowNum As Long, lngRecNumRow1 As Long
     
    On Error Resume Next
    lngHeaderHeight = Me.Section(acHeader).Height * IIf(Me.Section(acHeader).Visible = True, 1, 0)
    On Error GoTo 0
    lngDetailHeight = Me.Section(acDetail).Height
     
    ' Numéro de ligne de Me.CurrentRecord
    lngRowNum = 1 + (lngCurrSecTop - lngHeaderHeight) / lngDetailHeight
    ' Numéro enregistrement de la ligne 1
    lngRecNumRow1 = lngCurrRec - lngRowNum + 1
     
    Application.Echo False
    DoCmd.Requery
    DoCmd.GoToRecord acActiveDataObject, , acLast
    DoCmd.GoToRecord acActiveDataObject, , acGoTo, lngRecNumRow1
    DoCmd.GoToRecord acActiveDataObject, , acGoTo, lngCurrRec
     
    Me.SelTop = lngSelTop
    Me.SelHeight = lngSelHeight
    Application.Echo True
    End Sub
    La mise en évidence des enregistrements sélectionnés se fait comme toi, avec un contrôle zone de texte contenant "N" ou "S", auquel on applique une mise en forme conditionnelle.

    Le formulaire fmSelection ne sert plus à rien.
    Son but était de vérifier en temps réel le contenu de la table tblSelectionFmSelecteur.
    Pareil pour les images illustrant l'état des touches Ctl et Shift.
    C'est juste un moyen de contrôler visuellement le contenu des variables bToucheCTL et bToucheShift.

    J'espère que ma logique de repositionnement (ActualiserFormulaire) marche dans tous les cas.
    Il y a une configuration où ça ne fonctionne pas, c'est l'affichage en mode feuille de données.
    Mais tu ne dois pas t'en servir, puisque tu as un contrôle avec mise en forme conditionnelle qui occupe toute la largeur de la ligne.

    Lorsque tu seras près de la version finale de ton formulaire, je pense qu'on peut supprimer les procédures événementielles Form_KeyDown et Form_KeyUp.
    L'appel de la procédure ToucheCTL pourra se faire depuis la procédure événementielle Form_MouseUp, avec l'argument Shift de cette dernière.

    A+

  11. #31
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    188
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 188
    Points : 98
    Points
    98
    Par défaut
    Bonjour.

    J'ai recopié et fait les modification.

    Bien sur, ça marche.

    Sauf :

    Lors d'une tentative de sélection dans le but de sortir un enregistrement d'un bloc de lignes déjà sélectionnées.

    Explication :

    On a des lignes contiguës sélectionnées (peu importe comment, toutes les fonctions sont OK).
    On presse la touche CTRL pour aller en "sélectionner" une ou plusieurs au milieu de ce groupe.

    Selon la logique souhaitée pour ce système, cette ligne sera retirée de la table tblSelectionFmSelecteur.

    Au relachement de souris, ça bogue,

    le débogueur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Erreur d'exécution 3077
    Erreur de syntaxe (opérateur absent) dans l'expression
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    rs.FindFirst "[" & strChampSelection & "]=" & rsfm(strChamp)
    Surligné jaune dans le bloc ErrH
    Après une petite recherche sur le net sur la fonction FindFirst, j'ai trouvé cette modif :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    rs.FindFirst "[" & strChampSelection & "]='" & rsfm(strChamp) & "'"
    Il faut lire apostrophe, guillemets, & rsfm(strChamp) & guillemets, apostrophe, guillemets
    Je sais pas si c'est la bonne méthode, mais une fois cette modification opérée, ça fonctionne niquel.

    Pareil pour les images illustrant l'état des touches Ctl et Shift.
    C'est juste un moyen de contrôler visuellement le contenu des variables bToucheCTL et bToucheShift.
    Si j'ai bien compris, il suffira de supprimer ce bloc, quand je n'aurais plus besoin des images (moi je croyais que ce bloc et l'affichage des image servait juste à vérifier que la commande CTRL ou SHIFT était fonctionnelle…)

    J'espère que ma logique de repositionnement (ActualiserFormulaire) marche dans tous les cas.
    .
    Je ne lui ai pas trouvé de faille à l'utilisation.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    ' Affichage/Masquage Image touches
    ' Pour éviter scintillement, on teste s'il y a vraiment
    ' lieu de changer la propriété Visible
    If Me.imgToucheCtl.Visible <> bToucheCTL Then
       Me.imgToucheCtl.Visible = bToucheCTL
    End If
    If Me.imgToucheShift.Visible <> bToucheShift Then
       Me.imgToucheShift.Visible = bToucheShift
    End If
    Lorsque tu seras près de la version finale de ton formulaire, je pense qu'on peut supprimer les procédures événementielles Form_KeyDown et Form_KeyUp.
    L'appel de la procédure ToucheCTL pourra se faire depuis la procédure événementielle Form_MouseUp, avec l'argument Shift de cette dernière.
    Certes ! Je n'aurais pas mieux dit !
    En fait j'aurais rien dit. Parce que si cette modification suppose autre chose que de supprimer les bloc Form_KeyDown et Form_KeyUp dans le code, je vais pas m'y amuser.
    J'ai à peu près pigé le fonctionnement de l'argument Shift, mais je ne saurait pas le mettre en œuvre.

    Autrement, le comportement de ce système de sélection est exactement celui que je recherchais.

    Il y a une petite curiosité quand on vient de faire une sélection, et que on clique à l'extérieur du sélecteur, dans la zone détail du formulaire.
    La sélection est maintenue (tant dans la table qu'avec les indicateurs). On peut ajouter ou supprimer des lignes en appuyant sur la touche CTRL.
    En revanche, quand on utilise la touche Shift, la sélection est vidée, et seule la ligne cliquée est "sélectionnée".
    Personnellement, ça me convient tout à fait, ça donne une logique de "faites votre sélection d'un seul coup". Je me suis même demandé si je n'allais pas associer la commande vider sélection à mon contrôle Select.
    Ainsi, si l'utilisateur clique en dehors du sélecteur, la sélection est perdue, comme c'est le cas dans les gestionnaires de fichiers.


    Le système a cependant une limite.

    J'ai tenté de sélectionner un gros bloc de lignes et le système a planté total !

    Détail :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Erreur d'éxécution 2505
    Une expressionde l'argument 4 comporte une valeur incorecte pour cet argument
    Il est vivement conseillé de choisir l'option débogage.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    DoCmd.GoToRecord acActiveDataObject, , acGoTo, lngRecNumRow1
    Surligné en jaune dans le bloc Sub ActualiserFormulaire
    A ce moment, incapable de trouver le problème je stoppe le débogueur et je ferme VBA. Access patine et je suis obligé de le fermer.
    Si je ne prends pas l'option débogage, seul un ALT+CTRL+SUPPR sauve la situation…

    Hypothèse :
    En fait j'ai fait plusieurs essais : 99 lignes c'est OK, 100 c'est KO.

    Donc:
    Soit il existe une variable qui lit le nombre de lignes et cette variable est limitée à 99 lignes,
    Soit il existe une variable qui lit le nombre de lignes et cette variable est limitée à 2 chiffres.

    Mais autant vous dire que s'il m'a fallu presque une semaine pour commencer à appréhender le premier code, sans pour autant savoir en faire quoi que ce soit, il m'en faudra certainement beaucoup plus pour celui-là qui semble faire appel à des fonction cabalistiques…

    Je serrais tenté de dire que c'est la faute à une varible, mais elles sont toutes au moins déclarées en Long.

    J'avais déja trouvé une fonctionalité d'Access qui semblait bloquer aux alentours de 250 lignes. Est ce que c'est pareils ?

    Encore merci.

  12. #32
    Expert éminent
    Avatar de LedZeppII
    Homme Profil pro
    Maintenance données produits
    Inscrit en
    Décembre 2005
    Messages
    4 485
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Maintenance données produits
    Secteur : Distribution

    Informations forums :
    Inscription : Décembre 2005
    Messages : 4 485
    Points : 7 759
    Points
    7 759
    Par défaut
    Bonsoir,

    Après une petite recherche sur le net sur la fonction FindFirst, j'ai trouvé cette modif :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    rs.FindFirst "[" & strChampSelection & "]='" & rsfm(strChamp) & "'"
    Il faut lire apostrophe, guillemets, & rsfm(strChamp) & guillemets, apostrophe, guillemets
    Je sais pas si c'est la bonne méthode, mais une fois cette modification opérée, ça fonctionne niquel.
    C'est la bonne méthode pour un champ de type texte.
    Le mien était numérique.

    Si j'ai bien compris, il suffira de supprimer ce bloc, quand je n'aurais plus besoin des images (moi je croyais que ce bloc et l'affichage des image servait juste à vérifier que la commande CTRL ou SHIFT était fonctionnelle…)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    ' Affichage/Masquage Image touches
    ' Pour éviter scintillement, on teste s'il y a vraiment
    ' lieu de changer la propriété Visible
    If Me.imgToucheCtl.Visible <> bToucheCTL Then
       Me.imgToucheCtl.Visible = bToucheCTL
    End If
    If Me.imgToucheShift.Visible <> bToucheShift Then
       Me.imgToucheShift.Visible = bToucheShift
    End If
    C'est exact. C'est ça qu'on peut enlever.
    Tu peux le laisser si tu penses que ça peut aider l'utilisateur.


    L'erreur sur une grande sélection vient du fait que le nombre de lignes sélectionnées est supérieur au nombres de lignes affichées par le formulaire.
    Citation Envoyé par LedZeppII
    J'espère que ma logique de repositionnement (ActualiserFormulaire) marche dans tous les cas.
    La réponse est donc Non.
    Ma logique était basée sur le fait que l'enregistrement actif était une ligne visible.
    Or, si le formulaire peut afficher 10 lignes max, par exemple, et qu'on en sélectionne 15, la première ligne de sélection est dans le meilleur des cas 5 lignes au dessus de la première ligne visible.
    Le problème, lorsqu'on fait défiler les enregistrements avec la barre de défilement vertical, est qu'on n'a aucun moyen de savoir quel est l'enregistrement correspondant à la première ligne visible.
    Il faut que je revoie ça, mais je ne le sent pas.

    Je peux éventuellement le faire avec une fonction de l'API, à condition que ton formulaire soit un formulaire principal.
    Si c'est un sous-formulaire, la fonction de l'API ne fonctionne pas directement.
    Il faut au préalable trouver le handler (sorte d'identifiant) de la barre de défilement vertical (pas mal de code supplémentaire).
    Problème que l'on a pas avec un formulaire principal, car on a pas besoin du handler de la barre de défilement vertical.

    A+

  13. #33
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    188
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 188
    Points : 98
    Points
    98
    Par défaut
    Bonsoir et encore merci de la rapidité de réponse et surtout de l'aide sans faille que vous m'apportez depuis le début de ce topic.
    Je n'y serais jamais arrivé seul, c'est maintenant une absolue certitude.
    Citation Envoyé par LedZeppII Voir le message
    Bonsoir,
    C'est la bonne méthode pour un champ de type texte.
    Le mien était numérique.
    Si j'ai fait cette modif, c'est parceque j'avais un bogue quand j'utilisait la touche CTRL dans une sélection déja opérante et que le debogueur m'indiquait cette ligne comme précisé dans mon dernier message.
    Je vais re-essayer avec le code d'origine.
    L'erreur sur une grande sélection vient du fait que le nombre de lignes sélectionnées est supérieur au nombres de lignes affichées par le formulaire.
    Je n'ai pas ma base test sous les yeux, mais je suis pratiquement sur que je suis arrivé à sélectionner plusieurs lignes en dehors du nombre affiché par le formulaire.

    Au maximum j'ai 20 lignes à l'écran (j'ai fait des lignes épaisses pour y voir clair) et j'ai pu en sélectionner plusieurs dizaines en dehors de la zone de visualisation (le record avec succes étant de 99...)

    Je n'ai pas assez de maîtrise pour en juger, mais c'est currieux que cela fonctionne avec 99 et pas 100 par exemple. Ce sont ces chiffres "couperet" qui me font penser qu'il y un genre de limite physique du type variable à 2 chiffres ou variable inférieure à 100.

    Ou bien quand vous indiquez que "le nombres de lignes affichées par le formulaire", il faut comprendre que si à l'écran je n'ai que 20 lignes, le formulaire considère qu'il ne peut en afficher au max que 99.

    La réponse est donc Non.
    Ma logique était basée sur le fait que l'enregistrement actif était une ligne visible.
    Or, si le formulaire peut afficher 10 lignes max, par exemple, et qu'on en sélectionne 15, la première ligne de sélection est dans le meilleur des cas 5 lignes au dessus de la première ligne visible.
    Le problème, lorsqu'on fait défiler les enregistrements avec la barre de défilement vertical, est qu'on n'a aucun moyen de savoir quel est l'enregistrement correspondant à la première ligne visible.
    Je n'avais pas fait attention à cette particularité. Il faudrait que j'essaye pour me rendre compte.
    Mais, ne pourrait-on pas, "plus simplement" si j'ose me permettre de m'exprimer ainsi, indiquer que l'enregistrement actif aille se positionner sur la dernière ligne de sélection qui devrait être toujours visible plutôt que sur la première ? (quelque chose qui serrait = SelTop+SelHeight, ou last au lieu de first...)
    Il faut que je revoie ça, mais je ne le sent pas.
    Aucun soucis, vous avez déja fait plus que ce que je n'espérait.
    Je suis plus que content et plus que reconnaissant du travail que vous avez accompli.
    Si d'autres intervenants sont interressés par ce système et veulent le pousser encore, ils aurront déja de très solides bases, et même plus,me semble-t-il...
    Je peux éventuellement le faire avec une fonction de l'API, à condition que ton formulaire soit un formulaire principal.
    Si c'est un sous-formulaire, la fonction de l'API ne fonctionne pas directement.
    Il faut au préalable trouver le handler (sorte d'identifiant) de la barre de défilement vertical (pas mal de code supplémentaire).
    Problème que l'on a pas avec un formulaire principal, car on a pas besoin du handler de la barre de défilement vertical.
    Si cela signifie que le code actuel fonctionne sur des sous-formulaires (ce que je n'ai pas encore testé) mais qu'il est limité à 99 lignes de sélection et qu'augmenter ce nombre de lignes le rendra inutilisable sur des sous-formulaires, je garde le code actuel. Pour moi, c'est vraiement important que cela fonctionne sur des sous-formulaires.

    Encore une fois mille merci pour votre aide. Vous faites honneur à ce site.

  14. #34
    Expert éminent
    Avatar de LedZeppII
    Homme Profil pro
    Maintenance données produits
    Inscrit en
    Décembre 2005
    Messages
    4 485
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Maintenance données produits
    Secteur : Distribution

    Informations forums :
    Inscription : Décembre 2005
    Messages : 4 485
    Points : 7 759
    Points
    7 759
    Par défaut
    Rebonsoir,

    Je pas de problème avec une sélection de plus de 100 enregistrements.
    Si le problème venait d'une capacité de variable, la valeur serait plutôt un multiple de 16 ou de 8.

    Le problème que j'ai constaté, pour ma part, est le suivant :
    On part de l'hypothèse que le formulaire a 20 lignes.
    On clique sur le 10ème enregistrement.
    On fait défiler les enregistrements de telle sorte que la première ligne soit par exemple le 30ème enregistrement.
    En maintenant Ctl+Shift, on clique sur le 35ème.
    L'enregistrement courant (le 10ème) est en dehors de l'écran.
    -> bogue.
    En fait c'est pire que ce que je croyais.
    Ça bogue dès que l'enregistrement actif est en dehors des 20 lignes affichées.
    Cela vient de ce que dans cette ligne, le calcul est erroné
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    lngRowNum = 1 + (lngCurrSecTop - lngHeaderHeight) / lngDetailHeight
    à cause de lngCurrSecTop (Me.CurrentSectionTop) qui contient une valeur beaucoup trop grande.
    La conclusion est que Me.CurrentSectionTop ne contient une valeur correcte que si l'enregistrement actif est visible.

    J'ai constaté que lorsque l'enregistrement actif n'est pas visible, mon calcul renvoie dans lngRowNum un numéro de ligne supérieur au nombre de lignes du formulaire en continu (20 lignes avec le même exemple).
    J'ai ajouté un test pour détecter ce cas et repositionner le formulaire sur le premier enregistrement de la sélection.
    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
    Sub ActualiserFormulaire(lngSelTop As Long, lngSelHeight As Long, _
                             lngCurrRec As Long, lngCurrSecTop As Long)
    Dim lngDetailHeight As Long, lngHeaderHeight As Long, lngFooterHeight As Long
    Dim lngRowNum As Long, lngRecNumRow1 As Long
    Dim lngRowMax As Long
     
    On Error Resume Next
    lngHeaderHeight = Me.Section(acHeader).Height * IIf(Me.Section(acHeader).Visible = True, 1, 0)
    lngFooterHeight = Me.Section(acFooter).Height * IIf(Me.Section(acFooter).Visible = True, 1, 0)
    On Error GoTo 0
    lngDetailHeight = Me.Section(acDetail).Height
     
    ' Numéro de ligne de Me.CurrentRecord
    lngRowNum = 1 + (lngCurrSecTop - lngHeaderHeight) / lngDetailHeight
    ' Numéro enregistrement de la ligne 1
    lngRecNumRow1 = lngCurrRec - lngRowNum + 1
    ' Numéro ligne max
    lngRowMax = (Me.InsideHeight - lngHeaderHeight - lngFooterHeight) / lngDetailHeight
     
    Application.Echo False
    Me.Requery
    DoCmd.GoToRecord acActiveDataObject, , acLast
    If lngRowNum <= lngRowMax Then
        DoCmd.GoToRecord acActiveDataObject, , acGoTo, lngRecNumRow1
        DoCmd.GoToRecord acActiveDataObject, , acGoTo, lngCurrRec
    End If
    Me.SelTop = lngSelTop
    Me.SelHeight = lngSelHeight
    Application.Echo True
    End Sub
    Je viens de tester le formulaire fmSelecteur en tant que sous-formulaire d'un autre formulaire et ça fonctionne.
    A condition de corriger dans la sub ActualiserFormulaire (je l'ai fait dans la copie ci-dessus), une erreur.
    J'avais mis
    au lieu de

    Mais, ne pourrait-on pas, "plus simplement" si j'ose me permettre de m'exprimer ainsi, indiquer que l'enregistrement actif aille se positionner sur la dernière ligne de sélection qui devrait être toujours visible plutôt que sur la première ? (quelque chose qui serrait = SelTop+SelHeight, ou last au lieu de first...)
    Le problème est que lorsqu'on rétablit la sélection avec
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Me.SelTop = lngSelTop
    Me.SelHeight = lngSelHeight
    l'enregistrement actif de devient lngSelTop, c'est à dire le premier enregistrement de la sélection.
    Me.SelHeight ne fonctionne que de haut en bas.
    Je ne peux donc pas aller au dernier enregistrement de la sélection, puis effectuer une sélection de bas en haut.

    Le fond du problème est qu'il n'y a pas de fonctions pour agir sur la barre de défilement vertical, et surtout qu'on ne peux obtenir sa position.
    Ma procédure de replacement essaie de contourner cela en faisant plusieurs déplacements dans les enregistrements.
    Mais elle ne peut pas reproduire exactement ce qu'on peut faire avec la barre de défilement vertical.
    Elle y parvient seulement quand la sélection est faite dans les lignes affichées.

    Tu me confirme que c'est la configuration sous-formulaire qui t'intéresse ?
    Je peux écrire un code qui marchera pour des sous-formulaires.

    A+

  15. #35
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    188
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 188
    Points : 98
    Points
    98
    Par défaut
    Bonjour.

    Malheureusement, et contrairement à ce que j'ai indiqué ci-dessus, suite à un imprévu (causé par cet sa****rie de MapInfo) je n'ai as eu le temps de vérifier ni de confirmer quoi que ce soit ce matin.

    Je viens juste de lire en travers votre dernière réponse.

    Je ne voudrais pas vous faire travailler pour rien, ou pour quelque-chose qu'il faudra re-modifier , encore...

    Aussi, je vais avoir besoin d'un peu de temps pour regarder tout ça.

    Mais je vous tiens au courant.

    Encore merci.

  16. #36
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    188
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 188
    Points : 98
    Points
    98
    Par défaut
    Bonjour et encore un grand merci de travailler si tard. J'espère ne pas être la cause de cette insomnie…

    Effectivement, je n'avais pas fait le bon essai.

    Dans le but de "mesurer" le nombre de ligne max, j'ai fait défiler les lignes jusqu'à trouver la 99 ème.
    J'ai cliqué dessus.
    Ensuite je suis remonté jusqu'à la première sur laquelle j'ai fait un Shift+Clic.
    La sélection a fonctionné.
    C'est quand je suis redescendu vers la 99 ème pour en rajouter une 100 ème à l'aide de la touche CTRL+Clic que le bogue c'est produit.
    J'en ai donc déduit que seulement 99 lignes pouvaient être sélectionnées.

    Mais votre test met à mal le système avec beaucoup moins !

    En fait je n'avais jamais testé le Clic suivi de Shift+Clic en dehors de la plage d'affichage de mon formulaire, soit 10 lignes. C'est stupide de ma part, car le Shift+Clic sert surtout à sélectionner de grandes plages…

    J'ai fait l'essai suivant : clic sur une ligne = la ligne est sélectionnée.
    CTRL+Clic sur la ligne juste en dessous, clic maintenu, balayage vers le bas = les lignes sont sélectionnées, ajoutées à la table sélection en plus de la première ligne déjà sélectionnée.
    La sélection vient se positionner sans encombres sur la première ligne du bloc sélectionné avec CTRL+Clic+Balayage. Test réussi avec 406 lignes…

    Donc CTRL+Clic semble fonctionner sans rencontrer ce problème de lignes et d'affichage...

    PS :les plantages avec ce code sont particulièrement "plantants". Surtout dans le bloc ActualiserFormulaire. Je ne sais pas si c'est le cas chez vous, mais le debogage n'y suffit généralement pas et je suis obligé de sortir en vrac.

    J'en profite pour persister : j'ai ré-essayé avec le code d'origine pour cette ligne incluse dans ErrH
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Erreur d'exécution 3077
    Erreur de syntaxe (opérateur absent) dans l'expression
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    rs.FindFirst "[" & strChampSelection & "]=" & rsfm(strChamp)
    Surligné jaune dans le bloc ErrH
    Cette ligne semble poser problème chez moi. En revanche, quand je fait la modif suivante, plus de problèmes.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    rs.FindFirst "[" & strChampSelection & "]='" & rsfm(strChamp) & "'"
    Il faut lire apostrophe, guillemets, & rsfm(strChamp) & guillemets, apostrophe, guillemets
    Je ne sais que penser.

    En maintenant Ctl+Shift, on clique sur le 35ème.
    On maintient à la fois les touches CTRL et SHIFT au moment de cliquer ?!?!
    Si c'est bien CTRL et SHIFT en même temps en plus du Clic, je ne vois pas l'intérêt. Je ne me sert jamais de cette combinaison et le code précédent répond à toutes mes attentes (en dehors de ce petit soucis de lignes…) et toutes les combinaisons que j'espérait.

    Le problème est que lorsqu'on rétablit la sélection avec
    Code :
    Me.SelTop = lngSelTop
    Me.SelHeight = lngSelHeight
    l'enregistrement actif de devient lngSelTop, c'est à dire le premier enregistrement de la sélection.
    Me.SelHeight ne fonctionne que de haut en bas.
    D'où ma question peut-être maladroite : Ne peut-on pas faire que l'enregistrement actif devienne lngSelTop+lngSelHeight ?

    Mais ce doit être pour ça qu'il est possible de sélectionner sans encombres plus de 100 lignes en remontant. Car dans ce cas, la dernière ligne sélectionnée est en fait la première de la sélection est en plus elle est à l'écran. Donc ça marche...

    Par ailleurs, j'ai essayé d'intégrer le code sans les dernières modifications dans un sous formulaire, et il semble que le module ActualiserFormulaire doive quand même être remanié pour fonctionner, ne serrait-ce que sur un nombre de ligne inférieur ou égal au nombre de lignes d'affichage.

    Bon, tout ça c'est pour la partie pédagogique, si j'oses dire…

    Parce que la dernière modification du code apportée par LedZepII, résout le problème du nombre de lignes !!!!

    Par contre si on sélectionne 300 lignes, le curseur revient au début des 300 lignes (ou plus, ou moins…). Il faudra donc tout re-balayer pour atteindre la fin de la sélection et ajouter une ou plusieurs lignes situées après ces 300 lignes

    Je viens de tester le formulaire fmSelecteur en tant que sous-formulaire d'un autre formulaire et ça fonctionne.
    A condition de corriger dans la sub ActualiserFormulaire (je l'ai fait dans la copie ci-dessus), une erreur.
    J'avais mis[...]
    De mon côté, j'ai utilisé un formulaire vierge pour y insérer le formulaire fmSelecteur.
    ça marche pas. Il faut, je penses et j'ai testé avec succès, remplacer
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Private Sub Form_Load()
    Call ViderSelection
    DoCmd.OpenForm "fmSelection"
    Me.txtEnrSelectionnes = DCount("*", strTableSelection)
    Me.SetFocus
    End Sub
    Par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Private Sub Form_Load()
    Call ViderSelection
    DoCmd.OpenForm "fmSelection"
    Me.txtEnrSelectionnes = DCount("*", strTableSelection)
    Forms![Formulaire1]![fmSelecteur].SetFocus
    End Sub
    Tu me confirme que c'est la configuration sous-formulaire qui t'intéresse ?
    Honnêtement, ce qui m'intéresserait et intéresserait je penses le plus grand nombre de lecteurs, ce serait un système qui puisse marcher à la fois sur des formulaires et sur des sous-formulaires… Car personnellement je souhaiterais y recourir dans des formulaires et des sous-formulaires.

    Mais le test indiqué ci-dessus me laisse penser que les dernières modifications résolvent les problèmes de lignes et de sous-formulaires.

    A part l'affichage qui revient en début de sélection (et ce, uniquement dans le cas repéré d'un Clic suivi d'un Shift+Clic, et qui ne me semble pas problématique, je ne vois pas trop ce qui pourrait être amélioré.

    On peut imaginer d'expliquer la logique du système par le fait qu'il est plus rapide de sélectionner un très grosse portion de lignes avec Clic suivi de Shift+Clic beaucoup plus bas, et ensuite de supprimer les lignes en trop par CTRL+Clic, avec éventuellement balayage, plutôt que de sélectionner un gros bloc par Clic suivi de Shift+Clic, puis de reprendre plus bas avec CTRL+Clic+balayage pour ajouter un nouveau gros bloc de lignes.

    Personnellement, ces dernières modifications me vont très bien.

    Je vais continuer à faire quelques essais sur mon système test, puis ensuite sur mon système final…

    Je peux écrire un code qui marchera pour des sous-formulaires.
    Comme indiqué ci-dessus, j'ai cru comprendre que le code fonctionnait déjà pour des sous formulaires…
    Si j'ai bien compris, il ne me semble pas utile de modifier quoi que ce soit.
    Le essais que je fais au fur et à mesure que je rédige cette réponse semblent ne pas poser de problèmes…
    Si tel est le cas, je pense qu'il serait bon de poster, soit vous (après tout, vous avez tout fait...), soit moi, une version complète du dernier code, tel que vous l'avez modifié jusqu'à maintenant, un pour les formulaires, un pour les sous-formulaires, avant de clôturer.

    Je ne sais quoi ajouter, si ce n'est un merci de plus.

    MERCI.

  17. #37
    Expert éminent
    Avatar de LedZeppII
    Homme Profil pro
    Maintenance données produits
    Inscrit en
    Décembre 2005
    Messages
    4 485
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Maintenance données produits
    Secteur : Distribution

    Informations forums :
    Inscription : Décembre 2005
    Messages : 4 485
    Points : 7 759
    Points
    7 759
    Par défaut
    Bonsoir,

    Le plantage n'est qu'apparent.
    Il vient de la ligne
    dans la procédure ActualiserFormulaire.
    Elle fige l'affichage d'Access.

    Il faut forcer l'exécution de la ligne
    en déplacement la flèche jaune sur celle-ci puis continuer l'exécution.
    Ou alors la taper dans la fenêtre d'exécution (Ctrl+G) et appuyer sur Entrée.

    Voici le code complet de mon formulaire.
    J'ai retiré tout ce qui est relatif au formulaire fmSelection et aux deux images.
    J'ai également retiré la gestion des procédures événementielles KeyDown et KeyUp du formulaire.
    J'utilise l'argument Shift de l'événement Mouse_Up 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
    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
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    Option Compare Database
    Option Explicit
     
    ' Nom de la table dans laquelle on va sauver la sélection
    Const strTableSelection = "tblSelectionFmSelecteur"
    ' Nom du champ dans la table
    Const strChampSelection = "Réf produit"
    ' Nom du contrôle servant de clé pour mémoriser sélection
    Const strCtlCle As String = "F1"
     
    ' Variable pour savoir si la touche "Control" est appuyée
    Dim bToucheCTL As Boolean
    ' Variable pour savoir si la touche "Shift" est appuyée
    Dim bToucheShift As Boolean
     
    ' ------------------------
    ' Chargement du formulaire
    ' ------------------------
    Private Sub Form_Load()
    Call ViderSelection
    Me.Requery
    Me.txtEnrSelectionnes = DCount("*", strTableSelection)
    End Sub
    ' ---------------------
    ' Bouton Souris relâché
    ' ---------------------
    Private Sub Form_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
    Dim lngSelTop As Long, lngSelHeight As Long
    Dim lngCurrRec As Long, lngCurrSecTop As Long
     
    lngSelTop = Me.SelTop: lngSelHeight = Me.SelHeight
    ' Si pas de sélection, sortir
    If lngSelHeight < 1 Then Exit Sub
     
    lngCurrRec = Me.CurrentRecord
    lngCurrSecTop = Me.CurrentSectionTop
     
    bToucheCTL = ((Shift And acCtrlMask) = acCtrlMask)
    bToucheShift = ((Shift And acShiftMask) = acShiftMask)
     
    If Not bToucheCTL Then Call ViderSelection
    SauverSelection2 lngSelTop, lngSelHeight
    ActualiserFormulaire lngSelTop, lngSelHeight, lngCurrRec, lngCurrSecTop
    Me.txtEnrSelectionnes = DCount("*", strTableSelection)
    End Sub
    ' --------------------------------
    ' Suppression de la sauvegarde des
    ' enregistrements sauvegardé
    ' --------------------------------
    Private Sub ViderSelection()
    Dim db As DAO.Database
    Set db = CurrentDb
    db.Execute "DELETE FROM [" & strTableSelection & "]"
    End Sub
    ' -------------------------------------------
    ' Sauvegarde du champ clé des enregistrements
    ' sélectionnés
    ' -------------------------------------------
    Private Sub SauverSelection2(lngSelTop As Long, lngSelHeight As Long)
    Dim i As Long, rsfm As DAO.Recordset, db As DAO.Database, rs As DAO.Recordset
    Dim strChamp As String
     
    ' Quitter si recordset vide
    Set rsfm = Me.RecordsetClone
    If rsfm.RecordCount = 0 Then Exit Sub
     
    ' Quitter si premier enregistrement de la sélection est
    ' au dela du dernier enregistrement
    rsfm.MoveLast
    If lngSelTop > rsfm.RecordCount Then Exit Sub
     
    ' Aller au premier enregistrement lngSelTop
    rsfm.MoveFirst
    rsfm.Move (lngSelTop - 1)
     
    ' Nom du champ lié au contrôle F1
    strChamp = Me.F1.ControlSource
     
    On Error GoTo ErrH:
     
    ' Copier champ clé "réf produit"
    Set db = CurrentDb
    Set rs = db.OpenRecordset(strTableSelection, dbOpenDynaset)
    For i = 1 To lngSelHeight
        rs.AddNew
        rs(strChampSelection) = rsfm(strChamp)
        rs.Update
        rsfm.MoveNext
        If rsfm.EOF Then Exit For
    Next
     
    ExitHere:
    If rs.EditMode <> dbEditNone Then rs.CancelUpdate
    rs.Close
    Exit Sub
     
     
    ErrH:
    Select Case Err.Number
        Case 3022  ' Ignorer les doublons
            rs.CancelUpdate
            If Not bToucheShift Then
               ' Syntaxe pour un champ numérique.
               rs.FindFirst "[" & strChampSelection & "]=" & rsfm(strChamp)
               ' Syntaxe pour un champ texte.
               'rs.FindFirst "[" & strChampSelection & "]='" & rsfm(strChamp) & "'"
               If Not rs.NoMatch Then rs.Delete
            End If
            Resume Next
        Case Else
            MsgBox Err.Description, , "Erreur N. " & Err.Number & " dans Sub SauverSelection"
            Resume ExitHere
    End Select
     
    End Sub
    ' ---------------------------------------- '
    ' Actualisation du formulaire et tentative
    ' de repositionnement
    ' ---------------------------------------- '
    Sub ActualiserFormulaire(lngSelTop As Long, lngSelHeight As Long, _
                             lngCurrRec As Long, lngCurrSecTop As Long)
    Dim lngDetailHeight As Long, lngHeaderHeight As Long, lngFooterHeight As Long
    Dim lngRowNum As Long, lngRecNumRow1 As Long
    Dim lngRowMax As Long
     
    On Error Resume Next
    lngHeaderHeight = Me.Section(acHeader).Height * IIf(Me.Section(acHeader).Visible = True, 1, 0)
    lngFooterHeight = Me.Section(acFooter).Height * IIf(Me.Section(acFooter).Visible = True, 1, 0)
    On Error GoTo 0
    lngDetailHeight = Me.Section(acDetail).Height
     
    ' ligne = N° d'une ligne affichée par le formulaire continu.
    ' Compris entre 1 et Nombre max de lignes
    ' Par exemple 1 à 12, si le formulaire peut afficher 12 lignes simultanément
     
    ' Numéro de ligne de Me.CurrentRecord
    lngRowNum = 1 + (lngCurrSecTop - lngHeaderHeight) / lngDetailHeight
    ' Numéro enregistrement de la ligne 1
    lngRecNumRow1 = lngCurrRec - lngRowNum + 1
    ' Numéro ligne max
    lngRowMax = (Me.InsideHeight - lngHeaderHeight - lngFooterHeight) / lngDetailHeight
     
    Application.Echo False
    Me.Requery
    DoCmd.GoToRecord acActiveDataObject, , acLast
    If lngRowNum <= lngRowMax Then
       ' Enr. actif etait visible
        DoCmd.GoToRecord acActiveDataObject, , acGoTo, lngRecNumRow1
        DoCmd.GoToRecord acActiveDataObject, , acGoTo, lngCurrRec
        Me.SelTop = lngSelTop
        Me.SelHeight = lngSelHeight
    ElseIf lngSelHeight > lngRowMax Then
       ' Enr. actif n'était pas visible
       ' et selection > Nbre de lignes du formulaire
       ' - On va au dernier enregistrement de la selection
       '   en deux étapes pour être sur la dernière ligne.
       '   -> Sinon on se retrouve sur la première
       ' - On ne sélectionne que le dernier enregistrement.
       '   Sélection du bas vers le haut impossible avec SelTop/SelHeight
        Me.SelTop = lngSelTop + lngSelHeight - lngRowMax
        Me.SelTop = lngSelTop - 1 + lngSelHeight
        Me.SelHeight = 1
    Else
       ' Enr. actif n'était pas visible
       ' et selection <= Nbre de lignes du formulaire
       ' - On va au premier enregistrement de la sélection,
       '   il se postionne sur la première ligne
       ' - On recrée la sélection
        Me.SelTop = lngSelTop
        Me.SelHeight = lngSelHeight
    End If
    Application.Echo True
     
    End Sub
    J'ai également modifié le code de la procédure ActualiserFormulaire, pour traiter un peu mieux le cas où le premier enregistrement de la sélection n'est pas visible.
    * Si la sélection comporte plus de lignes que ne peut en afficher le formulaire :
    Le dernier enregistrement de la sélection est affiché sur la dernière ligne.
    On ne recrée pas la sélection (pas possible en allant du bas vers haut avec SelTop et SelHeight).
    Ça devrait répondre à ta question
    D'où ma question peut-être maladroite : Ne peut-on pas faire que l'enregistrement actif devienne lngSelTop+lngSelHeight ?
    * Si la sélection comporte un nombre de lignes inférieur ou égal au nombre de lignes que ne peut en afficher le formulaire :
    Le premier enregistrement de la sélection est sur la première ligne.
    On recrée la sélection.


    On maintient à la fois les touches CTRL et SHIFT au moment de cliquer ?!?!
    Si c'est bien CTRL et SHIFT en même temps en plus du Clic, je ne vois pas l'intérêt.
    Le maintient de CTL empêche de vider la table dans la quelle on sauvegarde la sélection.
    Exemple :
    Avec CTL enfoncé, je sélectionne les enregistrements 10 à 15.
    Puis (CTL toujours enconcé) 40 à 45.
    La sélection mémorisée est alors 10 à 15 + 40 à 45.
    CTL toujours maintenu enfoncé, je clique sur l'enregistrement 70 --> 10 à 15 + 40 à 45 + 70
    Je m'apprête à cliquer sur l'enregistrement 100.

    Cas 1 : Ni CTL ni SHIFT ne sont enfoncés.
    La sélection est effacée de la table, et devient l'enregistrement 100.

    Cas 2 : CTL n'est pas enfoncé et SHIFT est enfoncé.
    La sélection est effacée de la table, et la sélection mémorisée devient les enregistrements 70 à 100.

    Cas 3 : CTL est SHIFT sont enfoncés.
    La sélection n'est pas effacée de la table, et la sélection mémorisée devient les enregistrements 10 à 15 + 40 à 45 + 70 à 100.


    Sinon, j'ai fait des essais avec des fonctions de l'API windows pour tenter de manipuler directement la barre de défilement vertical.
    J'arrive à faire défiler les enregistrements sans avoir à faire des DoCmd.GoToRecord, mais cela crée un autre problème.
    La sélection est recrée, mais ellse se décale selon une logique qui m'échappe, dès qu'on clique sur la barre de défilement ou qu'on agit sur la molette de la souris.
    Il y a donc un problème d'interaction entre le fait de créer une sélection avec SelTop/SelHeight et le défilement des enregistrements.

    Je pense que les gens qui ont travaillé sur la fonctionnalité du sélecteur d'enregistrement seraient surpris de voir l'usage qu'on en fait.
    Je suis persuadé qu'il n'a pas été conçu dans le sens d'une sélection multiple non contigüe.
    Mon code fonctionne tant bien que mal, mais c'est de la bidouille.

    A+

  18. #38
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    188
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 188
    Points : 98
    Points
    98
    Par défaut
    Bonjour.

    J'ai pas trouvé le smiley qui tombe en poussière, pétrifié tellement il en croit pas ses yeux...

    Merci donc...

    J'ai recopié le dernier code qui fonctionne, et c'est au moment d'écrire cette ligne que je viens de comprendre ce qui va suivre.
    J'ai encore eu le problème avec cette ligne dans le bloc ErrH.
    Mais j'ai repéré que vous aviez prévu les deux cas de figure.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     ' Syntaxe pour un champ numérique.
               rs.FindFirst "[" & strChampSelection & "]=" & rsfm(strChamp)
               ' Syntaxe pour un champ texte.
               'rs.FindFirst "[" & strChampSelection & "]='" & rsfm(strChamp) & "'"
    Ce n'est que depuis quelques secondes que j'ai compris :
    C'est la bonne méthode pour un champ de type texte.
    Le mien était numérique.
    Je pensais qu'il s'agissait d'une liaison mystérieuse qui pour une raison qui m'échappait était numérique chez vous et ne fonctionnait pas chez moi. Mais je vient de comprendre qu'il s'agissait du contenu du champ à recopier dans la table sélection qui chez moi est effectivement alphanumérique.

    Je n'avais pas bien saisi le fonctionnement de CTRL+SHIFT, c'est génial. Cette fonction est évidemment un avantage.

    Sinon, j'ai fait des essais avec des fonctions de l'API windows pour tenter de manipuler directement la barre de défilement vertical.
    J'arrive à faire défiler les enregistrements sans avoir à faire des DoCmd.GoToRecord, mais cela crée un autre problème.
    La sélection est recrée, mais ellse se décale selon une logique qui m'échappe, dès qu'on clique sur la barre de défilement ou qu'on agit sur la molette de la souris.
    Il y a donc un problème d'interaction entre le fait de créer une sélection avec SelTop/SelHeight et le défilement des enregistrements.
    Gageons que le résultat sera encore plus hallucinant. Mais ne vous sentez pas obligé d'y consacrer plus de temps que celui que je vous remercie d'avoir déjà consacré.

    Soit il y a un problème que vous avez détecté dans votre dernier code et qui m'a échappé, soit tout fonctionne déjà très bien comme j'ai pu le tester jusqu'à présent et je pense que l'on peut se satisfaire (on le serrait à beaucoup, beaucoup moins…) de cette dernière version.

    Je pense que les gens qui ont travaillé sur la fonctionnalité du sélecteur d'enregistrement seraient surpris de voir l'usage qu'on en fait.
    En fait je n'ai pas trouvé beaucoup d'infos sur le sélecteur. Le fait est qu'il ne semble même pas avoir de propriétés le concernant à part le fait de l'afficher ou non.

    Je suis persuadé qu'il n'a pas été conçu dans le sens d'une sélection multiple non contiguë.
    Ce doit certainement être le cas. Je trouve que c'est du travail bâclé de la part des concepteurs. Je me demande si le sélecteur existe dans les versions Open source et s'il est plus sophistiqué…

    Mon code fonctionne tant bien que mal, mais c'est de la bidouille. .
    C'est certainement ce qu'à dû dire l'inventeur de Linux…

    Encore merci pour tout.

  19. #39
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    188
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 188
    Points : 98
    Points
    98
    Par défaut
    Bonjour.

    J'ai finalement intégré le code dans le formulaire (en fait dans un des formulaires) pour lequel je m'étais mis à la recherche d'information.

    Mon formulaire est basé sur une requête qui regroupe une dizaine de tables et requêtes qui contiennent des milliers de lignes alors que le résultat ne concerne généralement que 30 lignes.

    ça rame sévèrement.

    Les fonctions fonctionnent (Haha !) mais le rafraîchissement est plus long que sur le prototype dont je me servait jusqu'à présent.
    Il faut un certain temps pour que la case Select de chaque ligne incluse passe "au vert".

    Par ailleurs, lors de l'utilisation de la touche CTRL pour ajouter ou soustraire plusieurs lignes à la sélection en cours, il vaut mieux ne pas cliquer trop vite (mais alors vraiment pas vite) :

    1) Le rafraîchissement est très vite (mais alors très vite) pris en défaut et du coup on ne sait plus quelles lignes sont déjà incluses ou non dans la sélection,
    2) Au bout de trois ou quatre lignes "re-sélectionnées" avec CTRL on obtient le message d'erreur suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Erreur d'exécution '3252' :
    Impossible d'ouvrir un formulaire dont la requête sous-jacente contient une fonction définie par l'utilisateur qui tente de définir ou de lire la propriété RecordsetClone du formulaire.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     If rsfm.RecordCount = 0 Then
    Surligné en jaune dans le bloc SauverSelection2

    Ma non compétence dans ce domaine me fait penser qu'il faut comprendre que comme on fait des sélections trop vite, le formulaire n'a pas le temps de tout mettre à jour et du coup, la "re-sélection" de plusieurs lignes consécutivement et rapidement fait que la première ligne sélectionnée est traitée correctement mais lentement, et dès la ligne suivante ou la troisième, Access essaye de faire des modifs ou d'accéder au recorset alors que celui-ci n'a pas fini de traiter la ou les première lignes.

    Du coup, ça bloque.

    C'est comme ça que je le vois.

    Bon, tout ça c'est à titre informatif, pour ceux qui comme moi veulent se lancer dans l'aventure sélecteur, avec déjà une base lourdingue.
    Parce que ma base rame surtout à cause de son volume et des requête tarabiscotées qui servent de source qu formulaire.
    L'intégration du sélecteur alourdi encore un peu plus les traitements déjà présent sur le formulaire ne question, mais ce n'est rien en comparaison du reste.

    Donc, si j'ai vu juste, je vais commencer par tenter d'alléger la base et surtout le formulaire pour que tout rentre dans l'ordre.

    Encore merci.

    PS : le problème se pose aussi avec un Clic suivi d'un Shift+Clic quelques lignes plus bas.
    En effet le premier Clic est considéré comme la sélection d'une ligne et le second Clic accompagné de Shift permet de sélectionner toutes les lignes entre. Mais si l'on attends pas entre les deux opérations, Access n'a pas fini de traiter le première ligne et bloque au second Clic...

  20. #40
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    188
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 188
    Points : 98
    Points
    98
    Par défaut
    Bonjour.

    Juste pour signaler que j'ai solutioné la problématique lenteur de mon système actuel en convertissant la requête source du formulaire en requête de création de table.

    C'est cette table qui sert maintenant de source, via quand même une requête qui permet l'effet mise en surbrillance des lignes sélectionnées.

    Le résultat fonctionne tout à fait est même pour les énervés de la sélection, le système n'est pas pris en défaut par des délais de traitement.

    Encore merci.

+ Répondre à la discussion
Cette discussion est résolue.
Page 2 sur 3 PremièrePremière 123 DernièreDernière

Discussions similaires

  1. Critères de requêtes basées sur valeur de liste d'un formuliare
    Par 7guizz9 dans le forum Requêtes et SQL.
    Réponses: 4
    Dernier message: 22/01/2008, 10h57
  2. une liste ou requête basée sur deux fichiers
    Par chapeau_melon dans le forum WinDev
    Réponses: 8
    Dernier message: 12/11/2007, 20h00
  3. [SimpleXML] comment faire une requête basée sur un namespace d'un attribut ?
    Par hansaplast dans le forum Bibliothèques et frameworks
    Réponses: 7
    Dernier message: 03/09/2007, 01h18
  4. requête basée sur des intervalles d'heures
    Par lieselotte02 dans le forum Requêtes et SQL.
    Réponses: 1
    Dernier message: 02/06/2007, 21h23
  5. une requête basée sur un seul critère ?
    Par rangernoir dans le forum Access
    Réponses: 5
    Dernier message: 07/09/2005, 18h53

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