2 pièce(s) jointe(s)
Démo pour positionner un UserForm ou ContextMenu sur la grille (Toute version)
Pièce jointe 644373 : la démo
Pièce jointe 644374 : la conversion pour Excel 2003
Cette démo permet de montrez comment positionner un UserForm ou un Menu Contextuel sur une position de la grille
La fonction permettant de convertir une position de la grille en position écran et toutes les fonctions associées sont contenues dans le module 'Lib' et les fonctions assurant la compatibilité avec Excel 2003 dans le module 'LibV11'.
Avec ce problème, c'est l'occasion de montrer comment assurer la compatibilité avec toutes les versions depuis 2003 avec la constante de précompilation classique VBA7 mais qui ne répond pas au problème du passage de la version 2003 à 2007. Dans ce cas il faut utiliser du simple code :
Code:
XLS2003 = IIf(Val(Application.Version) < 12, True, False)
La fonction permettant d'obtenir la position écran à partir du coin Haut-Gauche d'une cellule est GetScreenGridPos et GetScreenGridPosV11 pour la version Excel 2003.
Les fonctions pane.PointsToScreenPixelsX et pane.PointsToScreenPixelsY d'Excel assure déjà plutôt bien cette fonction (disponible depuis la version Excel 2007) mais comporte une imprécision variant de 1 (zoom à 100%) à 4 (zoom à 400%) pixels qui est corrigé par cette fonction reprenant le principe de l'algorithme développé par Pijaku en éliminant les 2 à 3% de cas d'echec de sa fonction et en améliorant la performance.
Source : Déterminer les coordonnées en pixels, par rapport à l'écran, du coin supérieur gauche d'une cellule Excel
Ce que j'ai corrigé ce sont les cas ou la position déterminée au départ est située en dehors de la grille et qui concerne les cellules du pourtour de la grille. Pour retrouver la grille je me déplace en diagonale en direction de la grille plutôt que de façon rectiligne. Une fois la grille trouvée je cherche le coin de la cellule en me déplaçant de façon rectiligne.
Code:
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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| Public Function GetScreenGridPos(ByVal noPane As Integer, ByVal cellTopLeft As Range) As ScreenPos
Dim cel As Range, x As Long, y As Long, crtPane As Pane
Dim wayHor As Integer, wayVert As Integer, state As Byte, totIt As Byte
Set crtPane = ActiveWindow.Panes(noPane)
With crtPane
'Repérer la 1ère ligne et la 1ère colonne du volet
wayHor = IIf(cellTopLeft.Column = .ScrollColumn, 1, -1) 'Sens Hor
wayVert = IIf(cellTopLeft.row = .ScrollRow, 1, -1) 'Sens Vert
x = .PointsToScreenPixelsX(cellTopLeft.Left)
y = .PointsToScreenPixelsY(cellTopLeft.Top)
Do
Set cel = ActiveWindow.RangeFromPoint(x, y)
If cel Is Nothing Then
If (state And 2) Then state = state + 2
x = x + wayHor: y = y + wayVert
Else
If state < 3 Then
If cel.Left < cellTopLeft.Left Then
state = IIf(state = 2, 4, 1)
x = x + 1
Else
Select Case state
Case 0: wayHor = 1: wayVert = 0: state = 2
Case 1: state = 4
Case 2: x = x - 1
End Select
End If
End If
If state > 3 Then
If cel.Top < cellTopLeft.Top Then
state = IIf(state = 6, 8, 5)
y = y + 1
Else
Select Case state
Case 4: wayHor = 0: wayVert = 1: state = 6
Case 5: state = 8
Case 6: y = y - 1
End Select
End If
End If
End If
totIt = totIt + 1: If totIt = 20 Then state = 9
Loop Until state > 7
End With
'State = 9 : retour=(0,0)
GetScreenGridPos.x = IIf(state = 8, x, 0)
GetScreenGridPos.y = IIf(state = 8, y, 0)
End Function |
Le deuxième élément important à calculer est le coefficient permettant de passer d'une grandeur en pixel vers une grandeur en point :
J'ai créer une variable globale 'PxToPt' que je calcule au moment de l'initialisation.
Il existe plusieurs façon de calculer ce coefficient, dont une qui utilise des fonctions systèmes et permet aussi de connaître la résolution de l'écran.
Sinon il existe ce calcul très simple que j'ai testé avec toute les valeurs entières de zoom entre 10 et 400 et fonctionne très bien :
Code:
1 2 3 4 5
| Sub SetPxToPt()
With ActiveWindow
PxToPt = Round(11520 / (.Panes(1).PointsToScreenPixelsX(57600 / .Zoom) - .Panes(1).PointsToScreenPixelsX(0))) / 20
End With
End Sub |
Cette macro ne peut être utilisée sous Excel 2003 car pane.PointsToScreenPixelsXouY n'existait pas et il y a donc la macro 'SetPxToPtV11' qui détermine le taux par tatonnement. Elle cherche la plus petite hauteur d'une ligne (1 pixel) et interroge excel pour savoir quel est cette hauteur en point.
Les modules 'exemple' permettant de tester les fonctions ci-dessus
Le module 'Ex1' : il met à disposition un menu contextuel qui permet de changer le nombre de volet, le zoom, de changer d'algo pour tester GetScreenGridPos et GetScreenGridPosV11 ...
Le module 'Ex2' :
Il est possible d'afficher le Userform1 depuis le menu contextuel mais dans certaines versions Excel (ou windows), l'affichage du menu contextuel déborde un peu par rapport à la position d'affichage.
La fonction 'SwapWindowStyle' utilisant des fonctions système permet de modifier l'apparence du Userform en le transformant en simple rectangle est une solution au problème ci-dessus. Accessible depuis le menu avec le bouton 'Basculer en Style Simple'.
Retirer la compatibilité avec Excel 2003
- Il faut supprimer le module 'LibV11'
- Dans le module 'Lib' :
Il faut modifier la macro 'InitLib' en remplaçant
par Il faut retirer, dans la fonction 'GetScreenGridPos', la partie en commentaire 'COMP2003'
La fonction 'GetGapSize' n'a pas forcément d'utilité sauf cas particulier et peut être retiré aussi
2 pièce(s) jointe(s)
Nouvelle version de cette Démo
Citation:
Envoyé par
BrunoM45
Bonjour,
Grossière erreur dans l'aide du classeur :lol:
"Pour pouvoir tester cette fonction il suffit de se positionner sur l'onglet 'Démo' et de cliquer sur le bouton gauche de la souris sur la cellule ou vous"
Sinon sympa ;)
Bonjour,
Evidemment j'ai corrigé le texte, mais j'ai surtout revu la partie contenu dans le module 'Ex2_SysFun' du code utilisant mal les fonctions systèmes. Il faut notamment associé d'après la documentation SetWindowLong avec SetWindowPos (avec l'option Show ou Hide) pour les modifications de style soient effectivement prise en compte. J'initialise l'instance window de mon UserForm 'HWinInst' à l'initialisation de façon à ne plus avoir besoin d'utiliser 'GetForeground'. J'utilise d'ailleurs 'GetActiveWindow' à la place mais à l'init.
J'ai ajouté une fonction PosResizeWindow pour pouvoir positionner mon UserForm sans que des contraintes de taille ne soient appliquées et corrige la taille de mon UserForm. C'est aussi pourquoi j'ai aussi ajouté une fonction "Retailler en mini" dans mon Menu Contextuel pour montrer son application.
Je propose une version générique pour la procédure 'SetPxToPt' fournie par @patricktoulon utilisant la base de registre. D'autres méthodes sont présentes dans le module 'Tools' si celle-ci ne convient pas.
J'ai aussi corrigé le code qui permet de créer le menu contextuel en lui donnant un nom aléatoire qui ne soit pas déjà utilisé au sein de la même session Excel.
J'ai eu un retour de @patricktoulon qui m'expliquait que sur sa configuration il a un soucis avec 'DrawMenuBar' et que le UserForm ne s'affiche pas correctement lorsque l'on change son style entre 'simple' et 'classique'.
Du coup merci à ceux qui, ayant un problème à l'utilisation, me feront part de leur retour ...