Manipulation chaines de caractères (Mid/Replace)

Bonjour à tous,

Je travaille sur un petit UserForm pour des collègues, qui selon les valeurs des ComboBox doit afficher une codification.

Le code de départ est composé de zéros, et il se modifie au fur et à mesure via les ComboBox_Change. Jusque là tout allait bien même si je me galère un peu avec les replace (Première utilisation). Si on vide le ComboBox, le code se remet avec des zéro.

Mais après les tests de combinaison de tombe sur un os et n'arrive pas à trouver de parade... Je vous joint mon fichier pour que vous puissiez faire le teste et voir mon code.

Voici la combinaison qui me pose soucis:

Type de produit -> Clapet anti-retour à battant -> Remplace les deux premiers caractères -> 00 devientCB

Type de fermeture -> Boulonnée -> Remplace le troisième caractère -> 0 devient B

Le code commence donc pas CBB et fonctionne jusque la nickel. Mais si je veux revenir en arrière et que je supprimer le type de fermeture, au lieu d'afficher CB0 il m'affiche C0B car forcément avec le replace il vient chercher le premier B... J'ai regardé avec le départ mais du coup il dégage le texte devant donc pas une solution non plus...

Edit: J'ai inséré un split, ce qui me permet de scinder ma chaine grave aux espaces et donc de manipuler quasi tout les modifications séparément. Le soucis reste sur les 3 premiers caractères car je ne peux pas les espacer, peut-être en récupérer l'info du combox1 et en la réécrivant mais ça fait de la manip pour rien.

Y-a-t'il une façon de faire dont je n'aurai pas connaissance ? Peut-être une alternative plus simple ? Merci pour votre aide comme toujours

12designation.xlsm (51.22 Ko)

Bonjour,

"REPLACE" n'est pas adapté puisqu'il va remplacer tous les caractères identiques dans la chaîne.

il faut utiliser "MID".

Votre code pour la combobox2, à reproduire pour les autres.

Private Sub ComboBox2_Change()
    'Titre image
    If ComboBox2 = "" Then
        Titre_Image = ""
    Else
        Titre_Image = "Illustration: Type de fermeture"
    End If

    'Désignation
    If ComboBox2 = "" Then
        Mid(Désignation, 3, 1) = 0 'on remplace le 3ème caractère par 0
        TextBox2 = Désignation 'la textbox2 affiche la nouvelle désignation
    Else
        'Création de la table
        NombreLignes = Application.WorksheetFunction.CountA(Range("C2", Cells(Rows.Count, "C").End(xlUp)))
        ReDim TableLignes(NombreLignes, 1)
        For i = 0 To NombreLignes
            For J = 0 To 1
                TableLignes(i, J) = Données.Cells(2 + i, 3 + J) '3 = Colonne "Fermeture"
            Next J
        Next i
        For i = 0 To NombreLignes
            If TableLignes(i, 0) = ComboBox2 Then
               Valeur = TableLignes(i, 1)
            End If
        Next i
        'Remplacement
        Mid(Désignation, 3, 1) = Valeur 'on remplace le 3ème caractère par la valeur
        TextBox2 = Désignation 'la textbox2 affiche la nouvelle désignation
    End If
End Sub

Cdlt

Bonjour Arturo,

Cela fonctionne parfaitement merci, c'était bête mais je ne savais pas qu'on pouvait utiliser le "MID" ainsi, je pensais qu'il servait juste a récupérer une info.

Merci beaucoup

Salut à tous,

Ton code peut-être réduit en utilisant un tableau.
Pour la mise en forme du textbox2 c'est dans le module Factory.

J'ai modifier les tableaux et je les ai passés en structurés, les Listes déroulantes comportent le texte et la valeur à renvoyée cette dernière est cachée.
N'ayant pas les images sur mon PC j'ai désactiver l'affichage, elles doivent se nommer à l'identique de la valeur du produit sélectionné ex. "Vanne à siège parallèle" image "VP.jpg".
Je te conseille d'utiliser le module Factory pour déterminer le chemin des images cela t'évitera de changer dans moulte procédures

Bon maintenant :

  1. Évites de cacher l'application quand tu fournis le fichier
  2. Il serait judicieux de nommer les contrôles autrement que par leur valeurs de défaut
  3. Idem pour la fermeture de l'application on évite quand on transmet le fichie

Bonjour Jean-Paul,

Brillante production quoique parfois un peu limite trop chiadée (presque obfusquée !), mais je suppose que Heelflip doit bien comprendre...

On arrivait quasiment au même résultat en se contentant de plage nommées avec INDIRECT et ça restait très clair pour des apprenants. Mébon j'avoue avoir été tenté également par les Tableaux Structurés car la présentation de la feuille Données était à revoir.

J'en était arrivé à peu près à la même construction que toi si ce n'est que les 2 fonctions auraient très bien être privatisées dans le UserForm puisqu'elles ne sont appelées que pour son fonctionnement.

Je trouve un peu dommage que sur des constructions semblables la plupart des intervenants ne se donnent pas plus la peine d'inciter les auteurs à améliorer leur pratique et se contentent de réponses peu constructives.

Il est vrai que trop souvent si l'on tente de modifier leur production les auteurs se sentent agressés et réagissent souvent vertement... C'est dommage les forums spécialisés y ont ainsi perdus beaucoup de leur intéret car on n'aide pas beaucoup les gens quand on les laissent patauger dans des constructions aussi médiocre que l'original...

A+

Bonjour,

c'est quoi ce boulot ?
J'ai voulu voir ton fichier, à la fin il me ferme tout excel.
Même ceux sur lesquels je travaillais. Sans sauvegarde bien sûr...

C'est vrai que les appli masquées c'est vraiment "beurk" sur les forums...

A+

Bonsoir à tous,

Excusez le fichier caché et la fermeture auto, j'ai oublié de les virer avant diffusion sur le forum...

Jean-Paul, pour les tableaux structurés, en effet c'est plus propre, j'en ai utilisé sur d'autres macros avec des tables changeantes, mais celles-ci étant figées je n'ai pas pris le temps de faire cela proprement, je code pour le boulot pendant mes heures de repos et jusque tard donc parfois je vais au plus simple avant de finalement reprendre 3/4 fois le fichier pour arriver à une version propre. J'ai regardé ton fichier, maintenant faut que je déchiffre car certains morceaux de code me dépassent un peu, le factory les localControl etc... Le but étant de savoir le modifier en cas de besoin j'ai plus besoin de comprendre ce que je fais que d'avoir une version qui fonctionne mais que je ne maitrise pas.

Par contre je ne comprends pas le -> Il serait judicieux de nommer les contrôles autrement que par leur valeurs de défaut ?

Galopin, tu as raison, sauf pour le "médiocre" car je suis déjà content d'en arriver là après quelques mois de pratique . Mais en effet les conseils des utilisateurs chevronnés sont les bienvenus, même si parfois très difficile à déchiffrer quand ils te filent un code raccourcis que tu as du mal à lire sans plus d'explication.

C'est vrai que là tu as "du lourd" mais c'est vrai que quand on aime et qu'une réponse semble déjà donnée et qu'on s'attaque à des sujets qui motivent le répondeurs, on a souvent tendance à broder ou à fignoler rien que pour le plaisir. Mais s les demandeurs sont motivés je ne doute pas que tu auras les réponses à tes questions.

Moi ce qui m'a un peu estomaqué c'est l'utilisation du tag qui m'a paru un peu "hard" sur un sujet initialement si peu fignolé. (tout est relatif hein : On a déjà vu bien pire sur les forums. Pardon, l'idée n'est pas de blesser !)

Tant il est vrai qu'à force de vouloir faire vite, vite, vite, on perd plus de temps à remettre plusieurs fois le boulot à plat pour refaire de manière plus soignée... Ça a quand même plus de gueule non ?

Bah ça a tellement de gueule que je ne comprends plus rien au code, oui c'est beau mais il y a un trop grand écart entre ce que j'apprends et ça. L'avantage c'est que ça me donne plein de nouvelles choses à apprendre mais dans l'immédiat c'est compliqué a exploiter en l'état.

C'est vrai que là Jean-Paul à fait fort, néanmoins ce n'est pas trop compliqué à comprendre.

La fonction Factory : C'est une simple concaténation de chaîne. (le genre d'outils à noter bien dans au chaud dans un petit coin de sa mémoire...)

Factory utilise pour cela une fonction d'Excel spécialement conçue pour concaténer des chaînes à rallonge : Join

Join est conçu pour concaténer en un temps record un Array de x éléments.

Bon Effectivement si tu ne maîtrise pas les Array, il est temps pour toi d'acheter une boite de Doliprane et de potasser d'urgence les Array. Ce sont des instruments puissants : Dès qu'on est tombé dedans, on ne peut plus s'en passer.

Pour Join consulter l'aide en ligne de VBA.

La fonction GetTheValue. Là c'est un petit peu plus compliqué mais comme je dis souvent pas besoin de connaitre dans le détails je mécanisme du moteur pour conduire une voiture : il suffit d'utiliser toussa à bon escient.

GetTheValue est une encore pépite à archiver d'urgence dans sa bibliothèque de macros de référence. Elle permet dans des situation comme la tienne de charger une multitude de combo à partir de tableaux. Ceux des Tableaux Structurés conviennent parfaitement, mais ont auraient pu utiliser également les Noms avec Décaler ensuite c'est juste un petit jeu (une manip de String avec Split) pour découper le Tag de chaque combo. Le Tag est une propriété du combo contenu dans la fenêtre des propriétés de VBA. Ce Tag utilise la liste des Noms du Gestionnaire de Fichier pour envoyer le tout au Turbo multitâche (GetTheValue)

La dessus pas besoin de te faire greffer un supplément de méninges : Tu retiens le principe et tu notes juste le classeur en référence dans ta bibliothèque de trésors perso. Si tu n'en as pas encore c'est le moment de t'en faire une. C'est Noël à la Toussaint ! Tu en auras forcément besoin ultérieurement. Ce ce serait bête de laisser se perdre un tel cadeau...

Une fois n'est pas coutume, je ne suis pas avare en superlatifs avec d'autant moins de complexe que ce n'est pas ma prod... Alors profite !

Bon c'est clair ou t'en veut encore ? Je recommence ?

A+

Salut à tous,

galopin à bien fait le tour de la question. Quelques explication quand même:

GetTheValue me permet d'aller chercher dans le Tag du contrôle une valeur bien déterminée exemple:

  • Si le Tag du contrôle contient Key:=Miscellaneous.PageLoaded;ListeValueCmb:=vt_Contacts
  • GetTheValue(cmbContacts.Tag,"ListeValueCmb") renverra "vt_Contacts"

A la création du formulaire j'assigne aux Listes déroulantes, liste, etc les plages de valeurs. Ensuite je remplis ce petit monde plus facilement:

    Dim localControl As Control
    For Each localControl In Me.Controls
        Select Case TypeName(localControl)
            Case "ComboBox"
                Dim ListValuesAddress As String
                ListValuesAddress = XlTools.GetTheValue(localControl.Tag, "ListValues")
                If ListValuesAddress > vbNullString Then
                    localControl.List = Range(ListValuesAddress).value
                End If
        End Select
    Next localControl

Donc je boucle sur tous les contrôles de la feuille, si c'est une liste déroulante, alors je vais chercher la plage de valeur dans son Tag. Cette plage de valeur peu être un tableau complet, une plage nommée qui ne reprend que l'ID, Nom et Prénom d'un contact par exemple etc..
On peut aussi gérer d'autres contrôles ce n'est que l'imagination qui vous freinera.

Concernant le module Factory, j’essaie quand c'est possible de gérer les initialisations depuis ce module. Pourquoi ? Imaginons, j'assigne à une variable ListObject un tableau :

Dim ContactsListObject As ListObject
Set ContactsListObject =ThisWorkbook.WorkSheets("vs_Contacts").Range("vt_Contacts").listObject
If Not ContactsListObject Is Nothing Then
'...
'...
End If

Ça c'est dans le formulaire frmContacts, maintenant j'ai besoin de ce ListObject dans le Formualire frmDetailContact je dois réécrire le tout ?
Si en plus demain je veux changer le nom du tableau, je dois me peler tout le code à la recherche de ce fameux vt_Contacts. Houlala !!!

Je préfère donc sortir comme le dis si bien galopin et aller initialiser mon tableau dans le module Factory, si je dois faire un changement je ne le fait que dans le module Factory. Et Excel ne s'en porte pas plus mal, c'est une gymnastique à prendre mais une fois fait, cela simplifie la vie.

Concernant la gestion du tableau qui gère la mise en forme de la référence c'est Idem, un seul endroit, cela pourrait être encore mieux car nous avons toujours l'appel à GetControlChange cmbClosure, 1, "0" qui demande aussi une modification. Pour le fonctionnement j'ai trouvé plus facile de travailler avec un tableau on aurait pu aussi utiliser un Dico ou une Collection. Le tableau te permet de formater la référence complète à ta convenance en mettant les espaces que tu veux ou tu le veux.

Maintenant, ne vous trompez pas je ne suis qu'un néophyte autodidacte qui à appris sur le tas, comme tout un chacun j'ai mes défauts et mes limites, et de se fait je ne suis pas contre toutes formes de suggestions concernant la programmation, c'est comme cela que l'on avance, même si pour moi cela reste un hobby.

Je sais aussi très bien que la plupart du temps les gens ne prennent qu'un bout de code par-ci par-là, pour étoffer leur projet. Cela ne me dérange pas si je fais ces petits programmes c'est surtout pour moi, afin de garder mon cerveau actif, à mon age c'est important.

Si besoin de plus d'explication je suis là, même si ma situation personnelle ne me permet que de faire de l'épisodique.

édit :

Par contre je ne comprends pas le -> Il serait judicieux de nommer les contrôles autrement que par leur valeurs de défaut

Je ne sais pas moi, mais cmbProduits est quand même plus parlant que ComboBox1 non ? ou txtFullReference au lieux de TextBox2.

Bonne programmation à tous,

ps. J'ai tapé à la volé donc il y a sûrement des fautes dans les exemple de code...

Merci à tout les deux pour vos explications c'est déjà "un peu" plus clair car sans essais perso ça reste abstrait, mais par contre la manipulation derrière à l'air géniale.

Comme tu dis galopin, il faut que je rentre dans les Array car pour l’instant je suis passé un peu volontairement à côté, afin d'apprendre en douceur et de pas lâcher l'affaire comme j'avais fait il y a une dizaine d'années, découragé par le flot de données et la difficulté de s'y retrouver tant les gens codent différemment.

Pour la bibliothèque, j'ai doucement commencé à m'enregistrer des petites macro que j'utilise souvent en effet, celle ci s'ajoutera ;)

Bon... J'y ai passé du temps, je réécris le code dans mon programme pour comprendre en même temps. Mais c'est chaud

J'ai compris le Tag, il va chercher le Nom du tableau structuré que je veux utiliser -> OK.

Par contre arrivé au GetTheValue je suis paumé. Pour essayer de comprendre j'ai renommé mes tables pour voir s'il allait chercher la colonne qui a un nom et si les colonnes "Value" étaient nommées ainsi volontairement et pas d'incidence, j'ai alors recréé mes tableaux en inversant les colonnes par rapport à ta version (A devient B et inversement) et là il continue de me mettre les bonnes valeurs dans les ComboBox Du coup je ne comprends pas comment exploiter ce programme... Comment dans ton programme il peut aller chercher la colonne B et dans le mien la colonne A sans n'avoir rien changé au programme ?

Salut,

Peux-Tu mettre le fichier anonymisé ?
Je fais une édition de ma précédente réponse car elle ne me satisfaisait pas. Et que mon temps libre aujourd'hui risque d'être écourté.

La procédure GetTheValue ne te pose pas de problème, ça c'est acquis.
Ce qui te pose problème je pense c'est l'affectation de la propriété List de ta liste déroulante. Et les tableaux structurés.

Explication :

Imaginons ton tableau "vt_Produits" comme suit :

000195

Regardons quelques assignations de ta liste déroulante

  • cmbProduits.List = Range("vt_Produits").Value Charge la liste déroulante avec le tableau complet donc 3 colonnes
  • cmbProduits.List = Range("vt_Produits[[ID]:[Produits]]").Value Charge la list avec les colonnes comprises entre ID et Produits donc le tableau complet aussi.
  • cmbProduits.List = Range("vt_Produits[[Value]:[Produits]]").Value Charge la Liste déroulante avec les colonnes comprises entre Value et Produits
  • cmbProduits.List = Range("vt_Produits[[Produits]:[Value]]").Value Charge la liste avec le colonnes comprises entre Produits et Value hé oui ça marche aussi.
  • cmbProduits.List = Range("vt_Produits[Produits]").Value Charge la liste déroulante avec juste la colonne Produits

Donc dans un premier temps tu dois savoir quoi renvoyer avec la propriété Tag de la liste déroulante, si tu ne veux que les colonnes Value et Produits alors à la création du formulaire tu modifie le Tag comme ceci :

  • ListeValue:=vt_Produits[[Value]:[Produits]]

Bon maintenant je ne veux pas afficher la colonne Value dans la liste déroulante, mais je veux que ce soit quand même Value qui soit renvoyé. Je vais donc paramétré la liste déroulante comme ceci :

  • BoundColumn = 1 : Je renvoie la colonne 1 par défaut
  • ColumnCount = 2 : J'ai deux colonnes
  • ColumnWidths = 0pt : Je cache la première colonne

Petite note Quand tu assigne la propriété List d'une liste déroulante, la propriété Column Count se cale automatiquement sur le nombres de colonnes.

Bonjour Jean-Paul,

Je mettrais le fichier ce soir j'ai un audit à gérer aujourd'hui

OK merci ton EDIT c'est hyper clair, je cherchais BoundColumn etc. avant de voir que c'était dans les propriétés du ComboBox. Du coup je regarde un peu les possibilités.

OK pour BoundColumn / OK pour ColumnCount

Par contre pour ColmnWidths, si je reprends ta table, je veux retourner deux valeurs (ID et Value) je fais BoundColumn = 3 pour avoir cette colonne dans ma liste déroulante / ColumnCount = 3 pour définir mon tableau mais comment je masque les deux autres colonnes, ça fonctionne qu'avec deux colonnes ?

Re Bé non !

Que vient faire RefersTo ici ?

Si ton tableau contient deux colonne tu prends le tableau complet pour ta liste déroulante donc :

  • .List doit être égal à .List = Range("vt_Produits").Value ou bien .List = Range("vt_Produits[[Value]:[Produits]]").Value mais la première est plus explicite.

Donc la propriété .Tag de la liste déroulante doit être doit-être : ListValues:=Range("vt_Produits")

Dans une liste déroulante tu as la valeur affichée et la valeur retournée, si deux colonne tu peux :

  • Afficher les deux colonnes et renvoyer la colonne 1 .BoundColumn = 1
  • Afficher qu'une colonne la 2 et renvoyer la colonne 1 .BoundColumn = 1, ColumnWidths = 0pt

Heu RefersTo ? J'en ai pas parlé ?

J'ai regardé de plus près le BoundColumn et du coup j'ai mis 1pt; 0pt ce qui m'affiche bien la colonne A dans le ComboBox et masque la B (Juste que les valeurs retournées dans toutes mes macros sont en seconde colonne donc je cherche a éviter une MAJ majeure par la suite).

Je continue de découvrir ton code ;)

Bon j'ai pas mal avancé et compris la logique du code c'est vraiment excellent et quelle simplicité de rédaction

J'ai plusieurs questions du coup:

Dans Factory il y a "Or Init = True Then" -> Qu'est-ce qu c'est cette variable, je ne la trouve que dans ce code ?

Pour les ComboBox 7 et 8 j'ai du mal à voir comment faire avec ta méthode, car il doit réagir ainsi:

Si le ComboBox 4 Commence par "PN" alors il affiche la table "Raccordements EN". S'il commence par "Class" il affiche la table "Raccordements ASME". Il y a donc deux valeurs, on peut mettre deux tags dans un ComboBox, j'ai essayé mais sans succès.

J'ai du coup essayé en mettant cela mais ça ne semble pas fonctionner non plus.

If Left(ComboBox_PN_Class, 2) = "PN" Then ComboBox_Raccordement_Entrée.List = Range("Table_Raccordement_EN").Value

Salut,

Tu n'a pas bien lu le code, c'est un argument de la fonction.

Public Function WriteOnReference(ByVal Index As Long, ByVal StringWrite As String, Optional ByVal Init As Boolean) As String

Elle est noté Optional donc tu peux, ne pas la mettre, à ce moment là elle sera égale = False et donc le code va exécuter le bloc Else de la fonction If Then.

Cela te permet si tu le veux de forcer l'initialisation du tableau ailleurs dans ton code.

Il est vrai que j'aurais du la noté comme suit : Optional Byval Init As Boolean = False

Rechercher des sujets similaires à "manipulation chaines caracteres mid replace"