Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Apprendre VBA pour Excel par la pratique - Sixième partie : apprendre la programmation de nouvelles fonctions pour utilisateur
Un tutoriel de L. OTT

Le , par laurent_ott

0PARTAGES

15  0 
Chers membres du club,

J'ai le plaisir de vous présenter ce sixième mémento qui va vous apprendre la programmation de nouvelles fonctions Excel pour l'utilisateur.

Ce sixième et dernier volet de cette hexalogie sur la programmation en VBA pour EXCEL explore un aspect qui n'a pas été souvent abordé dans les précédents mémentos : le développement de fonctions pour simplifier la vie des utilisateurs (et non plus des programmeurs).

Un vaste sujet dont on peut difficilement faire le tour en quelques pages.
Alors ici nous ne présenterons que le contour des techniques à utiliser. Rassurez-vous, il n'y a rien de bien compliqué, d'autant plus qu'Alice et Bob vous guideront au fil de votre lecture.
Bonne lecture et n'hésitez pas à apporter vos commentaires

Retrouvez les meilleurs cours et tutoriels pour apprendre Microsoft Excel

Une erreur dans cette actualité ? Signalez-le nous !

Avatar de laurent_ott
Rédacteur https://www.developpez.com
Le 03/10/2018 à 15:59
Citation Envoyé par maliano20 Voir le message

Pourquoi vous avez préféré le IF au SELECT CASE? J'ai lu quelque part sur ce site que le second est plus rapide.
Par habitude de programmation, tout simplement (et tout bêtement) !
Je viens de tester et effectivement, SELECT CASE semble bien plus rapide que IF dans une boucle répétée plusieurs milliers de fois. Mais la différence est infime sur un appel ponctuel. En tout cas merci pour cette remarque, j'en tiendrai compte dans mes prochains programmes.

Citation Envoyé par maliano20 Voir le message

Pourquoi avoir utiliser le / en lieu et place du \? Étant donné qu'on a besoin de la partie entière de la division, le second n'est il pas plus rapide?
D'après mes tests, le second n'est pas plus rapide. Ici, comme la variable "Milieu" est déclarée Entier Long, la valeur calculée renvoyée sera toujours un entier (donc la partie entière), et donc pas besoin d'utiliser \ dans ce cas.
2  0 
Avatar de eriiic
Membre expert https://www.developpez.com
Le 04/10/2018 à 11:27
Bonjour,

Milieu = (Début + Fin) / 2
Pourquoi avoir utiliser le / en lieu et place du \? Étant donné qu'on a besoin de la partie entière de la division, le second n'est il pas plus rapide?
Attention que ces 2 opérateurs ne sont pas équivalents et substituables, les résultats peuvent être différents.
Avec Début = 1 et Fin = 6, soit une somme impaire :
(Début + Fin) / 2 = 3.5, qui sera arrondi à 4 lors de la conversion si Milieu est typé Entier
(Début + Fin) \ 2 = 3, résultat de la division entière, et restera à 3.
Il faut penser à en tenir compte.
eric
2  0 
Avatar de Filippo
Membre éclairé https://www.developpez.com
Le 18/09/2018 à 14:09
Bonjour Laurent,
merci beaucoup pour ce mémento.
C'est super.

1  0 
Avatar de maliano20
Nouveau membre du Club https://www.developpez.com
Le 03/10/2018 à 14:56
Permettez-moi de vous remercier d'abord pour ces excellents documents.
Code : Sélectionner tout
1
2
If ValRecherchée <= TabDonnées(Début) Then TableauRecherchePosition = Début: Exit Function
If ValRecherchée >= TabDonnées(Fin - 1) Then TableauRecherchePosition = Fin: Exit Function
Pourquoi vous avez préférer le IF au SELECT CASE? J'ai lu quelque part sur ce site que le second est plus rapide.

Code : Sélectionner tout
Milieu = (Début + Fin) / 2
Pourquoi avoir utiliser le / en lieu et place du \? Étant donné qu'on a besoin de la partie entière de la division, le second n'est il pas plus rapide?
1  0 
Avatar de maliano20
Nouveau membre du Club https://www.developpez.com
Le 03/10/2018 à 16:16
Citation Envoyé par laurent_ott Voir le message
Par habitude de programmation, tout simplement (et tout bêtement) !
Je viens de tester et effectivement, SELECT CASE semble bien plus rapide que IF dans une boucle répétée plusieurs milliers de fois. Mais la différence est infime sur un appel ponctuel. En tout cas merci pour cette remarque, j'en tiendrai compte dans mes prochains programmes.

D'après mes tests, le second n'est pas plus rapide. Ici, comme la variable "Milieu" est déclarée Entier Long, la valeur calculée renvoyée sera toujours un entier (donc la partie entière), et donc pas besoin d'utiliser \ dans ce cas.
Merci pour votre prompt réaction.
1  0 
Avatar de laurent_ott
Rédacteur https://www.developpez.com
Le 03/10/2018 à 16:31
À noter qu'il y a encore plus rapide que SELECT CASE, c'est WHILE .... WEND, ou encore DO UNTIL ... LOOP
J'utilise parfois cela dans l'algorithme QuickRanking.
1  0 
Avatar de maliano20
Nouveau membre du Club https://www.developpez.com
Le 06/10/2018 à 23:41
Bonsoir,
J'ai quelques observations sur les triés.

Dans la Function RechercheW() du Tome 6

code 1:

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
 ' Mémorise les données:
Application.Cursor = xlWait

For i = 1 To UBound(PlageDonnées())
TabDonnées(i - 1) = PlageDonnées(i, ColRecherche).Value
Next i

' Trie les données et retourne leur ordre de classement:
Classement = QuickRanking(TabDonnées(), True, 2)
Il est possible de faire l’économie de cette boucle en faisant :

code 2:

Code : Sélectionner tout
1
2
3

TabDonnées= PlageDonnées.Value
Vous avez choisie le code 1 par préférence ou bien pour des considérations techniques?

Dans la Function QuickRanking(), je pense qu'il est préférence de remettre une gestion pour annuler On Error Resume Next dans le code 3 ci-dessous

code 3:

Code : Sélectionner tout
1
2
3
4
5
6
7
' Bornes du tableau des données d'origine :
Dim TabDébut As Long, TabFin As Long

On Error Resume Next ' Si aucune donnée à trier.
TabDébut = LBound(TabDonnées)
TabFin = UBound(TabDonnées)
code 4:

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
' Bornes du tableau des données d'origine :
Dim TabDébut As Long, TabFin As Long

On Error Resume Next ' Si aucune donnée à trier.
TabDébut = LBound(TabDonnées)
TabFin = UBound(TabDonnées)

On Error GoTo FIN

..........

FIN:
Sinon, en cas d'erreur la boucle suivante risque de tourner indéfiniment:

code 5:

Code : Sélectionner tout
1
2
3
i = TabTps(Anc) ' Plus proche donnée inférieure connue.
While Anc < MiniRac: MiniRac =Anc: Wend ' Plus rapide que If Anc < MiniRac Then MiniRac = Anc

Si l'indice min du tableau (LBound(TabDonnées)) est différent de 0, la boucle suivante tourne indéfiniment.

code 6:

Code : Sélectionner tout
1
2
While TabDonnées(TabTps(Début + 1)) < Tps: Début = Début + 1: Wend
1  0 
Avatar de Ar No
Candidat au Club https://www.developpez.com
Le 10/02/2019 à 8:29
Citation Envoyé par laurent_ott Voir le message
Chers membres du club,

J'ai le plaisir de vous présenter ce sixième mémento qui va vous apprendre la programmation de nouvelles fonctions Excel pour l'utilisateur.

Bonne lecture et n'hésitez pas à apporter vos commentaires

Retrouvez les meilleurs cours et tutoriels pour apprendre Microsoft Excel

Bonjour Laurent,

J'ai commencé à faire du VBA en 'suivant' un Laurent (Longre) il y a longtemps, sur Excel 5 ...
petitement, je suis simple utilisateurs de Excel
J'imagine le temps passé sur c'est ouvrages.
Merci donc
Bonjour à Alice
1  0 
Avatar de laurent_ott
Rédacteur https://www.developpez.com
Le 03/10/2018 à 18:06
Je ne peux pas te répondre car je n'utilise pas les class et les collections. Et je n'y connais rien. Donc je donne ma langue au chat.
Tu trouveras un exemple pratique de QuickRanking dans le tome 6.
0  0 
Avatar de laurent_ott
Rédacteur https://www.developpez.com
Le 08/10/2018 à 13:04
Bonjour.
Mes réponses à ces questions:

Il est possible de faire l'économie de cette boucle en faisant : TabDonnées = PlageDonnées.Value
Non, pour deux raisons :
- TabDonnées doit être en base 0 alors que PlageDonnées.Value est en base 1 ;
- PlageDonnées est une plage qui peut avoir plusieurs colonnes, et TabDonnées(i - 1) = PlageDonnées(i, ColRecherche).Value permet de mémoriser les données de la colonne sur laquelle porte la recherche dans cette plage (qui n'est pas forcément la première colonne).

Dans la Function QuickRanking(), je pense qu'il est préférable de remettre une gestion pour annuler On Error Resume Next.
Si l'indice min du tableau (LBound(TabDonnées)) est différent de 0, la boucle suivante tourne indéfiniment.
C'est vrai que je n'ai pas mentionné explicitement qu'il faut que TabDonnées (la mémoire qui contient les données à trier) soit en base 0.
Dit autrement il faut déclarer TabDonnées ainsi :
Code : Sélectionner tout
1
2
Dim TabDonnées() As Variant
ReDim TabDonnées(0 To i-1) ' où i est le nombre d'éléments.
et non pas :
Code : Sélectionner tout
ReDim TabDonnées(1 To i) ' où i est le nombre d'éléments.
Effectivement, tu peux faire une gestion des erreurs pour les cas où TabDonnées n'est pas en base 0 :

Code : Sélectionner tout
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
' Bornes du tableau des données d'origine:
Dim TabDébut As Long, TabFin As Long
On Error Resume Next ' Si aucune donnée à trier.
TabDébut = LBound(TabDonnées)
TabFin = UBound(TabDonnées)

' Controle que TabDonnées est de la forme TabDonnées(0 To i):
If TabDébut <> 0 Then
    MsgBox "Erreur de programmation: TabDonnées doit être de la forme TabDonnées(0 To i)", _
            vbCritical + vbOKOnly, "QuickRanking"
    Exit Function
End If

' Gestion des erreurs:
Err.Clear
On Error GoTo Gest_Err
 
..............

QuickRanking = Pos()

Gest_Err:
If Err.Number <> 0 Then MsgBox "Erreur: " & Err.Number & " - " & Err.Description, _
                        vbCritical + vbOKOnly, "QuickRanking"
Err.Clear
End Function
Merci pour ces remarques très constructives.
0  0