Création d'une calculatrice pour vos applications Access
Date de publication : 15/05/2006 , Date de mise à jour : 15/05/2006
Par
Jean-Philippe AMBROSINO (home page)
Ce document a pour but de vous montrer comment concevoir une petite calculatrice sous Access.
Vous devez être à l'aise avec Microsoft Access et impérativement maîtriser la conception de formulaires ainsi que connaître le langage Visual Basic for Application pour mettre en pratique cet exemple.
1.
Avant propos
1-1.
Remerciements
1-2.
Contact
2. Présentation du projet
3.
Présentation du formulaire exemple
3-1. Le formulaire en mode formulaire
3-2. Les propriétés du formulaire
4. Le formulaire en mode création
4-1. Détail des contrôles utilisés
4-1-1. La partie application
4-1-1-1. Les messages circonstanciels à l'usage du Mode d'affichage
4-1-1-2. Les boutons des fonctions d'application
4-1-2. La partie Calculatrice
4-1-2-1. Liste des contrôles utilisés avec leur nom et position (en pixels)
5. Le code de la calculatrice
5-1. Le projet est constitué de deux Modules de code
5-1-1. Le code du Formulaire
5-1-2. Le code du Module basRegistry
6. Comment cela fonctionne t-il ?
7. Comment l'utiliser ?
7-1. Elle est ouverte, mais je peux pas la déplacer !!!
8.
Conclusion
1.
Avant propos
Ce document a pour but de vous montrer comment concevoir une petite calculatrice sous Access.
En effet, vous pouvez appeler la calculatrice de Windows mais cette opération vous oblige à vérifier si elle n'est pas déjà lancée auquel cas, il vous faut l'afficher au premier plan (donc être à l'aise les API's Windows).
Là, aucun problème de ce coté puisqu'il s'agit d'un formulaire et seules les fonctions de base d'ouverture (DoCmd.OpenForm) et de fermeture (DoCmd.Close) sont nécessaires.
1-1.
Remerciements
Je tiens à remercier toutes celles et ceux qui ont participé à la relecture de ce document en y incluant leurs remarques.
1-2.
Contact
Pour tous renseignements complémentaires, veuillez me contacter directement (
Argyronet) par MP.
2. Présentation du projet
L'objectif de ce tutoriel est de vous montrer qu'il est possible concenoir une petite calculatrice d'appoint parfaitement opérationnelle dans votre application Access.
Cette calculatrice offre toutes les fonctions de base y compris la mémoire (+/-) avec un convertisseur Euro/Francs en temps réel au fur et à mesure des entrées et résultats affichés.
Bon, je vous l'accorde, ce n'est pas forcément très utile mais il s'avère que son usage devient vite pratique si des boutons permettant de l'appeler au moment voulu sont correctement posés dans vos formulaires.
Autre avantage, les calculs trouvés, en dehors du fait que j'ai prévu une routine de copier/coller automatique, peuvent se trouver recopiés dans une zone de texte d'un formulaire parent ou plutôt du formulaire appelant par la ligne de code suivante :
| Recopier le résultat trouvé |
Forms!NomDuFormulaireParent.NomDuContrôle = Me!txtLCDDisplayEUR
|
où bien entendu, txtLCDDisplayEUR est le nom du contrôle affichant le résultat dans la calculatrice ;
(Nous verrons les noms des contrôles un peu plus loin).
3.
Présentation du formulaire exemple
Réaliser une calculatrice d'un point de vue graphique n'est pas très difficile en soit ; il suffit de s'inspirer de sa calculatrice de bureau ou d'une photo idoine représentative...
Le reste se réalise en fonction de vos goûts et en fonction des besoins. Dans ce tutoriel, la calculatrice possède un certain nombre de boutons associés à différentes fonctionnalités et vous n'êtes pas tenu de les greffer tous.
3-1. Le formulaire en mode formulaire
Vous pouvez constater que ce formulaire est volontairement dépourvu du sélecteur et du diviseur d'enregistrements.
J'ai également pour les mêmes raisons d'esthétique, supprimé les boutons de déplacement.
Une fois appelé, il s'ouvre au premier plan en mode Modal, c'est à dire, que vous ne pouvez pas intervenir sur le formulaire qu'il l'a ouvert tant que celui-ci reste affiché.
Comme je suis un peu maniaque, j'ai greffé à la calculatrice un petit bouton permettant à volonté de changer cet état Modal en non Modal pour des raisons pratiques.
Le formulaire en mode formulaire
Pour le coté graphique, le formulaire voit sa propriété
Image affectée à une image dégradée d'un bleu-violet tirant un un écru grisonnant, charte graphique adoptée à l'époque où j'ai créé l'application qui employait cette calculatrice.
Pour créer cette image ou tout autre arrière plan de votre convenance, prenez un logiciel de retouche d'images (
The Gimp,
PaintShop Pro,
Photoshop...), mettez en oeuvre une forme rectangulaire de
100 x 332 pixels puis appliquez-lui le dégradé désiré si vous avez choisi d'opter pour un tel arrière plan
 |
Rognez ensuite l'image de telle sorte à ce que sa taille devienne 1 x 332 pixels et dans les propriétés Mode d'affichage de l'image du formulaire, choisissez Echelle ; le rendu du dégradé sera répété sur toute la largeur de la section détail du formulaire.
Merci à cafeine pour cette remarque...
|
Sauvez l'image au format BMP ou JPG dans le dossier \Images de votre application.
3-2. Les propriétés du formulaire
Liste récapitulative des propriétés à affecter au formulaire
Ce formulaire, pour pouvoir être affiché ainsi, possède donc les propriétés suivantes :
| Propriétés générales |
Propriétés des événements |
 |
 |
Pour afficher les propriétés du formulaire, cliquez deux fois sur la zone externe gris foncé de votre environnement Access ou bien sur le bouton Propriétés de la barre d'outils.
Cliquez alors sur l'onglet intitulé "Toutes" puis "Événements".
 |
TRES IMPORTANT
N'oubliez pas de définir à Oui, la propriété Aperçu des touches (Key Preview) sans quoi, vous ne pourrez pas utiliser la calculatrice avec le clavier...
|
4. Le formulaire en mode création
Lorsque l'on passe en Mode Création, vous pouvez remarquer que qu'il n'y a pas grandes différences avec le mode formulaire.
Le projet exploite 47 contrôles différents parmi lesquels figurent :
 |
des Boutons |
 |
des Zones de texte |
 |
des Etiquettes |
 |
des Rectangles |
Vous en trouverez la liste ci-après.
Le formulaire en mode création (Design)
Du fait que la mise en place de ces contrôles nécessite une certaine précision, je vous recommande de ne pas afficher la Grille que vous désactivez dans le menu Affichage.
 |
Petite astuce
Les touches de raccourcis Ctrl+Flèche de direction déplacent un contrôle ou un groupe de contrôles au pixel près.
Les touches de raccourcis Shift+Flèche de direction agrandissent/rétrécissent un contrôle ou un groupe de contrôles au pixel près.
|
4-1. Détail des contrôles utilisés
Il y a deux parties à considérer pour la réalisation de ce projet :
- 1/ La partie application
- 2/ La partie calculatrice
4-1-1. La partie application
La partie dite "application" relate ce que je considère comme étant les fonctions externes au formulaire lui-même.
En effet, ces fonctions sont représentées par les trois boutons qui sont respectivement :
- Copier (Ctrl+C)
- Coller (Ctrl+V)
- Premier plan / Arrière plan
Vous pouvez constater que trois rectangles de couleur rouge sont leur support.
J'ai posé ces contrôles tout simplement pour indiquer l'état de l'emploi des boutons
- Rouge : Inactif ou non disponible
- Vert : Activé ou enclenché
Dans le code, ces rectangles voient leur propriété BackColor changer en conséquence.
| Code du changement des couleurs des rectangles |
ledCopy.BackColor = RGB(0, 255, 0)
ledPaste.BackColor = RGB(255, 0, 0)
|
 |
Le 3ème bouton quant à lui est peu un particulier parce qu'il masque ou affiche son "conjoint" en conséquence de l'état de la fenêtre :
Son conjoint est bien évidemment un autre bouton illustré différemment. J'ai préféré cette méthode plutôt que l'affectation dynamique de l'image (qui nécessite que l'image soit dans un dossier en tant que fichier) mais rien ne vous empêche de faire comme bon vous semble pour ce cas précis.
|
| Mode non Modal |
Mode Modal |
 |
 |
Mode non Modal : L'accès au formulaire appelant est libre : (il faudra appuyer de nouveau sur le bouton ouvrant la calculatrice si le formulaire appelant occupe tout l'écran). |
Mode Modal : Il est nécessaire de fermer la calculatrice pour avoir la main sur le formulaire appelant : (Le mode Modal est affecté par défaut au formulaire) |
4-1-1-1. Les messages circonstanciels à l'usage du Mode d'affichage
J'ai greffé au projet deux affichages de message avec la fonction MsgBox() qui annoncent respectivement l'état de la calculatrice selon le mode choisi :
Avertissement de désactivation du mode Modal
Avertissement de d'activation du mode Modal
4-1-1-2. Les boutons des fonctions d'application
Vous dessinerez donc trois Rectangles identiques au format 3D enfoncé avec par défaut, la couleur de fond rouge.
Détail des contrôles utilisés pour les actions de Copier/Coller et du Mode fenêtre
 |
Les boutons du mode d'affichage sont superposés ;
- le bouton Mode Modal est au premier plan et possède la propriété Visible définie à True ;
- l'autre bouton Mode non Modal possède bien entendu la propriété Visible définie à False et se trouve sur la couche du milieu ;
(entre le Rectangle et le bouton du premier plan).
|
4-1-2. La partie Calculatrice
C'est de loin la mise en place la plus délicate car elle nécessite de la minutie et de la patience...
L'idéal est de dessiner un bouton pour la partie bouton par exemple et de le dupliquer autant de fois que nécessaire, c'est à dire
27 fois...
Dans un premier temps, posez-les de façon approximative mais régulière. L'ajustement se fait soit à l'aide des données de propriétés par les propriétés
Haut (
Top) et
Gauche (
Left) ou bien comme précisé ci-avant, à l'aide
des raccourcis clavier...
Affectez à chacun d'entre-eux la légende appropriée
 |
Seul le bouton Racine Carrée possède une police Symbole car je n'avais pas trouvé à l'époque le symbole idoine et j'avais triché avec cette méthode en entrant les caractères Öa.
(Ceci dit, rien ne vous empêche de mettre de images pour chacun des boutons).
|
Tous les autres boutons sont définis en police
Arial 12 et colorés en noir pour les chiffres et en différentes couleurs pour les fonctions particulières comme l'illustre
la première image.
Vous dessinerez en suite les rectangles puis les zones de texte.
=> La zone de texte affichant la valeur en Euro - ou plus exactement le résultat trouvé en fait - est définie en Arial 18 Noir avec un fond gris clair et comme Valeur par défaut "0."
=> La zone de texte affichant la valeur en Francs est définie en Arial 11 Gris foncé avec avec un fond gris clair et comme Valeur par défaut "0."
Elle sont toutes les deux justifiées à Gauche.
=> Quatre étiquettes (Label) sont dessinées à gauche de chaque afficheur et recevant respectivement la propriété Intitulé (Caption) avec les caractères € en Arial 16 Italique et F en Arial 10 Italique avec les couleurs Bleu au-dessus du Violet.
=> Deux zones de texte nommées txtPasteData et txtHiddenFinalResult possèdent la propriété Visible à False et sont destinées à recevoir respectivement les informations du presse papier de façon temporaire et le calcul en cours avant de l'afficher.
4-1-2-1. Liste des contrôles utilisés avec leur nom et position (en pixels)
Je vous recommande (
comme je l'ai stipulé dans ce tutoriel) de nommer tous les contrôles même ceux qui ne sont pas utilisés dans le code.
Cela est bien plus pratique pour vous comme pour tout autre développeur qui reprendrait éventuellement votre projet.
Détail des contrôles utilisés pour les les rectangles, zones de texte et images
Vous trouverez ci-dessous, la liste récapitulative des contrôles du formulaire avec leur position en pixels...
 |
Pour ceux d'entre vous qui le souhaitent, vous pouvez très bien mettre en place une procédure de conception du formulaire avec les méthodes Add de l'objet Control ; de ce fait, vous n'aurez plus qu'un minimum de travail à faire...
|
Tableau récapitulatif des contrôles utilisés avec leur position
| Objet |
Type de contrôle |
Nom du contrôle |
Position horizontale |
Position verticale |
Largeur |
Hauteur |
| Bouton 0 |
104 |
btn0 |
x:375 |
y:3150 |
w:945 |
h:397 |
| Bouton 1 |
104 |
btn1 |
x:375 |
y:2640 |
w:450 |
h:397 |
| Bouton 2 |
104 |
btn2 |
x:877 |
y:2640 |
w:450 |
h:397 |
| Bouton 3 |
104 |
btn3 |
x:1366 |
y:2640 |
w:450 |
h:397 |
| Bouton 4 |
104 |
btn4 |
x:375 |
y:2130 |
w:450 |
h:397 |
| Bouton 5 |
104 |
btn5 |
x:877 |
y:2130 |
w:450 |
h:397 |
| Bouton 6 |
104 |
btn6 |
x:1366 |
y:2130 |
w:450 |
h:397 |
| Bouton 7 |
104 |
btn7 |
x:375 |
y:1635 |
w:450 |
h:397 |
| Bouton 8 |
104 |
btn8 |
x:877 |
y:1635 |
w:450 |
h:397 |
| Bouton 9 |
104 |
btn9 |
x:1365 |
y:1635 |
w:450 |
h:397 |
| Bouton + |
104 |
btnAdd |
x:1920 |
y:2130 |
w:500 |
h:397 |
| Bouton C |
104 |
btnC |
x:1920 |
y:1635 |
w:500 |
h:397 |
| Bouton CE |
104 |
btnCE |
x:2505 |
y:1635 |
w:500 |
h:397 |
| Bouton , |
104 |
BtnDec |
x:1366 |
y:3150 |
w:450 |
h:397 |
| Bouton ÷ |
104 |
btnDivide |
x:1920 |
y:3675 |
w:500 |
h:397 |
| Bouton = |
104 |
btnEqual |
x:1366 |
y:3675 |
w:450 |
h:397 |
| Bouton 1/x |
104 |
btnInvert |
x:2505 |
y:2640 |
w:500 |
h:397 |
| Bouton MC |
104 |
btnMemClear |
x:3075 |
y:2647 |
w:470 |
h:397 |
| Bouton M- |
104 |
btnMemLess |
x:3075 |
y:2130 |
w:470 |
h:397 |
| Bouton M+ |
104 |
btnMemMore |
x:3075 |
y:1635 |
w:470 |
h:397 |
| Bouton MR |
104 |
btnMemRecall |
x:3075 |
y:3150 |
w:470 |
h:922 |
| Bouton X |
104 |
btnMult |
x:1920 |
y:3150 |
w:500 |
h:397 |
| Bouton On/Off |
122 |
btnOnOff |
x:405 |
y:3720 |
w:870 |
h:307 |
| Bouton % |
104 |
btnPercent |
x:2505 |
y:3150 |
w:500 |
h:397 |
| Bouton Vx |
104 |
btnSQRT |
x:2505 |
y:2130 |
w:500 |
h:397 |
| Bouton - |
104 |
btnSubst |
x:1920 |
y:2640 |
w:500 |
h:397 |
| Bouton X² |
104 |
btnX2 |
x:2505 |
y:3675 |
w:500 |
h:397 |
| Bouton Copier |
103 |
cmdCopy |
x:2340 |
y:4305 |
w:315 |
h:334 |
| Bouton Mode non modal |
103 |
cmdNoTopMost |
x:3195 |
y:4305 |
w:330 |
h:330 |
| Bouton Coller |
103 |
cmdPaste |
x:2768 |
y:4305 |
w:315 |
h:334 |
| Bouton Mode modal |
103 |
cmdTopMost |
x:3195 |
y:4305 |
w:315 |
h:334 |
| Rectangle des boutons du bas |
103 |
imgAppButtons |
x:240 |
y:4140 |
w:3390 |
h:630 |
| Etiquette € bleue |
100 |
lblCurrency01 |
x:150 |
y:300 |
w:255 |
h:465 |
| Etiquette € violette |
100 |
lblCurrency02 |
x:135 |
y:285 |
w:255 |
h:465 |
| Etiquette F bleue |
100 |
lblFRF1 |
x:165 |
y:990 |
w:195 |
h:285 |
| Etiquette F violette |
100 |
lblFRF2 |
x:180 |
y:1005 |
w:195 |
h:285 |
| Rectangle Copier |
101 |
ledCopy |
x:2295 |
y:4260 |
w:405 |
h:420 |
| Rectangle Coller |
101 |
ledPaste |
x:2723 |
y:4260 |
w:421 |
h:420 |
| Rectangle Mode |
101 |
ledTopMost |
x:3151 |
y:4260 |
w:405 |
h:420 |
| Rectangle grand cadre |
101 |
shpCalc1 |
x:90 |
y:90 |
w:3673 |
h:4822 |
| Rectangle moyen cadre |
101 |
shpCalc2 |
x:225 |
y:1530 |
w:3405 |
h:3255 |
| Rectangle cadre de l'afficheur Euro |
101 |
shpEuroDisplayer |
x:405 |
y:165 |
w:3255 |
h:615 |
| Rectangle cadre de l'afficheur FRF |
101 |
shpFRFDisplayer |
x:405 |
y:960 |
w:3255 |
h:435 |
| Rectangle du bouton On/Off |
101 |
shpLED |
x:375 |
y:3690 |
w:930 |
h:360 |
| Rectangle trait de séparation |
101 |
shpSeparator |
x:120 |
y:855 |
w:3630 |
h:45 |
| Zone de texte Afficheur Euro |
109 |
txtLCDDisplayEUR |
x:465 |
y:225 |
w:3135 |
h:495 |
| Zone de texte Afficheur FRF |
109 |
txtLCDDisplayFRF |
x:465 |
y:1020 |
w:3135 |
h:315 |
5. Le code de la calculatrice
Bien que cela semble être on ne peut plus simple de comprendre les fonctions de base d'une calculatrice, il faut considérer qu'un certain nombre de lignes de code est nécessaire à son bon fonctionnement.
Bien entendu, les fonctions de base d'additions, de soustractions, de multiplications et de divisions restent les plus simples :
L'usage de deux variables tampons qui subissent un changement de résultat en fonction de l'opérateur choisi.
Pour mettre en oeuvre les gestion des opérateurs, il y a plusieurs manière de procéder. J'ai, pour ce projet, choisi l'usage d'une variable de type String qui prend la valeur idoine en fonction du fait que j'appuie sur un chiffre, une virgule ou un opérateur...
Cette variable nommée "m_strLastFlagEntry" reçoit les valeur suivantes :
| Valeur reçue |
Description |
| C |
L'utilisateur a appuyé sur C |
| CE |
L'utilisateur a appuyé sur C |
| ActionIsOperator |
L'utilisateur a appuyé sur un opérateur |
| ActionIsNumber |
L'utilisateur a appuyé sur un chiffre |
| ActionIsNothing |
Aucune action (Equivaut à vbNullString) |
5-1. Le projet est constitué de deux Modules de code
Le code associé à ce projet est réparti dans deux modules ; le premier étant bien entendu le Module de classe du formulaire lui-même et l'autre étant un Modules de projet avec une fonction pour lire dans la Base de Registre...
5-1-1. Le code du Formulaire
L'ensemble du code ci-après est à recopier dans le module du formulaire...
Dans l'en-tête sont déclarées des variables de module ainsi qu'une fonction API
| En-tête de Module du formulaire |
Option Compare Database
Option Explicit
Private m_dblFirstEntry As Double
Private m_dblSecondEntry As Double
Private m_blnWithDecimal As Integer
Private m_blnOperationNumber As Integer
Private m_strLastFlagEntry As String
Private m_strFlagOperator As String
Private m_vntTotalDisplayed As Variant
Private m_intMaxDigit As Integer
Private m_dblBufferMemory As Double
Private m_vntFinalResult As Double
Private m_dblEuroValue As Double
Private m_strSeparator As String
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
|
Les boutons gèrent toujours les mêmes événements
| Code des boutons 1 à 9 et , et = |
Private Sub btn0_Click()
FlagActionButtons "0"
KeepFocus "btn0"
ConvertToFRF
End Sub
Private Sub btn1_Click()
FlagActionButtons "1"
KeepFocus "btn1"
ConvertToFRF
End Sub
Private Sub btn2_Click()
FlagActionButtons "2"
KeepFocus "btn2"
ConvertToFRF
End Sub
Private Sub btn3_Click()
FlagActionButtons "3"
KeepFocus "btn3"
ConvertToFRF
End Sub
Private Sub btn4_Click()
FlagActionButtons "4"
KeepFocus "btn4"
ConvertToFRF
End Sub
Private Sub btn5_Click()
FlagActionButtons "5"
KeepFocus "btn5"
ConvertToFRF
End Sub
Private Sub btn6_Click()
FlagActionButtons "6"
KeepFocus "btn6"
ConvertToFRF
End Sub
Private Sub btn7_Click()
FlagActionButtons "7"
KeepFocus "btn7"
ConvertToFRF
End Sub
Private Sub btn8_Click()
FlagActionButtons "8"
KeepFocus "btn8"
ConvertToFRF
End Sub
Private Sub btn9_Click()
FlagActionButtons "9"
KeepFocus "btn9"
ConvertToFRF
End Sub
Private Sub btnDec_Click()
If m_strLastFlagEntry <> "ActionIsNumber" Then
Me!txtLCDDisplayEUR = "0" & m_strSeparator
ElseIf m_blnWithDecimal = False Then
Me!txtLCDDisplayEUR = Me!txtLCDDisplayEUR & m_strSeparator
m_intMaxDigit = m_intMaxDigit + 1
End If
m_blnWithDecimal = True
m_strLastFlagEntry = "ActionIsNumber"
End Sub
Private Sub btnEqual_Click()
FunctionOperator "="
m_intMaxDigit = 0
KeepFocus "btnEqual"
ConvertToFRF
End Sub
|
Les opérations sont gérées par une seule fonction qui est appelée systématiquement
| Code des boutons des opérateurs + - x ÷ |
Private Sub btnAdd_Click()
FunctionOperator "+"
m_intMaxDigit = 0
KeepFocus "btnAdd"
ConvertToFRF
End Sub
Private Sub btnSubst_Click()
FunctionOperator "-"
m_intMaxDigit = 0
KeepFocus "btnSubst"
ConvertToFRF
End Sub
Private Sub btnDivide_Click()
FunctionOperator "/"
m_intMaxDigit = 0
KeepFocus "btnDivide"
End Sub
Private Sub btnMult_Click()
FunctionOperator "*"
m_intMaxDigit = 0
KeepFocus "btnMult"
ConvertToFRF
End Sub
|
Les boutons d'annulation annulent le contenu des variables et celui d'extinction change la propriété BackColor puis appelle la fonction KeepCurrentResult.
| Code des boutons des fonctions spéciales C CE On/Off |
Private Sub btnC_Click()
Me!txtLCDDisplayEUR = "0" & m_strSeparator
Me!txtLCDDisplayFRF = "0" & m_strSeparator
m_blnWithDecimal = False
m_strLastFlagEntry = "C"
KeepFocus "btnC"
m_intMaxDigit = 0
m_dblEuroValue = 0
End Sub
Private Sub btnCE_Click()
m_strLastFlagEntry = "CE"
KeepFocus "btnCE"
End Sub
Private Sub btnOnOff_Click()
btnOnOff.Caption = "O F F"
btnOnOff.ForeColor = RGB(255, 0, 0)
shpLED.BackColor = RGB(255, 0, 0)
DoEvents
Call Sleep(1000)
KeepCurrentResult
End Sub
|
Les fonctions spéciales exploitent un code aussi simple à comprendre que les opérations de base vues ci-avant.
| Code des boutons des fonctions spéciales Vx 1/x % X² |
Private Sub btnSQRT_Click()
m_dblFirstEntry = Val(Me!txtLCDDisplayEUR)
If m_dblFirstEntry < 0 Then
MsgBox "La racine carré d´un nombre négatif n´est pas valable !" & vbCrLf & _
vbCrLf & "Le calcul est impossible", 48, "Erreur"
Else
m_dblFirstEntry = Sqr(m_dblFirstEntry)
m_intMaxDigit = 0
End If
Me!txtLCDDisplayEUR = str$(m_dblFirstEntry)
m_blnOperationNumber = 1
m_strLastFlagEntry = "ActionIsOperator"
m_strFlagOperator = vbNullString
ConvertToFRF
End Sub
Private Sub btnInvert_Click()
m_dblFirstEntry = Val(Me!txtLCDDisplayEUR)
If m_dblFirstEntry = 0 Then
MsgBox "Cette opération est une division par zéro !" & vbCrLf & vbCrLf & _
"Le calcul est impossible", 48, "Erreur"
Else
m_dblFirstEntry = 1 / m_dblFirstEntry
m_intMaxDigit = 0
End If
Me!txtLCDDisplayEUR = str$(m_dblFirstEntry)
m_blnOperationNumber = 1
m_strLastFlagEntry = "ActionIsOperator"
m_strFlagOperator = vbNullString
KeepFocus "btnInvert"
ConvertToFRF
End Sub
Private Sub btnPercent_Click()
Me!txtLCDDisplayEUR = Format$(m_dblFirstEntry * Val(Me!txtLCDDisplayEUR) / 100)
m_intMaxDigit = 0
KeepFocus "btnPercent"
ConvertToFRF
End Sub
Private Sub btnX2_Click()
On Error GoTo L_ErrOverFow
m_dblFirstEntry = Val(Me!txtLCDDisplayEUR)
m_dblFirstEntry = m_dblFirstEntry * m_dblFirstEntry
m_intMaxDigit = 0
Me!txtLCDDisplayEUR = str$(m_dblFirstEntry)
m_blnOperationNumber = 1
m_strLastFlagEntry = "ActionIsOperator"
m_strFlagOperator = vbNullString
ConvertToFRF
L_ExOverFow:
Exit Sub
L_ErrOverFow:
MsgBox "Vous avez atteint la capacité maximum de calcul du processeur...", 48, "Calcul dépassé"
Resume L_ExOverFow
End Sub
|
Les gestion de la mémoire s'effectue tout simplement avec une variable de module.
| Code des boutons de mise en mémoire |
Private Sub btnMemClear_Click()
If m_dblBufferMemory Then
If MsgBox("Effacer le contenu de la mémoire maintenant ?", 52, "Effacer") = 6 Then
m_dblBufferMemory = 0
End If
End If
End Sub
Private Sub btnMemLess_Click()
m_dblBufferMemory = m_dblBufferMemory - Me!txtLCDDisplayEUR
End Sub
Private Sub btnMemMore_Click()
m_dblBufferMemory = m_dblBufferMemory + Me!txtLCDDisplayEUR
End Sub
Private Sub btnMemRecall_Click()
Me!txtLCDDisplayEUR = vbNullString
Me!txtLCDDisplayEUR = str(m_dblBufferMemory)
End Sub
|
Au sein du formulaire sont gérés les événements et plus particulièrement celui qui est généré par le clavier.
| Code des procédure événementielles du formulaire |
Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
Select Case KeyCode
Case 96, 48: btn0_Click
Case 97, 49: btn1_Click
Case 98, 50: btn2_Click
Case 99, 51: btn3_Click
Case 100, 52: btn4_Click
Case 101, 53: btn5_Click
Case 102, 54: btn6_Click
Case 103, 55: btn7_Click
Case 104, 56: btn8_Click
Case 105, 57: btn9_Click
Case 110: btnDec_Click
Case 111: btnDivide_Click
Case 106: btnMult_Click
Case 107: btnAdd_Click
Case 109: btnSubst_Click
Case 46: btnCE_Click
Case 13: btnEqual_Click
Case 27: InitializeCalculator: btnC_Click
End Select
End Sub
Private Sub Form_Load()
m_strSeparator = GetSystemDecimalSeparator()
btnC.SetFocus
End Sub
Private Sub txtLCDDisplayEUR_KeyPress(KeyAscii As Integer)
KeyAscii = 0
End Sub
|
Les fonctions de conversions sont nécessaires notamment à cause du séparateur de décimale du système mais également pour la conversion en Francs de la valeur Euro.
| Code des fonctions de conversion |
Private Sub ConvertToFRF()
Const EURO As Double = 6.55957
Dim dblResultFound As Double
dblResultFound = ConvertToDouble(Me!txtLCDDisplayEUR)
If dblResultFound = 0 Then
Exit Sub
End If
m_dblEuroValue = dblResultFound
dblResultFound = dblResultFound * EURO
dblResultFound = RoundNumber(dblResultFound, 2)
Me!txtLCDDisplayFRF = str$(dblResultFound)
End Sub
Private Function ConvertToDouble(ByVal varValue As Variant) As Double
Const CHR_DECIMALSEP_COMMA As String = ","
Const CHR_DECIMALSEP_DOT As String = "."
Dim strNumberSeparator As String
Dim strTempNumber As String
Dim dblResult As Double
If InStr(1, varValue, CHR_DECIMALSEP_COMMA) Then
strTempNumber = Replace(varValue, CHR_DECIMALSEP_COMMA, m_strSeparator, 1, -1, vbTextCompare)
ElseIf InStr(1, varValue, CHR_DECIMALSEP_DOT) Then
strTempNumber = Replace(varValue, CHR_DECIMALSEP_DOT, m_strSeparator, 1, -1, vbTextCompare)
Else
strTempNumber = varValue
End If
dblResult = CDbl(strTempNumber)
ConvertToDouble = dblResult
End Function
Private Function RoundNumber(ByVal NValue As Double, ByVal nDigits As Integer) As Double
RoundNumber = Int(NValue * (10 ^ nDigits) + 0.5) / (10 ^ nDigits)
End Function
|
Les fonctions des actions servent à faire en sorte que les calculs soient effectués selon les touches appuyées.
| Code des fonctions et procédures des actions |
Private Sub FunctionOperator(ByVal Operator As String)
If m_strLastFlagEntry = "ActionIsNumber" Then
m_blnOperationNumber = m_blnOperationNumber + 1
End If
If m_blnOperationNumber = 1 Then
m_dblFirstEntry = ConvertToDouble(Me!txtLCDDisplayEUR)
ElseIf m_blnOperationNumber = 2 Then
m_dblSecondEntry = ConvertToDouble(Me!txtLCDDisplayEUR)
Select Case m_strFlagOperator
Case "+"
m_dblFirstEntry = m_dblFirstEntry + m_dblSecondEntry
Case "-"
m_dblFirstEntry = m_dblFirstEntry - m_dblSecondEntry
Case "*"
m_dblFirstEntry = m_dblFirstEntry * m_dblSecondEntry
Case "/"
If m_dblSecondEntry = 0 Then
MsgBox "Cette opération est une division par zéro !" & vbCrLf & vbCrLf & _
"Le calcul est impossible", 48, "Erreur"
Else
m_dblFirstEntry = m_dblFirstEntry / m_dblSecondEntry
End If
Case "="
m_dblFirstEntry = m_dblSecondEntry
End Select
Me!txtLCDDisplayEUR = m_dblFirstEntry
m_blnOperationNumber = 1
End If
m_strLastFlagEntry = "ActionIsOperator"
m_strFlagOperator = Operator
End Sub
Sub KeepFocus(ByVal CtrlName As String)
Dim oForm As Form
Dim oCtl As Control
Set oForm = Form
Set oCtl = oForm.Controls(CtrlName)
oCtl.SetFocus
Set oCtl = Nothing
Set oForm = Nothing
End Sub
Private Sub InitializeCalculator()
m_blnWithDecimal = False
m_blnOperationNumber = 0
m_strLastFlagEntry = "ActionIsNothing"
m_strFlagOperator = vbNullString
End Sub
Private Sub FlagActionButtons(ByVal EnterNum As String)
If m_strLastFlagEntry <> "ActionIsNumber" Then
Me!txtLCDDisplayEUR = vbNullString
Me!txtHiddenFinalResult = 0
m_blnWithDecimal = False
End If
If m_intMaxDigit > 13 Then
Beep
Exit Sub
End If
Me!txtLCDDisplayEUR = Me!txtLCDDisplayEUR + LTrim$(EnterNum)
Me!txtHiddenFinalResult = ConvertToDouble(Me!txtLCDDisplayEUR)
m_intMaxDigit = m_intMaxDigit + 1
m_strLastFlagEntry = "ActionIsNumber"
End Sub
Private Sub KeepCurrentResult()
Const MSG_CLIPBOARD_01 = "Votre résultat "
Const MSG_CLIPBOARD_02 = " est copié en mémoire..."
Const MSG_CLIPBOARD_03 = "Vous pourrez le coller en utilisant les touches Ctrl+V !"
Const MSG_CLIPBOARD_00 = "Copie"
Const MMSG_KEEP_RESULT_01 = "Voulez-vous conserver les résultat de votre calcul pour un usage ultérieur ?"
Const MMSG_KEEP_RESULT_00 = "Conserver le résultat de "
m_vntTotalDisplayed = Val(Me!txtLCDDisplayEUR)
If m_vntTotalDisplayed = 0 Then GoTo L_ExCopyFail
If MsgBox(MMSG_KEEP_RESULT_01, 36, MMSG_KEEP_RESULT_00 & txtLCDDisplayEUR) = 6 Then
DoCmd.GoToControl "txtLCDDisplayEUR"
m_vntFinalResult = ConvertToDouble(Me!txtLCDDisplayEUR)
txtHiddenFinalResult.Visible = True
Me!txtHiddenFinalResult = m_vntFinalResult
txtHiddenFinalResult.SetFocus
txtHiddenFinalResult.SelStart = 0
txtHiddenFinalResult.SelLength = Len(Me!txtHiddenFinalResult)
On Error GoTo L_ErrCopyFail
DoCmd.RunCommand acCmdCopy
MsgBox MSG_CLIPBOARD_01 & m_vntFinalResult & MSG_CLIPBOARD_02 & vbCrLf & _
vbCrLf & MSG_CLIPBOARD_03, , MSG_CLIPBOARD_00
End If
L_ExCopyFail:
DoCmd.Close 2, "frmCalculator"
Exit Sub
L_ErrCopyFail:
MsgBox "Désolé, la copie a échoué...", 48, "Copie"
Resume L_ExCopyFail
End Sub
|
Les fonctions externes (facultatives) peremettent la gestion du Copier/Coller et du mode d'affichage...
| Code des autres fonctions (Copier/Coller/Mode) et l'appel au Registre |
Private Sub cmdCopy_Click()
m_vntTotalDisplayed = Val(Me!txtLCDDisplayEUR)
If m_vntTotalDisplayed = 0 Then Exit Sub
CopyResultToClipboard
ledCopy.BackColor = RGB(0, 255, 0)
ledPaste.BackColor = RGB(255, 0, 0)
End Sub
Private Sub cmdPaste_Click()
Dim dblPastedValue
txtPasteData.Visible = True
txtPasteData.SetFocus
On Error Resume Next
Application.RunCommand acCmdPaste
dblPastedValue = Me!txtPasteData
If dblPastedValue <> 0 And IsNumeric(dblPastedValue) Then
Me!txtLCDDisplayEUR = dblPastedValue
ConvertToFRF
ledCopy.BackColor = RGB(255, 0, 0)
ledPaste.BackColor = RGB(0, 255, 0)
Else
MsgBox "Aucun résultat valide n´est applicable à l´afficheur de la calculatrice !", _
48, "Donnée non numérique ou nulle"
End If
txtPasteData.Visible = False
End Sub
Private Sub cmdNoTopMost_Click()
If MsgBox("La calculatrice est affiché en mode verrouillé et vous devrez l´éteindre pour intervenir " & _
"sur la fenêtre en arrière plan...", 49, "Mode d´affichage") = 1 Then
cmdTopMost.Visible = True
Me.Modal = True
cmdNoTopMost.Visible = False
ledTopMost.BackColor = RGB(255, 0, 0)
End If
End Sub
Private Sub cmdTopMost_Click()
If MsgBox("La calculatrice n´est plus en mode exclusif de fenêtre et vous pouvez intervenir " & _
"sur la fenêtre en arrière plan...", 65, "Mode d´affichage") = 1 Then
cmdNoTopMost.Visible = True
Me.Modal = False
cmdTopMost.Visible = False
ledTopMost.BackColor = RGB(0, 255, 0)
End If
End Sub
Private Sub CopyResultToClipboard()
m_vntTotalDisplayed = Val(Me!txtLCDDisplayEUR)
If m_vntTotalDisplayed = 0 Then GoTo L_ExCopyFail
DoCmd.GoToControl "txtLCDDisplayEUR"
m_vntFinalResult = ConvertToDouble(Me!txtLCDDisplayEUR)
txtHiddenFinalResult.Visible = True
Me!txtHiddenFinalResult = m_vntFinalResult
txtHiddenFinalResult.SetFocus
txtHiddenFinalResult.SelStart = 0
txtHiddenFinalResult.SelLength = Len(Me!txtHiddenFinalResult)
On Error GoTo L_ErrCopyFail
DoCmd.RunCommand acCmdCopy
btnOnOff.SetFocus
txtHiddenFinalResult.Visible = False
L_ExCopyFail:
Exit Sub
L_ErrCopyFail:
MsgBox "Désolé, la copie a échoué...", 48, "Copie"
Resume L_ExCopyFail
End Sub
Private Function GetSystemDecimalSeparator() As String
Const HKEY_CPANEL_INTLKEYS As String = "Control Panel\International"
Dim strDecimal As String
strDecimal = fRegistryGetKeyValue(rootHKeyCurrentUser, HKEY_CPANEL_INTLKEYS, "sDecimal")
If VarType(strDecimal) = vbError Then
Exit Function
End If
GetSystemDecimalSeparator = strDecimal
End Function
|
5-1-2. Le code du Module basRegistry
| Code du Module d´accès au Registre de Windows |
Option Compare Database
Option Explicit
Private Declare Function RegCloseKey Lib "advapi32.dll" (ByVal lngHKey As Long) _
As Long
Private Declare Function RegOpenKeyEx Lib "advapi32.dll" Alias "RegOpenKeyExA" _
(ByVal lngHKey As Long, ByVal lpSubKey As String, ByVal ulOptions As Long, _
ByVal samDesired As Long, phkResult As Long) As Long
Private Declare Function RegQueryValueExString Lib "advapi32.dll" Alias _
"RegQueryValueExA" (ByVal lngHKey As Long, ByVal lpValueName As String, ByVal _
lpReserved As Long, lpType As Long, ByVal lpData As String, lpcbData As Long) _
As Long
Private Declare Function RegQueryValueExLong Lib "advapi32.dll" Alias _
"RegQueryValueExA" (ByVal lngHKey As Long, ByVal lpValueName As String, ByVal _
lpReserved As Long, lpType As Long, lpData As Long, lpcbData As Long) As Long
Private Declare Function RegQueryValueExBinary Lib "advapi32.dll" Alias _
"RegQueryValueExA" (ByVal lngHKey As Long, ByVal lpValueName As String, ByVal _
lpReserved As Long, lpType As Long, ByVal lpData As Long, lpcbData As Long) As _
Long
Private Declare Function RegQueryValueExNULL Lib "advapi32.dll" Alias _
"RegQueryValueExA" (ByVal lngHKey As Long, ByVal lpValueName As String, ByVal _
lpReserved As Long, lpType As Long, ByVal lpData As Long, lpcbData As Long) As _
Long
Public Enum EnumRegistryRootKeys
rootHKeyClassesRoot = &H80000000
rootHKeyCurrentUser = &H80000001
rootHKeyLocalMachine = &H80000002
rootHKeyUsers = &H80000003
End Enum
Public Enum EnumRegistryValueType
RRKREGSZ = 1
RRKREGBINARY = 3
RRKREGDWORD = 4
End Enum
Public Const HKEYLOCALMACHINE As String = "HKEY_LOCAL_MACHINE"
Public Const HKEYCURRENTUSER As String = "HKEY_CURRENT_USER"
Private Const mcregOptionNonVolatile = 0
Private Const MCREGERRORNONE = 0
Private Const MCREGKEYALLACCESS = &H3F
Private Const MCREGKEYQUERYVALUE = &H1
Public Function fRegistryGetKeyValue(ByVal eRootKey As EnumRegistryRootKeys, ByVal strKeyName As String, _
ByVal strValueName As String) As Variant
Dim lngRetVal As Long
Dim lngHKey As Long
Dim varValue As Variant
Dim strValueData As String
Dim abytValueData() As Byte
Dim lngValueData As Long
Dim lngValueType As Long
Dim lngDataSize As Long
On Error GoTo L_ErrRegistryOperation
varValue = Empty
lngRetVal = RegOpenKeyEx(eRootKey, strKeyName, 0&, MCREGKEYQUERYVALUE, lngHKey)
If MCREGERRORNONE = lngRetVal Then
lngRetVal = RegQueryValueExNULL(lngHKey, strValueName, 0&, lngValueType, 0&, lngDataSize)
If lngRetVal = MCREGERRORNONE Then
Select Case lngValueType
Case RRKREGSZ:
If lngDataSize > 0 Then
strValueData = String(lngDataSize, 0)
lngRetVal = RegQueryValueExString(lngHKey, strValueName, 0&, lngValueType, _
strValueData, lngDataSize)
If InStr(strValueData, vbNullChar) > 0 Then
strValueData = Mid$(strValueData, 1, InStr(strValueData, vbNullChar) - 1)
End If
End If
If MCREGERRORNONE = lngRetVal Then
varValue = Left$(strValueData, lngDataSize)
Else
varValue = Empty
End If
Case RRKREGDWORD:
lngRetVal = RegQueryValueExLong(lngHKey, strValueName, 0&, _
lngValueType, lngValueData, lngDataSize)
If MCREGERRORNONE = lngRetVal Then
varValue = lngValueData
End If
Case RRKREGBINARY
If lngDataSize > 0 Then
ReDim abytValueData(lngDataSize) As Byte
lngRetVal = RegQueryValueExBinary(lngHKey, strValueName, 0&, _
lngValueType, VarPtr(abytValueData(0)), lngDataSize)
End If
If MCREGERRORNONE = lngRetVal Then
varValue = abytValueData
Else
varValue = Empty
End If
Case Else
lngRetVal = -1
End Select
End If
RegCloseKey (lngHKey)
End If
fRegistryGetKeyValue = varValue
L_ExRegistryOperation:
Erase abytValueData
Exit Function
L_ErrRegistryOperation:
MsgBox "Error: " & Err.Number & ". " & Err.Description, , _
"fRegistryGetKeyValue"
Resume L_ExRegistryOperation
End Function
|
6. Comment cela fonctionne t-il ?
Le fonctionnement global est relativement simple :
Le formulaire intercepte les séquences de touche par l'événement Form_KeyDown et appelle la procédure associée selon le KeyCode correspondant.
Entrée de chiffres
Quelle que soit la valeur de KeyCode s'il s'agit d'un chiffre, la variable m_strLastFlagEntry prend la valeur appropriée et la fonction FlagActionButtons() est appelée. C'est elle qui régit l'affichage de ce qui est frappé ou cliqué et contrôle que ces séquences ne dépassent pas 13, nombre maximum de chiffres affichables.
Choix d'un opérateur
Quelle que soit la valeur de KeyCode s'il s'agit d'un opérateur, la variable m_strLastFlagEntry prend la valeur appropriée et la fonction FunctionOperator() est appelée. C'est elle qui régit le calcul de ce qui est demandé et contrôle l'erreur potentielle de la Division par zéro puis met à jour l'affichage à partir du moment où le paramètre Operator de la fonction est égale à "=".
Appelle des fonctions spéciales
Quelle que soit la valeur de KeyCode s'il s'agit d'une fonction mathématique spéciale, la variable m_strLastFlagEntry prend la valeur appropriée et chacun des boutons exécute le calcul selon que ce soit :
- une racine carrée : fonction SQR(valeur)
- l'inverse 1/x : opération 1 / valeur
- un pourcentage : opération valeur / 100
- une élévation X² : opération valeur * valeur
Appelle des fonction de mémoire
Ici, une variable de module nommée "m_dblBufferMemory" sert de buffer pour stocker en plus ou en moins la valeur du résultat courant.
Appelle de fonction de Copier/Coller et de mode d'affichage
=> Copier : Cette action appelle la fonction CopyResultToClipboard afin de stocker le résultat dans le presse papier.
=> Coller : Cette action appelle la fonction Application.RunCommand acCmdPaste afin de coller le résultat dans la zone de texte txtLCDDisplayEUR et appelle la fonction ConvertToFRF pour convertir instantanément la valeur en francs.
=> Mode : Cette action change la propriété Modal à True ou à False selon le choix et change la visiblité du bouton ainsi que la couleur du rectangle selon le cas.
Les autres opérations
- L'extinction de la calculatrice ferme le formulaire et affiche un message pour conserver le résultat dans le presse papier...
- L'utilisation de la touche C vide le contenu de la variable m_dblEuroValue et met les afficheurs à 0.
- Pour chacun des boutons, la fonction KeepFocus est appelée de manière à laisser le focus sur le bouton lors de l'utilisation du clavier pour simuler l'usage de la souris.
7. Comment l'utiliser ?
Bien une fois que vous avez terminé la conception et testé en mode formulaire que tout fonctionnait correctement, vous pouvez ouvrir la calculatrice depuis un autre formulaire avec la méthode :
| Ouvrir un formulaire |
Private Sub cmdShowCalculator()
DoCmd.OpenForm "", acNormal, , , , acDialog
End Sub
|
7-1. Elle est ouverte, mais je peux pas la déplacer !!!
Si effectivement vous avez, comme je l'ai stipulé, défini la propriété Fen indépendante à Oui, vous n'avez alors plus de barre de titre ; de ce fait, il est impossible de déplacer le formulaire.
La solution consiste alors à ajouter du code sur les événements Mouse_Move des Rectangles de la calculatrice
Pour ce faire, vous devez ajouter un Module que vous nommez basAPI par exemple dans lequel vous copiez le code suivant :
| Déclaration des API´s dans un module |
Public Declare Function ReleaseCapture Lib "user32" () As Long
Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Public Const WM_NCLBUTTONDOWN = &HA1
Public Const HTCAPTION = 2
|
Il vous reste alors à gérer les évenenemts pour chacun des rectangles comme suit :
| Code du déplacement de la calculatrice |
Private Sub imgAppButtons_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
MoveMyCalculator Button
End Sub
Private Sub shpCalc1_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
MoveMyCalculator Button
End Sub
Private Sub shpCalc2_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
MoveMyCalculator Button
End Sub
Private Sub MoveMyCalculator(Button As Integer)
If Button = 1 Then
ReleaseCapture
SendMessage Me.hwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0&
End If
End Sub
|
L'événement Mouse_Move exploite 4 paramètres :
- Button => Identifie quel bouton (gauche ou droite) est appuyé
- Shift => Identifie quelle touche du clavier parmi les touches Ctrl, Alt, Maj
- X => Identifie la position horizontale du pointeur
- Y => Identifie la position verticale du pointeur
Dans la procédure MoveMyCalculator, on identifie le bouton et si c'est bien le bouton gauche qui est appuyé (1) alors les appels des fonctions ReleaseCapture et de SendMessage sont lancés et permettent d'effectuer le déplacement de la fenêtre...
8.
Conclusion
Ce petit projet reste intéressant pour les développeurs qui souhaitent mettre à la disposition des utilisateurs de leurs applications une calculatrice personnalisée.
Les avantages ont été évoqués en début de document et personnellement, je préfère offrir une calculette de ce type pour mes applications plutôt que mettre un exécutable qui ouvrirait de façon unique et au premier plan la calculatrice de Windows (La calculatrice de Windows est malheureusement multi-instances).
Je vous laisse donc créer votre calculette personnalisée avec pourquoi pas, d'autres fonctions spécifiques associées à d'autres boutons. Les possiblités sont vastes, ce tutoriel étant en fait une petite base de départ pour commencer.
N'hésitez pas à me contacter si vous rencontrez des difficultés.


Ce document est issu de http://www.developpez.com et reste la propriété exclusive de son auteur.
La copie, modification et/ou distribution par quelque moyen que ce soit est soumise à l'obtention préalable de l'autorisation de l'auteur.