Lire valeur numérique dans listview

Bonjour,

J'ai un listview qui récupére des montants. Si je double clique j'envoie les données à un formulaire pour les modifier. Probléme : les montants affichés en milliers ne passent pas. J'ai essayé en multipliant par 1, en mettant Cdec, Cdbl, Ccur pour convertir la valeur lue, rien n'y fait.

La cellule source de la valeur est au format nombre sans séparateur. Par contre pour l'affichage dans le listview, j'affiche avec séparateur.

J'ai erreur d'exécution 13, incompatibilité de type.

QQun aurait-il une idée ?

Merci d'avance

liste des echeances

Je précise que j'ai aussi essayé en supprimant l'espace.

Bonjour Jvoitu,

La valeur de ta listview étant de type string, passe par Cnum pour la convertir en numérique.

Bonjour et merci X Cellus,

Avec Cnum, j'ai le message " sub ou fonction non définie". Cnum n'est pas dans la liste des fonctions de conversion sur le site microsoft. Comment la récupére-t-on?

Merci

Salut,

Remplace aussi la virgule...

Public Function Convert(ByVal Value As String) As Variant
    Dim tempValue As String
    tempValue = Replace(Value, " ", "", 1, , vbTextCompare)
    tempValue = Replace(Value, ",", ".", 1, , vbTextCompare)

    Convert = Val(tempValue)
End Function

Et le résultat :

000365

A nouveau,

En fait tu récupères dans ta listview par ton subitems(13) des valeurs qui doivent avoir un format personnalisé et visible surtout lorsque ces valeurs dépassent ou égales le millier.

C'est pourquoi je t'ai proposé Cnum pour les transformer sur feuille en utilisant Cnum ou sinon par VBA en utilisant Value qui est son pendant.

Car tout entrée texte quelque son contrôle à son équivalant value.

Mais vu que je réponds de mon phone et que tu n'as pas proposé de fichier je ne peux te donner plus d'explications.

Le fait que s'affiche un texte en format personnalisé en millier fait qu'il n'a pas été traité auparavant et repris en format numérique simple. Ce qui pose souci à la lecture dans une variable.

Je vais essayer de reproduire, en l'absence de fichier, ton cas mais pas avant ce soir. Car je ne peux utiliser l'ordi du travail.

Suite,

Comme solution il faut formater ta ligne en erreur en lui imposant un format de type acceptable.

Voilà ci-dessous exemple de la correction à apporter.

 Cdbl_X = CDbl(Format(.ListItems(3).ListSubItems(3), "# ##0.00"))
 'MsgBox Cdbl_X

Où Cdbl_X est de type Double, et après le format de conversion CDbl(... on insert la condition de format de type "# ##0.00"

Re,

J'ai testé en imposant le format, mais sans succès. Je te joins un extrait de mon classeur. Je précise que je suis retraité. je n'ai jamais suivi de formation informatique et que je fais çà pour m'occuper l'esprit. C'est donc un travail probablement peu correct sur la forme ou l'utilisation de vba, merci par avance de m'en excuser.

Je suis d'ailleurs preneur de tout conseil autre que ceux portant sur la question posée.

Merci

A nouveau,

Cela fonctionne pour moi en ajoutant le format. Par contre dans mon exemple il y a un point devant ListItem(3) car mon code était inclus dans une procédure With / End With.

Et tu ne dois pas inscrire ce point. Donc pour toi, c'est dblMontantDebEch = CDbl(format(Lvw_EcheancesListe.ListItems(IndexLigneLvw).subItems(13), "# ##0.00"))

Salut,

Pas de problème pour moi sans rien toucher..

Expression prise sur point d'arrêt de la condition dans l'évènement : Lvw_EcheancesListe_DblClick

000367

Par contre je ne vois pas dans l'initialisation du formulaire à quoi te sert cela :

    For lngCompteur = 1 To Lvw_EcheancesListe.ListItems.Count
        Lvw_EcheancesListe.ListItems(lngCompteur).ListSubItems(1).Text = CDec(CDate(Lvw_EcheancesListe.ListItems(lngCompteur).ListSubItems(1).Text))
    Next lngCompteur

Edit :

Je n'avais pas tout bien regardé ...

Suite,

Lorsque tu cliques sur le bouton de la page d'accueil qui lance le premier Userform.

Il manque dans la macro Bouton_Cliquer après la ligne du .Show le chargement du deuxième Userform sinon cela bloquera la suite de ton programme.

Donc rajouter Load Usf_EcheancesModification

Re,

Rien à faire, çà ne passe pas. J'ai copié ta ligne de code, mais çà ne fonctionne pas chez moi. Je ne comprends pas.

espions echeances

Le type affiché est integer alors que ma variable dblMontantDebitEch est bien déclarée 'as double.

Pour la partie de code que tu évoques, c'est pour trier le listview sur les dates. Je passe la date en décimal et je la repasse ensuite au format date.C'est une solution que j'ai trouvée sur internet.

Merci

Re,

J'ai remarqué que tu ne déclare aucune variable, ce n'est pas bien ça

Remets l'option Explicit et déclare toutes les variables.

repasse la ligne comme cela :

            dblMontantDebitEch = CDbl(Lvw_EcheancesListe.ListItems(IndexLigneLvw).SubItems(13))

Regarde aussi au niveau de Windows et des Options de langues.

Suite,

Je rejoins Jean-Paul sur ce point, j'ai déclaré dblMontantDebitEch comme variable Double en début de macro.

Donc il ne l'était pas à l'origine de ton fichier.

Faire des Debug.Print de certaines de tes variables pour contrôler celles-ci.

Exemple Debug.Print "test DebEch =" & dblMontantDebEch

Ne pas oublier de lancer avant la fenêtre d'exécution. Soit par le menu Affichage de l'éditeur VBA, soit directement par CTRL + G.

Petit retour après un peu de lecture.

  • Faut faire la déclaration des variables..

Tu initialises une partie des variables du Formulaire Usf_EcheancesModification dans le formulaire Usf_EcheancesListe et l'autre partie dans la Méthode Initialize du formulaire Usf_EcheancesModification c'est fouillis tout ça. Je te propose une autre approche.

Une seule variable nous est importante l'index de la ligne du tableau qui est dans la première colonne du ListView. il vaut mieux récupérer les informations à la source donc dans le tableau "Tab_Echeances".

Pour ce faire nous allons créer une propriété dans le formulaire Usf_EcheancesModification et cela évitera des variables publiques.

Donc au début du module du formulaire Usf_EcheancesModification tu ajoutes ce code :

'@Jean-Luc Voituron
' **********************************************************************************
' Userform EcheancesModification
' **********************************************************************************
Option Explicit

Dim dicCategorie As Dictionary
Dim sceDicCategorie As Variant

Private mIndexEcheance As Long
Public Property Let indexEcheance(ByVal NewValue As Long)
    mIndexEcheance = NewValue
End Property

Private Sub Cbx_EcheancesModification_Nature_Exit(ByVal Cancel As MSForms.ReturnBoolean)
    Select Case Me.Cbx_EcheancesModification_Nature
        Case Is <> Me.Tbx_EcheancesModification_NatureEch
            Select Case Me.Cbx_EcheancesModification_Nature
'...
'...

Cette propriété va te permettre de passer l'ID de la ligne du tableau en paramètre au formulaire.

Maintenant dans Lvw_EcheancesListe_DblClick tu vire tout ce qui fait référence à l'initialisation des variables du formulaire de modification.

Il ne devrait rester qu'a peut prêt ces lignes de code :

Public Sub Lvw_EcheancesListe_DblClick()
    With Lvw_EcheancesListe
        Select Case .ListItems(.SelectedItem.Index).SubItems(10)
            Case Is = 9989
                MsgBox "Impossible de modifier une échéance de carte bancaire à débit différé", vbCritical, _
                       "Gestion des échéances - Modification des échéances"
                Exit Sub
            Case Is = 9988
                Dim Message As String
                Message = "La modification d'une échéance de virement entre comptes porte sur les deux comptes concernés" & _
                          "Gestion des échéances - Modification des échéances"
                MsgBox Message, vbInformation
        End Select
    End With

    With Usf_EcheancesModification
        ' // passage de l'index de ligne du tableau au formulaire de modification
        .indexEcheance = CLng(Lvw_EcheancesListe.SelectedItem.Text)
        ' Todo "Doit-on garder l'initialisation du label ?"
        If Message > vbNullString Then
            .Lbl_EcheancesModification_EchAssociee.Caption = "La modification d'une échéance de virement modifie l'échéance sur le compte associé"
        End If
    End With

End Sub

Maintenant reste à faire l'initialisation complète du formulaire de modification :

En sachant que ce code :

    ' -- Charge la liste des tiers, hors tiers 'tiers supprimé'
    intIndex = 0
    '@Ignore ImplicitActiveSheetReference
    For Each cellTiers In Range("Tab_Tiers[TiersId]")
        If cellTiers > 0 Then
            With Me.Cbx_EcheancesModification_Tiers
                .AddItem cellTiers
                .List(intIndex, 1) = cellTiers.Offset(0, 1)
                intIndex = intIndex + 1
            End With
        End If
    Next cellTiers

Peut être avantageusement changé par :

Cbx_EcheancesModification_Tiers.List = Range("Tab_Tiers[[TiersId]:[TiersNom]]").Value

Je te conseille de faire de petites procédures qui ont une seule fonction exemple :

La procédure InitListView mettra en forme le listeView colonnes etc..

La procédure FillListView chargera les données

etc...

Il reste une chose. Pouvoir utiliser indexLigne que l'on a passé en paramètre.

Suite au prochain épisode si intéressé.

Bonne prog

bonjour le fil,

ne suffit-il pas en supprimant les espaces ? En utilisant CDbl, ce dblMontantDebitEch devient double

   If Lvw_EcheancesListe.ListItems(IndexLigneLvw).SubItems(13) <> "" Then
        dblMontantDebitEch = CDbl(Replace(Lvw_EcheancesListe.ListItems(IndexLigneLvw).SubItems(13), " ", ""))

Bonjour et merci à tous

Un petit souci aprés la tempête Géraldine m'a empêché de regarder tout çà.

Donc,

BsAlv : j'avais déjà essayé le replace pour supprimer l'espace sans succés

Jean-Paul, X Cellus : je vous rassure, j'utilise bien l'option explicit et ma variable a bien été déclarée en tant que double. Simplement j'ai fait une extraction de mon fichier avec les feuilles concernées. Pour ne pas recopier toutes les variables, j'ai mis en commentaires l'option, ainsi que tout le code qui ne servait pas dans l'extraction. J'aurais du à minima laisser les variables échéances, cela aurait été aussi plus fidèle à mon fichier, mea culpa.

X cellus : je vais regarder mes paramétres régionaux

jean-paul, ce que tu me proposes me convient parfaitement. C'est ce que j'ai du mal à faire, simplifier mon code et le découper. Comme je maitrise mal, j'ai besoin de suivre l'évolution du code qd je passe d'un formulaire à un autre, donc je m'assure que j'ai tout en reprenant les éléments, et comme tu dis, çà fait fouillis. Mais oui, si je ne passe que l'index de la ligne ou l'identifiant de l'opération, çà sera plus simple. J'ai lu aussi le bas de page de tes messages. En ce moment j'utilise excel un peu en tant que sgbd. Mais je connais encore plus mal Access, mais je vais m'y interesser dés que possible. Je termine le projet sous excel (en fait une petite application pour gérer mes comptes) et je regarde çà.

Merci à vous

Je teste la solution de Jean-Paul et je reviens vers vous.

re

bonjour

je viens de télécharger ton fichier et je peux même pas ouvrir le userform

j'ai essayé de changer le controls listview entre version excel ca joue des tours des fois

et je ne peux pas ajouter de listview donc pour la remplacer c'est walouh

je me suis dis peut être qu'une mise a jour m'a pétarder le common control v6

alors j'ai ré-ouvert un de mes fichiers et mes listview fonctionnent

j'ai essayer de les remplacer ça fonctionne aussi

j'en conclu que c'est un fichier qui a été fait sur 2021 ou 365 et que malheureusement ces deux versions on des soucis avec le listview

chose qu'une mise a jour a parfaitement réglé sauf que dès l'ors les controls listview ne sont plus compatible avec une autre version d'excel

quand je l'ouvre ton userform par le VBE

image

quand j'essaie de remplacer ta listview

demo

pourtant mes listview fonctionnent très bien dans mes fichiers

demo

et quand j'essaie de remplacer ma listview sur mon fichier je n'ai pas de soucis non plus

demo

bref ton fichier est naze selon moi

Re,

Bon alors on continu un peu.

On été rester sur le passage de l'index de ligne en paramètre au formulaire Usf_EcheancesModification.

Je vois que tu utilises Rubberduck tu peux voir les Todo pour y revenir plus tard. Pour se faire Menu RubberDuck Outils puis A Faire (Todo)

Public Sub Lvw_EcheancesListe_DblClick()
    With Lvw_EcheancesListe
        Select Case .ListItems(.SelectedItem.index).SubItems(10)
            Case Is = 9989
                MsgBox "Impossible de modifier une échéance de carte bancaire à débit différé", vbCritical, _
                       "Gestion des échéances - Modification des échéances"
                Exit Sub
            Case Is = 9988
                Dim Message As String
                Message = "La modification d'une échéance de virement entre comptes porte sur les deux comptes concernés" & _
                          "Gestion des échéances - Modification des échéances"
                MsgBox Message, vbInformation
        End Select
    End With

    With Usf_EcheancesModification
        ' // passage de l'index de ligne du tableau au formulaire de modification
        .indexEcheance = CLng(Lvw_EcheancesListe.SelectedItem.Text)
        ' Todo "Doit-on garder l'initialisation du label ?"
        If Message > vbNullString Then
            .Lbl_EcheancesModification_EchAssociee.Caption = "La modification d'une échéance de virement modifie l'échéance sur le compte associé"
        End If
        .Show
    End With
Unload Me
End Sub

Ce qu'il faut savoir :

Quand on fait un Whith End Whith sur un formulaire, Comme sur le code ci-dessus il va exécuter dans l'ordre Initialize, puis il va charger indexEcheance, puis Activate.

Donc le code qui a besoin de l'index de ligne ne devra pas être dans la méthode initialize.

Souvent je dis de faire travailler Excel avant tout, tu possèdes Office 365 donc il faut l'utiliser au maximum exemple ce code :

    intIndex = 0
    '@Ignore ImplicitActiveSheetReference
    For Each cellTiers In Range("Tab_Tiers[TiersId]")
        If cellTiers > 0 Then
            With Me.Cbx_EcheancesModification_Tiers
                .AddItem cellTiers
                .List(intIndex, 1) = cellTiers.Offset(0, 1)
                intIndex = intIndex + 1
            End With
        End If
    Next cellTiers

Peut être avantageusement remplacer par :

    ' // Charge les listes déroulantes
    With Cbx_EcheancesModification_Tiers
        .Clear
        .List = Evaluate("SORT(UNIQUE(FILTER(Tab_Tiers[[TiersId]:[TiersNom]],Tab_Tiers[TiersNom]<>"""")))")
    End With

Je ne pense pas que tu ais besoin d'avoir deux colonnes dans les zones de liste déroulantes. Mais au cas où tu peux utiliser Filtre :

    With Cbx_EcheancesModification_Compte
        .Clear
        .List = Evaluate("SORT(UNIQUE(FILTER(Tab_ComptesSuivi[[CompteId]:[CompteNom]],Tab_ComptesSuivi[CompteNom]<>"""")))")
    End With

Alors tout cela nous amène à quoi ?

Tu va pouvoir supprimer les procédures de tri du Module1 et pas mal de lignes de code aussi.

Tu pourras aussi supprimer les colonnes qui ne te seront plus utiles exemple NatureEstDoublon dans le tableau Tab_Categories.

La procédure ChargeCbxCategories s'en trouve allégée aussi :

Private Sub ChargeCbxCategories()
    ' -- Charge la liste des natures
    With Cbx_EcheancesModification_Nature
        .Clear
        ' Todo "Besoin de deux colonnes pour le chargement des listes ?"
        '.List = Evaluate("SORT(UNIQUE(FILTER(Tab_Categories[[NatureId]:[Nature]],Tab_Categories[Nature]<>"""")))")
        .List = Evaluate("SORT(UNIQUE(Tab_Categories[Nature]))")
    End With

    ' -- Charge la liste des groupes de catégories
    With Cbx_EcheancesModification_GroupeCat
        .Clear
        .List = Evaluate("SORT(UNIQUE(Tab_Categories[GroupeCatNom]))")
    End With

    ' -- Charge la liste des catégories
    With Cbx_EcheancesModification_Cat
        .Clear
        .List = Evaluate("UNIQUE(SORT(Tab_Categories[CategorieNom]))")
'        .Text = Me.Tbx_EcheancesModification_Cat
    End With
End Sub

Concernant le chargement des contrôles du formulaire Usf_EcheancesModification cela se passe dans l'évènement Activate :

Private Sub UserForm_Activate()
    InitialiseTextCombos
End Sub

Je n'ai pas tout compris au niveau de qui fait quoi alors ne m'en veux pas trop.

Avant de regarder la procédure petit commentaire j'initialise le plus possible mes tableaux dans un Module Factory en cas de changement de nom ou autre tu n'as pas tout le code à te peller...

Donc un module que je nomme Factory et j'y colle l'initialisation du tableau :

'@Description "Initialisation de la table échéances"
Public Function InitTableEcheances() As Excel.ListObject
    Static Item As Excel.ListObject
    If Item Is Nothing Then
        ' // Chargement de la table échéances
        Set Item = TabsManagement.getListObject("Tab_Echeances")
    End If
    Set InitTableEcheances = Item
End Function

C'est pas fini. je vais le perdre là. Dans la fonction j'affecte le ListObject grace à une fonction De Philippe Tulliez merci à lui.

Set Item = TabsManagement.getListObject("Tab_Echeances")

Donc dans un Module que je nomme TabsManagement on colle ce code :

'@Description "Fonction renvoyant l'objet feuille où se trouve le tableau. Nothing s'il n'existe pas"
Public Function GetListObjectSheet(ByVal ListName As String, Optional ByVal Workbook As Excel.Workbook) As Excel.Worksheet
    Dim localWorkbook As Excel.Workbook
    Set localWorkbook = Workbook
    If localWorkbook Is Nothing Then Set localWorkbook = ThisWorkbook

    Dim CounterListObjects As Long
    Do
        Dim SheetCounter As Long
        SheetCounter = SheetCounter + 1
        On Error Resume Next
        Set GetListObjectSheet = localWorkbook.Worksheets.Item(SheetCounter).ListObjects(ListName).Parent
        On Error GoTo 0
        Err.Clear
    Loop While SheetCounter < localWorkbook.Worksheets.Count And GetListObjectSheet Is Nothing
End Function

Une fois tout cela fait on peu passer à l'initialisation des Contrôles du formulaire :

Private Sub InitialiseTextCombos()
    Dim listerowEcheance As Excel.ListRow
    ' // Affectation de la listRow avec l'index de ligne
    Set listerowEcheance = Factory.InitTableEcheances.ListRows(mIndexEcheance)
    If Not listerowEcheance Is Nothing Then
        With listerowEcheance

Sur le code ci-dessus je déclare une ListRow et je l'affecte, ensuite je teste si j'ai un retour.

Il ne reste plus qu'a charger les valeurs des contrôles. Bon là je ne suis pas sur de tout. A toi de voir.

Tu remarqueras que j'utilise le nom des colonnes plus long mais plus utile si l'on change l'ordre des colonnes dans le tableau, ou si l'on supprime une colonne.

Private Sub InitialiseTextCombos()
    Dim listerowEcheance As Excel.ListRow
    Set listerowEcheance = Factory.InitTableEcheances.ListRows(mIndexEcheance)
    If Not listerowEcheance Is Nothing Then
        With listerowEcheance
            Cbx_EcheancesModification_Cat.Text = .Range(.Parent.ListColumns("EcheanceCategorie").index).Value
            Cbx_EcheancesModification_Compte.Text = .Range(.Parent.ListColumns("EcheanceCompte").index).Value
            Me.Cbx_EcheancesModification_GroupeCat.Text = .Range(.Parent.ListColumns("EcheanceGroupeCatNom").index).Value

            ' Todo "Zone de liste Nature doit avoir un ID unique, ou bien renvoyer le texte"
            'Cbx_EcheancesModification_Nature.Text = .Range(.Parent.ListColumns("EcheanceNature").index).Value
            Cbx_EcheancesModification_Periode.Text = .Range(.Parent.ListColumns("EcheancePeriodicite").index).Value
            Cbx_EcheancesModification_Tiers.Text = .Range(.Parent.ListColumns("EcheanceTiers/Cpte").index).Value

            Tbx_EcheancesModification_Cat.Value = .Range(.Parent.ListColumns("EcheanceCatId").index).Value
            Tbx_EcheancesModification_Comments.Value = .Range(.Parent.ListColumns("EcheanceComments").index).Value
            Tbx_EcheancesModification_Credit.Value = .Range(.Parent.ListColumns("EcheanceCredit").index).Value
            Tbx_EcheancesModification_Date.Value = .Range(.Parent.ListColumns("EcheanceDate").index).Value
            Tbx_EcheancesModification_Debit.Value = .Range(.Parent.ListColumns("EcheanceDebit").index).Value
            Tbx_EcheancesModification_GroupeEch.Value = .Range(.Parent.ListColumns("EcheanceGroupeCatId").index).Value
            Tbx_EcheancesModification_IdCompteEch.Value = .Range(.Parent.ListColumns("EcheanceCompteId").index).Value
            Tbx_EcheancesModification_IdEch.Value = .Range(.Parent.ListColumns("EcheanceId").index).Value
            Tbx_EcheancesModification_IdEchAssociee.Value = .Range(.Parent.ListColumns("IdEchAssociee").index).Value
            Tbx_EcheancesModification_IdTiersEch.Value = .Range(.Parent.ListColumns("EcheanceTiersId/CompteId").index).Value
            Tbx_EcheancesModification_NatureEch.Value = .Range(.Parent.ListColumns("EcheanceNature").index).Value
            Tbx_EcheancesModification_Num.Value = .Range(.Parent.ListColumns("EcheanceNumCheque").index).Value

            ' Todo "Quelles sont ces entrées ?"
            'Tbx_EcheancesModification_OrigineDemande.Value = ""
            'Tbx_EcheancesModification_PorteeModif.Value = ""
            'Tbx_EcheancesModification_Virt.Value = ""
        End With
    Else
        ' Todo "Make message"
    End If
End Sub

Voilà, tu as pas mal de travail pour nettoyer le classeur.

La suite au prochain épisode.

Bonne prog.

Access, mais je vais m'y interesser dés que possible

Oui y'a pas photo, Ce n'est pas la même approche, mais si tu construit bien les tables le travail est à moitie fait. Les requêtes facilitent le travail aussi. Mais chut, on est sur un forum Excel...

Oups, merci Jean-Paul

Effectivement, c'est la différence entre un pro et un amateur . Je vais regarder çà de prés, mais j'ai du boulot.Je pense que je vais mettre un peu de temps à tout comprendre. Il va me falloir un peu de temps avant de te répondre et j'aurai probablement des questions en cours de route.

Merci à toi

Rechercher des sujets similaires à "lire valeur numerique listview"