Comment associer un userform a une plage précise dans une feuille précise

Comment associer un userform a une plage précise dans une feuille précise 1.0

Bonjour a tous
comme on me le demande souvent je vous donne un exemple du comment on associe l'affichage d'un userform a une plage dans une feuille et comment on gère les events de la feuille dans le userform

tout d'abords je redis avant tout un module userform est un module classe
en effet peu le savent et d'autres comprennent mal


une classe dans un module (quel qu’il soit) se déclare comme ceci
dim maclasse as classe1
et dans une sub ou event
set maclasse = new classe1 'classe1 étant le nom du module classe

et bien avec le userform c'est la même chose

voici un exemple
j'ajoute un userform dans mon classeur et je le nomme "menu"

je voudrais qu'il s'affiche au click droit dans la feuil1 en range B3:B10 dès que j'active cette feuille

je commence donc par instancier une classe de mon module userform dans ma feuil1
dans le module de la feuille en question
VB:
Dim u As menu
Public RnG As Range

Private Sub Worksheet_Activate()
Set RnG = [B3:B10]
menu.Umodal = 0
Set u = New menu
End Sub




donc ici déclare un instance classe de mon userform menu
je déclare une variable public range ( la plage que je souhaite
elle peut être sous toute forme contiguë ou pas

et dans l'event activate (de la feuille)
je détermine la plage
j'instancie la classe déclarée
j'ajoute la possibilité de choisir si mon userform menu sera modal ou pas avec une variable déclaré dans le userform (nous allons voir après comment dans le module du userform)

voila la partie code de la feuille est terminé
passons a l'userform "menu"
je vais instancier un classe event feuille dans le userform
Code:
Public WithEvents feuille As Worksheet
parti de la je peux gérer tout les events d'une feuille
je déclare aussi une variable pour le mode modal ou pas
Code:
Public Umodal As Boolean
maintenant il faut instancier la classe event feuille
et cela on va le faire dans le initialise userform( et pas ailleur!!!!!)
VB:
Private Sub UserForm_Initialize()
    Set feuille = ActiveSheet
End Sub
voila c'est pas bien compliqué
maintenant on va coder l'event feuille
les events feuille sont désormais implémentés dans la liste du module userform ( voir capture)
demo7.gif


nous allons pour un menu choisir l'event click droit
voici l'event codé complètement
VB:
Private Sub feuille_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)
    If Not Intersect(ActiveSheet.RnG, Target) Is Nothing Then
        menu.StartUpPosition = 0
        placementRange menu, ActiveCell
        menu.Show menu.Umodal: Cancel = True
    Else
        Cancel = False
    Unload menu
    End If
End Sub
Remarque
1°j'utilise activesheet.rng au lieu de feuil1.rng( pour une réutilisation sur d'autres feuilles
2° je précise toujours le parent userform par son nom et non "Me" comme on le ferait normalement dans un userform(TRES IMPORTANT!!!!)
car en effet dans l'event feuille vous êtes dans la classe et pas dans l'instance du userform proprement dit

je met ensuite le userform en StartUpPosition 0 pour pouvoir le déplacer avant même de l'afficher
je le place avec ma fonction perso (voir plus bas)
je l'affiche avec la variable "umodal" que j'ai instruit dans le activate du module de la feuille
je cancel bien évidement pour ne pas avoir le menu contextuel que l'on a normalement au click droit dans une cellule

comme pour les menus j'ajoute l’effacement du menu au click ailleurs pendant son affichage
ATTENTION!! ne fonctionne qu'en mode non modal( comme les menu classique d'ailleurs )


VB:
' ne fonctionne qu'en mode non modal
Private Sub feuille_SelectionChange(ByVal Target As Range)
 If Intersect(ActiveSheet.RnG, Target) Is Nothing Then Unload menu
End Sub

je joint ma fonction perso pour l'emplacement qui gère toute les possibilités de l'affichage d'une feuille
VB:
'********************************************************************
'********************************************************************
'fonction placementrange issue de mon calendrier plus complet dans les ressources
'https://www.excel-downloads.com/resources/collection-fausse-boite-de-dialogue-patricktoulon-episode-1-un-vrai-faux-calendrier.1119/
Public Function placementRange(uf As Object, Obj As Object)
    If Obj Is Nothing Then Exit Function
    Dim z#, EcX#, L1#, T1#, C#, R#, Vr As Range, Hx#, Wx#, Ok As Boolean, Op&, PtoPx#, I&
    With ActiveWindow
        PtoPx = (.ActivePane.PointsToScreenPixelsX(72) - .ActivePane.PointsToScreenPixelsX(0)) / 72    'coeff point to pixel
        Op = Int(Val(Mid(Application.OperatingSystem, InStrRev(Application.OperatingSystem, " ") + 1)))    'number version system
        'exit si la cellule injecté n'est pas vible a l'ecran
        For I = 1 To .Panes.Count: Ok = IIf(Not Intersect(.Panes(I).VisibleRange, Obj) Is Nothing, True, Ok): Next
        If Ok = False Then Beep: MsgBox " cette cellule n'est pas visible a l'ecran": Exit Function
        z = (ActiveWindow.Zoom / 100): Set Vr = .VisibleRange    'Coeff zoom ,  rangevisible partie mobile
        EcX = 4 And Op = 6 And Int(Val(Application.Version)) < 16  'ecart cadre
        L1 = (.ActivePane.PointsToScreenPixelsX(Int(Obj.Left)) / PtoPx) * z + EcX    'placement partie mobile
        T1 = .ActivePane.PointsToScreenPixelsY(Int(Obj.Top)) / PtoPx * z + EcX
        With .Panes(1).VisibleRange: C = .Cells(.Cells.Count).Column: R = .Cells(.Cells.Count).Row: End With    'limite splitrow et splitcolumn
        If .SplitRow > 0 Then  'placement  dans le splitrow
            If Obj.Row < R + 1 And .ScrollRow > R Then T1 = ((.ActivePane.PointsToScreenPixelsY(Vr.Cells(1).Top) / PtoPx) * z) - (Range(Obj, Cells(R, 1)).Height * z) + EcX
        End If
        If .SplitColumn > 0 Then    'placement  dans le splitcolumn
            If Obj.Column < C + 1 And .ScrollColumn > C Then L1 = ((.ActivePane.PointsToScreenPixelsX(Vr.Cells(1).Left) / PtoPx) * z) - (Range(Obj, Cells(1, C)).Width * z) + EcX
        End If
    End With
    L1 = L1 + Obj.Width '- 2
    T1 = T1 '- 2
    If L1 > Application.Left + Application.Width - Me.Width Then L1 = Application.Left + Application.Width - Me.Width - 15
    If T1 > Application.Top + Application.Height - Me.Height Then T1 = Application.Top + Application.Height - Me.Height - 15
    With uf: .Left = L1: .Top = T1: End With
End Function

voila maintenant votre userform s'affichera a droite de la cellule cliqué si elle se trouve dans la plage "RnG"
vous reste plus qu'a coder votre menu avec des boutons et autres controls dans le userform
Auteur
patricktoulon
Version
1.0