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
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
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_XOù 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
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 lngCompteurEdit :
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.
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 SubMaintenant 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 cellTiersPeut être avantageusement changé par :
Cbx_EcheancesModification_Tiers.List = Range("Tab_Tiers[[TiersId]:[TiersNom]]").ValueJe 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
quand j'essaie de remplacer ta listview
pourtant mes listview fonctionnent très bien dans mes fichiers
et quand j'essaie de remplacer ma listview sur mon fichier je n'ai pas de soucis non plus
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 SubCe 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 cellTiersPeut ê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 WithJe 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 WithAlors 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 SubConcernant le chargement des contrôles du formulaire Usf_EcheancesModification cela se passe dans l'évènement Activate :
Private Sub UserForm_Activate()
InitialiseTextCombos
End SubJe 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 FunctionC'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 FunctionUne 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 listerowEcheanceSur 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 SubVoilà, 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
Merci à toi
