XL 2016 affichage userform avec 2 ou + ecrans

roby

XLDnaute Occasionnel
Bonjour le forum,

Lorsqu'on lance un fichier Excel sur un poste avec plusieurs écrans, à chaque fois les userform s'affichent sur un autre écran que l'écran ou est affiché excel.
y a-t-il une parade pour que cet userform s'affiche dans la même fenêtre que excel ?

je joint le même fichier solutionné dernièrement pour le test.

Merci encore.
 

Pièces jointes

  • Roby1.xlsm
    19.8 KB · Affichages: 16

Dudu2

XLDnaute Barbatruc
Tu as sûrement raison. Et tu es satisfait de ce que tu as produit.

Et moi je suis satisfait de ma fonction centralisée de positionnement PositionUserFormSurObjetFeuille() qui fait référence à l'API pour des choses nécessaires, y compris pour les conversions de Pixels en Points même si tu préfères faire autrement. Je suis aussi satisfait de la manière dont je détermine dans une fonction dédiée le Pane de l'Objet qui n'est pas dépendant de leurs VisibleRanges. Et aussi de la marge entre le RECT de la Window et le RECT du DWM.

Bref, on est tous les deux satisfaits. C'est pas beau la vie ?
1666121267664.gif
 

patricktoulon

XLDnaute Barbatruc
oui de toute façon ca fonctionne
et en voulant te montrer la simplicité je me suis apercu d'un inconvénient a utiliser une methode (api ou autre ) pour point to pixel
dans l'exemple que je viens de te donner j'ai mis en dur 1.333333333333333
ya pas de soucis c'est ça de toute façon je suis bien en dpi 100%

sauf!! que quand j'applique un zoom excel ben le coeff 1.33333... n'est plus valable
alors qu'avec ma méthode pointtoscreenpixels 72 ben zoom ou pas zoom on reste bon
et c'est logique a vrai dire
fait le test tu verra ;)
 

Dudu2

XLDnaute Barbatruc
sauf!! que quand j'applique un zoom excel ben le coeff 1.33333... n'est plus valable
Un ratio Pixel To Point ou l'inverse est invariant. Chez moi 0.6 et 1.66. L'API me le donne.
C'est lorsqu'on fait référence à une objet sensible au zoom qu'il faut appliquer le Zoom sur le calcul de sa position. Tu crois l'appliquer au ratio Pixel to Point mais tu te trompes à cause de ta méthode de calcul du ratio à laquelle je préfère l'API à cause de ça et des décimales pas toujours stables avec la variation du Zoom.

D'autant que les Pane.PointsToScreenPixelsX et Y tiennent compte du Zoom. Pas besoin de corriger !
Et lorsque je décale le UserForm je n'applique nullement le Zoom à la conversion Pixel To Point car le UserForm n'est pas sensible au Zoom.

Dans mon code je n'ai AUCUNE référence au zoom et pourtant la position du UserForm s'adapte parfaitement au zoom grâce au Pane.PointsToScreenPixelsX et Y.
 

Dudu2

XLDnaute Barbatruc
maintenant si tu veux m'aider a trouver l'activepane de l'oleobject ou shape cliqué je veux bien
mais juste ça pas tout ton module
Là franchement @patricktoulon, je sais pas quoi te dire.
Ma fonction de détermination du Pane permet de déterminer sur option:
- Le Pane que l'objet y soit visible ou non
- Le Pane uniquement si l'objet y est visible (méthode qui rejoint +/- la tienne)
Si ce code ne te convient pas je ne vois pas quoi d'autre te proposer ni dans la forme ni dans la fonctionnalité.
VB:
'----------------------------------------------------
'Pane de l'objet dont le parent est la feuille active
'- Visible = True, l'objet doit être visible
'- Visible = False, l'objet peut être visible ou non
'----------------------------------------------------
Private Function ObjectPane(Obj As Object, Optional Visible As Boolean = True) As Pane
    Dim Rng As Range
    Dim i As Integer
    Dim Pan As Pane
    Dim PosRow As Integer
    Dim PosColumn As Integer
 
    'Le Parent de l'objet n'est pas la feuille
    If Not TypeOf Obj.Parent Is Worksheet Then Exit Function
 
    'Selon le type d'objet
    Select Case True
        Case TypeOf Obj Is Range
            Set Rng = Obj
 
        Case Else
            Set Rng = Obj.TopLeftCell
    End Select
 
    With ActiveWindow
        '--------------------------------
        'L'objet peut être visible ou non
        '--------------------------------
        If Not Visible Then
            If .SplitRow = 0 Then
                PosRow = 1
            Else
                If Rng.Row <= .SplitRow Then PosRow = 2 Else PosRow = 3
            End If
  
            If .SplitColumn = 0 Then
                PosColumn = 1
            Else
                If Rng.Column <= .SplitColumn Then PosColumn = 4 Else PosColumn = 5
            End If

            Select Case PosRow * PosColumn
                Case 1, 2, 4, 8
                    Set Pan = .Panes(1)
                Case 3, 5, 10
                    Set Pan = .Panes(2)
                Case 12
                    Set Pan = .Panes(3)
                Case 15
                    Set Pan = .Panes(4)
            End Select
 
        '-------------------------
        'L'objet doit être visible
        '-------------------------
        Else
            'Recherche du Pane de l'objet si visible
            For i = 1 To .Panes.Count
                If Not Intersect(Rng, .Panes(i).VisibleRange) Is Nothing Then Exit For
            Next i
            If i <= .Panes.Count Then Set Pan = .Panes(i)
        End If
    End With
 
    'Return Value
    Set ObjectPane = Pan
End Function

Edit: D'ailleurs cette fonction n'est pas liée à un objet nécessairement sélectionné. Mais à mon avis qu'il soit sélectionné ou pas tu n'y coupes pas de passer par un code équivalent car la sélection n'aide en rien à déterminer son Pane. Car .Pane n'est pas une propriété de Selection.
Et tu n'as pas 36 options:
- Soit tu t'intéresses au VisibleRange des Panes (auquel cas ça limite ta recherche à la partie visible)
- Soit tu t'intéresses au point de croisement des volets (les fameux .SplitRow et .SplitColumn que tu dédaignes)

Maintenant tu as peut-être une méthode miracle à laquelle je n'ai pas pensé.
Je me méfie quand tu me poses ce genre de question pour m'amener à exposer des options que tu te ferais un plaisir de dézinguer !
 
Dernière édition:

Dudu2

XLDnaute Barbatruc
Une autre méthode plus "lisible" mais moins "élaborée" que la première à mon avis.
VB:
'----------------------------------------------------
'Pane de l'objet dont le parent est la feuille active
'- Visible = True, l'objet doit être visible
'- Visible = False, l'objet peut être visible ou non
'----------------------------------------------------
Function ObjectPane2(Obj As Object, Optional Visible As Boolean = True) As Pane
    Dim Rng As Range
    Dim i As Integer
    Dim Pan As Pane
    Dim FreezeCell As Range
 
    'Le Parent de l'objet n'est pas la feuille
    If Not TypeOf Obj.Parent Is Worksheet Then Exit Function
 
    'Selon le type d'objet
    Select Case True
        Case TypeOf Obj Is Range
            Set Rng = Obj
 
        Case Else
            Set Rng = Obj.TopLeftCell
    End Select
 
    With ActiveWindow
        '--------------------------------
        'L'objet peut être visible ou non
        '--------------------------------
        If Not Visible Then
            'https://www.mrexcel.com/board/threads/vba-how-do-i-figure-out-what-cell-at-which-panes-are-frozen-with-freezepanes.1129717/
            Set FreezeCell = ActiveSheet.Cells(.Panes(1).ScrollRow + .SplitRow, .Panes(1).ScrollColumn + .SplitColumn)
           
            '2 Panes
            If .Panes.Count = 2 Then
                'Split sur une ligne
                If FreezeCell.Column = 1 Then
                    If Rng.Row < FreezeCell.Row Then
                        Set Pan = .Panes(1)
                    Else
                        Set Pan = .Panes(2)
                    End If
                   
                'Split sur une colonne
                Else
                    If Rng.Column < FreezeCell.Column Then
                        Set Pan = .Panes(1)
                    Else
                        Set Pan = .Panes(2)
                    End If
                End If
           
            '4 panes
            Else
                'Dans les 2 premiers Panes
                If Rng.Row < FreezeCell.Row Then
                    If Rng.Column < FreezeCell.Column Then
                        Set Pan = .Panes(1)
                    Else
                        Set Pan = .Panes(2)
                    End If
               
                'Dans les 2 derniers Panes
                Else
                    If Rng.Column < FreezeCell.Column Then
                        Set Pan = .Panes(3)
                    Else
                        Set Pan = .Panes(4)
                    End If
                End If
            End If
 
        '-------------------------
        'L'objet doit être visible
        '-------------------------
        Else
            'Recherche du Pane de l'objet si visible
            For i = 1 To .Panes.Count
                If Not Intersect(Rng, .Panes(i).VisibleRange) Is Nothing Then Exit For
            Next i
            If i <= .Panes.Count Then Set Pan = .Panes(i)
        End If
    End With
 
    'Return Value
    Set ObjectPane2 = Pan
End Function
 
Dernière édition:

Dudu2

XLDnaute Barbatruc
Je reviens là-dessus:
mais juste ça pas tout ton module
On dirait qu'il te faut tout au plus court du code source. Faire des fonctions séparées ça permet de pas mélanger les choses et de pouvoir les ré-utiliser dans des contextes différents et de les partager.

Au passage, pour le Pixel To Point sans API, tu ferais bien d'en faire des fonctions séparées qui te rendent toujours l'équivalent de l'API. Car à tout concentrer dans des instructions à rallonge (Zoom dans le calcul des Pixel To Point + Zoom ou pas Zoom dans le calcul de la position) tu ne sais plus ce que tu fais.

Tu peux faire du code in-line pour la détermination du Pane, mélangé avec tes calculs de positions, de conversions Pixel To Point et de décalages. En concentrant l'écriture au maximum pour faire croire que tu fais court, mais c'est pas comme ça qu'il faut faire. C'est une vieille histoire.

Le deal c'est pas de faire un code compressé comme un Zip avec des lignes multi-instructions et des calculs qui finissent par être incompréhensibles à la relecture 3 jours plus tard. Ça n'accélère pas l'exécution du code et ça rend la maintenance et le partage difficiles.
 
Dernière édition:

patricktoulon

XLDnaute Barbatruc
re
je reviens sur ce que tu dis
Le deal c'est pas de faire un code compressé comme un Zip avec des lignes multi-instructions et des calculs qui finissent par être incompréhensibles à la relecture 3 jours plus tard. Ça n'accélère pas l'exécution du code et ça rend la maintenance et le partage difficiles.
ben sans vouloir offenser d'aucune manière tu devrais appliquer cette doctrine a toi même
le pire je crois c'est que tu est convaincu de ce que tu dis

honnêtement quand je regarde ton code je ne sais même pas par ou commencer pour en comprendre la mécanique et c'est pas peine de faire des efforts crois moi

je connais très bien la fonction pointstoscreenpixels( et ses mystères qui n'en sont pas) et je l'ai suffisamment défendu dans un débat (qui date un peu) sur DVP alors que tout le monde était contre moi

je reviens sur ma question
est tu capable de m'expliquer en quoi et comment ta fonction détermine le pane de l'oleobject ou shapes cliqué
encore une fois et honnêtement ,je teste par ce que je veux pas dire sans preuve mais a la simple lecture du code je savais déjà que ça ne marcherait pas
ou a lors j'ai raté un épisode
je crois que quand tu code tu ne dois pas faire tout les tests

VB:
'----------------------------------------------------
'Pane de l'objet dont le parent est la feuille active
'- Visible = True, l'objet doit être visible
'- Visible = False, l'objet peut être visible ou non
'----------------------------------------------------
Private Function ObjectPane(Obj As Object, Optional Visible As Boolean = True) As Pane
    Dim Rng As Range
    Dim i As Integer
    Dim Pan As Pane
    Dim PosRow As Integer
    Dim PosColumn As Integer
 
    'Le Parent de l'objet n'est pas la feuille
    If Not TypeOf Obj.Parent Is Worksheet Then Exit Function
 
    'Selon le type d'objet
    Select Case True
        Case TypeOf Obj Is Range
            Set Rng = Obj
 
        Case Else
            Set Rng = Obj.TopLeftCell
    End Select
 
    With ActiveWindow
        '--------------------------------
        'L'objet peut être visible ou non
        '--------------------------------
        If Not Visible Then
            If .SplitRow = 0 Then
                PosRow = 1
            Else
                If Rng.Row <= .SplitRow Then PosRow = 2 Else PosRow = 3
            End If
 
            If .SplitColumn = 0 Then
                PosColumn = 1
            Else
                If Rng.Column <= .SplitColumn Then PosColumn = 4 Else PosColumn = 5
            End If

            Select Case PosRow * PosColumn
                Case 1, 2, 4, 8
                    Set Pan = .Panes(1)
                Case 3, 5, 10
                    Set Pan = .Panes(2)
                Case 12
                    Set Pan = .Panes(3)
                Case 15
                    Set Pan = .Panes(4)
            End Select
 
        '-------------------------
        'L'objet doit être visible
        '-------------------------
        Else
            'Recherche du Pane de l'objet si visible
            For i = 1 To .Panes.Count
                If Not Intersect(Rng, .Panes(i).VisibleRange) Is Nothing Then Exit For
            Next i
            If i <= .Panes.Count Then Set Pan = .Panes(i)
        End If
    End With
 
    'Return Value
    Set ObjectPane = Pan
End Function

je constate aussi que tu disais hier ne pas avoir a utiliser visible range t tout le toin toin
et je lis dans ton code
VB:
 For i = 1 To .Panes.Count
                If Not Intersect(Rng, .Panes(i).VisibleRange) Is Nothing Then Exit For
            Next i

de plus comme je suis quelqu'un qui aime être sur je teste ta fonction
avec un seul shape dans une feuille fractionnée (voir démo visuelle après )
allez c'est parti un test simple

VB:
Sub Rectangle1_Cliquer()'macro affectée  à  la shape
MsgBox ObjectPane(ActiveSheet.Shapes(1), True).Index  'true ou false ca change rien c'est toujours  la pane 1  qui est trouvée
End Sub



'----------------------------------------------------

'Pane de l'objet dont le parent est la feuille active

'- Visible = True, l'objet doit être visible

'- Visible = False, l'objet peut être visible ou non

'----------------------------------------------------

 Function ObjectPane(Obj As Object, Optional Visible As Boolean = True) As Pane

    Dim Rng As Range

    Dim i As Integer

    Dim Pan As Pane

    Dim PosRow As Integer

    Dim PosColumn As Integer

 

    'Le Parent de l'objet n'est pas la feuille

    If Not TypeOf Obj.Parent Is Worksheet Then Exit Function

 

    'Selon le type d'objet

    Select Case True

        Case TypeOf Obj Is Range

            Set Rng = Obj

 

        Case Else

            Set Rng = Obj.TopLeftCell

    End Select

 

    With ActiveWindow

        '--------------------------------

        'L'objet peut être visible ou non

        '--------------------------------

        If Not Visible Then

            If .SplitRow = 0 Then

                PosRow = 1

            Else

                If Rng.Row <= .SplitRow Then PosRow = 2 Else PosRow = 3

            End If

 

            If .SplitColumn = 0 Then

                PosColumn = 1

            Else

                If Rng.Column <= .SplitColumn Then PosColumn = 4 Else PosColumn = 5

            End If


            Select Case PosRow * PosColumn

                Case 1, 2, 4, 8

                    Set Pan = .Panes(1)

                Case 3, 5, 10

                    Set Pan = .Panes(2)

                Case 12

                    Set Pan = .Panes(3)

                Case 15

                    Set Pan = .Panes(4)

            End Select

 

        '-------------------------

        'L'objet doit être visible

        '-------------------------

        Else

            'Recherche du Pane de l'objet si visible

            For i = 1 To .Panes.Count

                If Not Intersect(Rng, .Panes(i).VisibleRange) Is Nothing Then Exit For

            Next i

            If i <= .Panes.Count Then Set Pan = .Panes(i)

        End If

    End With

 

    'Return Value

    Set ObjectPane = Pan

End Function
ben je suis désolé mais tu a tout faux
ta fonction me renvoie toujours la pane 1
démonstration
demo.gif


et pour qu'il n'y ai pas d’ambiguïté je donne le fichier test avec ta fonction tel que je l'ai testé chez moi 2013 et au boulot 2016
 
Dernière édition:

Dudu2

XLDnaute Barbatruc
est tu capable de m'expliquer en quoi et comment ta fonction détermine le pane de l'oleobject ou shapes cliqué
La fonction ne donne pas le Pane de l'objet cliqué mais le Pane de l'objet désigné.
Si tu veux qu'elle donne le Pane de l'objet cliqué tu l'appelles comme ça:
Set Pan = ObjectPane(Selection)

Ou encore si tu sélectionnes un objet et que tu scrolles pour qu'il disparaisse de l'écran et que tu veux quand même son Pane tu l'appelles comme ça:
Set Pan = ObjectPane(Selection, Visible:=False)

Edit:
Le paramètre Visible est commenté, c'est simple:
VB:
'----------------------------------------------------
'Pane de l'objet dont le parent est la feuille active
'- Visible = True, l'objet doit être visible
'- Visible = False, l'objet peut être visible ou non
'----------------------------------------------------
Function ObjectPane(Obj As Object, Optional Visible As Boolean = True) As Pane
 
Dernière édition:

Dudu2

XLDnaute Barbatruc
De toutes façon je ne t'impose aucunement l'usage de cette fonction en particulier.
Si tu préfères mettre le code in-line selon que tu cherches un objet visible ou pas, tu peux reprendre des bouts de code de la fonction ou inventer ton propre code, personnellement ça m'est égal et je ne te ferai ici aucun commentaire sur ta façon de faire.
 

Dudu2

XLDnaute Barbatruc
comme tu peux le constater ca ne fonctionne pas
A toi de désigner l'objet cliqué.
  • Si le clic le sélectionne, une Shape ou une image par exemple ça fonctionne très bien.
  • Si le clic ne le sélectionne pas, un bouton par exemple, c'est à toi de trouver l'objet concerné.
    C'est quand même pas à la fonction de faire ce boulot !
PANE.gif
 

patricktoulon

XLDnaute Barbatruc
La fonction ne donne pas le Pane de l'objet cliqué mais le Pane de l'objet désigné.
Si tu veux qu'elle donne le Pane de l'objet cliqué tu l'appelles comme ça:
Set Pan = ObjectPane(Selection)

Ou encore si tu sélectionnes un objet et que tu scrolles pour qu'il disparaisse de l'écran et que tu veux quand même son Pane tu l'appelles comme ça:
Set Pan = ObjectPane(Selection, Visible:=False)

Edit:
Le paramètre Visible est commenté, c'est simple:
VB:
'----------------------------------------------------
'Pane de l'objet dont le parent est la feuille active
'- Visible = True, l'objet doit être visible
'- Visible = False, l'objet peut être visible ou non
'----------------------------------------------------
Function ObjectPane(Obj As Object, Optional Visible As Boolean = True) As Pane

1°La fonction ne donne pas le Pane de l'objet cliqué mais le Pane de l'objet désigné.
allons dudu2 c'est justement ça le problème que visiblement tu ne comprends pas malgré mes démos animées plus que parlantes
une shape ou un activx ou ce que tu veux n'a pas de panne !!! ou tout du moins elle peut se retrouver sur plusieurs (comme dans mes démos animées

et je ne détaille pas le reste (a propos des visible ou pas) car tout est faux dans ton raisonnement
c'est incroyable que tu ne comprenne pas cela
regarde une shapes peut être dans toutes les panes
demo.gif


si tu comprends pas là je sais plus moi
parti de là comment veux tu avec ta fonction déterminer sur quelle copie de la shape dudu2 dans chaque pane a tu cliqué
coquin de sort fait le test toi même avec ton module
 

Discussions similaires

Réponses
2
Affichages
466