IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Macros et VBA Excel Discussion :

[Windows API GDI] Dessiner un rectangle dans un userform


Sujet :

Macros et VBA Excel

  1. #1
    Membre éclairé
    Homme Profil pro
    Ingénieur aéronautique
    Inscrit en
    Octobre 2018
    Messages
    216
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur aéronautique

    Informations forums :
    Inscription : Octobre 2018
    Messages : 216
    Par défaut [Windows API GDI] Dessiner un rectangle dans un userform
    Bonjour,

    Je souhaite dessiner un rectangle sans remplissage dans un userform pour entourer des contrôles. Jadis, je m'en serais sorti avec plusieurs MSForms.Frame de faible hauteur.

    Ci-desous un exemple basique sensé juste dessiner trait oblique, sauf que ça n'affiche rien...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    Option Explicit
     
    '
    Private Sub UserForm_Initialize()
     
        Left = 0
        Top = 0
     
        Dim hwnd As LongPtr: hwnd = API.GetActiveWindow
     
        Dim hdc As LongPtr: hdc = API.GetDC(hwnd:=hwnd)
     
        Dim lppt(1 To 2) As API.POINTAPI 'dans cet exemple, je ne prend que 2 points (MoveToEx et LineTo seraient probablement plus adaptés)
     
        lppt(1).x = Left 'à vrai dire, j'ignore s'il faille effectuer la translation de l'origine, peut-être utilisé MoveToEx ?
        lppt(1).y = Top
     
        lppt(2).x = Left + Width
        lppt(2).y = Top + Height
     
        'converti les coordonnées logiques en pixels
        Dim ind As Integer: For ind = LBound(lppt) To UBound(lppt)
     
            'conversion en coordonnées pixel
            lppt(ind).x = API.GetDeviceCaps(hdc:=hdc, nIndex:=API.LOGPIXELSX) * lppt(ind).x / API.POINTSPERINCH
            lppt(ind).y = API.GetDeviceCaps(hdc:=hdc, nIndex:=API.LOGPIXELSY) * lppt(ind).y / API.POINTSPERINCH
     
        Next ind
     
        API.PolylineTo hdc:=hdc, lppt:=lppt(1), cCount:=UBound(lppt) - LBound(lppt) + 1
     
        'j'imagine qu'il n'y a pas de brush à spécifier, vu que je ne souhaite pas de remplissage
        'mais qu'en est-il de l'epaisseur du trait, du moins s'il y en a un ?
     
        API.ReleaseDC hwnd:=hwnd, hdc:=hdc
     
    End Sub
    Déclarations de l'API Windows:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    Option Explicit
     
    Public Declare PtrSafe Function GetActiveWindow Lib "user32" () As LongPtr
     
    Public Declare PtrSafe Function GetDC Lib "user32" (ByVal hwnd As LongPtr) As LongPtr
    Public Declare PtrSafe Function ReleaseDC Lib "user32" (ByVal hwnd As LongPtr, ByVal hdc As LongPtr) As Long
     
    Public Declare PtrSafe Function LineTo Lib "gdi32" (ByVal hdc As LongPtr, ByVal x As Long, ByVal y As Long) As Long
    Public Declare PtrSafe Function MoveToEx Lib "gdi32" (ByVal hdc As LongPtr, ByVal x As Long, ByVal y As Long, lpPoint As POINTAPI) As Long
    Public Declare PtrSafe Function PolylineTo Lib "gdi32" (ByVal hdc As LongPtr, lppt As POINTAPI, ByVal cCount As Long) As Long
     
    Public Declare PtrSafe Function GetDeviceCaps Lib "gdi32" (ByVal hdc As LongPtr, ByVal nIndex As Long) As Long
     
    Public Type POINTAPI
        x As Long
        y As Long
    End Type
     
    Public Const LOGPIXELSX                 As Long = &H58&
    Public Const LOGPIXELSY                 As Long = &H5A&
    Public Const POINTSPERINCH            As Long = &H48&
    A ce sujet, je suis entrain de lire le livre Programming Windows de Charles Petzold (1998) sur l'API Windows. J'ai rencontré de nombreux exemples où ça implique des coordonées logiques de ce que je me rappelle (bon autant dire, j'ai fait les exercices sans vraiment comprendre... ) De plus, je n'ai entrevu des exemple que ce servent des object Excel.Shape, mais celà ne me convient pas, car le formulaire est en réalité implémenté sous CATIA (même si je fais des appels vers Excel).

    Pouvez-vous s'il vous plaît m'aider à ce sujet ?

    Merci

  2. #2
    Expert confirmé
    Avatar de Arkham46
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    5 865
    Détails du profil
    Informations personnelles :
    Localisation : France, Loiret (Centre)

    Informations forums :
    Inscription : Septembre 2003
    Messages : 5 865
    Par défaut
    Bonjour,

    Que s'est il passé entre jadis et aujourd'hui ?
    Pourquoi vouloir dessiner avec gdi ?
    Pour dessiner sur un userform, il faut le dc non pas de la fenêtre principale, mais d'une sous fenêtre ; celle sur laquelle office y dessine ses contrôles.
    Vu le besoin, je ne comprends pas trop l'idée d'utiliser gdi.

  3. #3
    Membre éclairé
    Homme Profil pro
    Ingénieur aéronautique
    Inscrit en
    Octobre 2018
    Messages
    216
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur aéronautique

    Informations forums :
    Inscription : Octobre 2018
    Messages : 216
    Par défaut
    Merci pour toutes ces questions... A vrai dire, je me forme tout simplement. Pour l'instant, je commence avec les bases de GDI. Ensuite, je verrai avec GDI+, Direct2D et problament bien d'autres.

    Effectivement le handle que je récupère correspond à celui du ThunderDFrame. La zone graphique d'emplacement des contrôles est de classe F3 Server XXX. Bon, j'ai fait les modilfs pour pourvoir y récupérer son handle (j'ai encapsulé une bonne partie des appels de l'API dans des classes pour m'astreindre la gestion des handles), mais ça n'a pas résolu le problème (vu l'heure qu'il est... )

  4. #4
    Expert confirmé
    Avatar de Arkham46
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    5 865
    Détails du profil
    Informations personnelles :
    Localisation : France, Loiret (Centre)

    Informations forums :
    Inscription : Septembre 2003
    Messages : 5 865
    Par défaut
    Je fais des choses du genre dans clGdi32 :
    https://arkham46.developpez.com/arti...ffice/clgdi32/

    Le sujet n'est pas simple.

  5. #5
    Membre éclairé
    Homme Profil pro
    Ingénieur aéronautique
    Inscrit en
    Octobre 2018
    Messages
    216
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur aéronautique

    Informations forums :
    Inscription : Octobre 2018
    Messages : 216
    Par défaut
    Merci pour cet example de classe, je vais donc essayer de m'y inspirer .

    Pour infos, j'ai lu et pratiqué (c'est-à-dire recopié et adapté les exemples en C++) les 2 / 3 du livre Windows programming de Charles Petzold (5ème édition de 1998), mais j'avoue ne pas encore être en mesure de coder avec autonomie.. En tout cas, c'est sûr qu'il faille avoir une bonne dose de courage..

  6. #6
    Expert confirmé
    Avatar de Arkham46
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    5 865
    Détails du profil
    Informations personnelles :
    Localisation : France, Loiret (Centre)

    Informations forums :
    Inscription : Septembre 2003
    Messages : 5 865
    Par défaut
    Effectivement bon courage

    Ce qu'il faut bien comprendre, c'est qu'un userform c'est office qui le gère.
    Si on veut modifier son comportement standard, ce n'est pas aisé.
    C'est bien différent d'un dessin sur une fenêtre qu'on crée nous mêmes (ce qu'on voit souvent en exemple dans d'autres langages).

  7. #7
    Membre éclairé
    Homme Profil pro
    Ingénieur aéronautique
    Inscrit en
    Octobre 2018
    Messages
    216
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur aéronautique

    Informations forums :
    Inscription : Octobre 2018
    Messages : 216
    Par défaut
    En fait, je viens aussi de me commander un livre sur MFC, mais bon comme dirais-je j'aime bien d'abord m'attaquer à la base ...

    Qu'entendez-vous par Office gérant les Userforms ? Est-ce une conséquence des noms de classes "F3 Server ..." un peu comme "Afx:..." en MFC.

  8. #8
    Expert confirmé
    Avatar de Arkham46
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    5 865
    Détails du profil
    Informations personnelles :
    Localisation : France, Loiret (Centre)

    Informations forums :
    Inscription : Septembre 2003
    Messages : 5 865
    Par défaut
    Oui un userform est une fenêtre créée par office selon les propriétés qu'on a définie.
    On a des méthodes de bas niveau, du style "repaint", ou des propriétés comme "caption".
    Mais le reste est géré par office, on ne sait pas trop comment et si ça restera comme ça.
    On n'a pas accès aux événements de dessin (tout ce qu'on peut dessiner n'est donc pas persistant), et le sous classement en vba est risque de crash.

    Si c'est pour se former à gdi, ce n'est pas le plus simple d'essayer de dessiner sur la fenêtre de quelqu'un d'autre.

  9. #9
    Membre éclairé
    Homme Profil pro
    Ingénieur aéronautique
    Inscrit en
    Octobre 2018
    Messages
    216
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur aéronautique

    Informations forums :
    Inscription : Octobre 2018
    Messages : 216
    Par défaut
    Aie.. à vrai dire je me sers déjà de l'API Windows pour rajouter un icône et les bouttons réduire / maximiser dans la barre de titre, mettre de la transparence, changer la couleur de fond des multipages, rajouter du scroll, gérer les boites d'accès aux fichiers, menu flottant et piloter une application externe (via UI Automation en partie aussi). J'ai aussi en tête de voir ce que ça donne avec les listview (même si j'ai appris il n'y a pas longtemps qu'il y existe quand même une version Microsoft Windows Common Controls 6.0 en 64 bits). J'imagine que l'on pourrait pallier le problème en passant par des RegisterClass et CreateWindow et tout l'artirail qui va avec, mais c'est sûrement pas le top

    Par contre, j'ai qu'une vague notion de ce qu'est le sous-classement.

    Ps : je développe principalement le script pour CATIA V5 (logiciel de CAO), mais je le rend aussi compatible sous Excel avec des fonctions dégradées.

  10. #10
    Expert confirmé
    Avatar de Arkham46
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    5 865
    Détails du profil
    Informations personnelles :
    Localisation : France, Loiret (Centre)

    Informations forums :
    Inscription : Septembre 2003
    Messages : 5 865
    Par défaut
    Les listview j'en ai mis dans des inputbox. Le sous classement (en gros on redirige les messages de la fenêtre vers une fonction personnalisée) est stable ici car dans un appel modal.
    On ne peut pas faire tout ce qu'on veut, et on peut faire plein de choses instables.
    Et rien n'est garanti quand on modifie le comportement d'une application qui évolue sans nous prévenir.
    Par exemple on touve du code pour retirer la croix de fermeture de l'application. Pas de bol sur certaines versions récentes ça ne fonctionne pas.
    Pour les userForms il y a très peu de changements depuis plusieurs années, on est plus sereins.

    Pour en revenir au problème initial, le dessin dans l'événement initialize ne me semble pas au bon endroit.
    C'est justement ce que j'essaye d'expliquer un peu difficilement, le userform vit sa vie sans nous : après cet événement il se passe plein de chose et tout ce qu'on y dessine est écrasé.
    De toute façon même si on arrive à dessiner sur le formulaire, ce serait temporaire.
    Windows envoit un message dès que la fenêtre doit être redessinée, et ce message ne nous est pas destiné. On peut le capturer (c'est le sous classement) mais c'est plutôt instable en vba.

    Vba est très bien pour interagir avec son application hôte.
    Mais j'ai l'impression que le besoin d'origine est plutôt de la curiosité.
    Pour apprendre l'api windows je passerais à un autre langage.
    J'ai appris beaucoup en delphi (aujourd'hui vb.net a une version gratuite et proche de vba) avant de revenir à vba.

  11. #11
    Membre éclairé
    Homme Profil pro
    Ingénieur aéronautique
    Inscrit en
    Octobre 2018
    Messages
    216
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur aéronautique

    Informations forums :
    Inscription : Octobre 2018
    Messages : 216
    Par défaut
    Merci encore pour ces précisions, tout commence à s'expliquer . A vrai dire, je vise davantage le C++ (j'ai d'ailleurs commandé un livre sur MFC), même si je devrais normalement être amené à travailler en C# l'année prochaine.

    J'avais aussi remarqué que dans l'extrait de code, si je déplace Caption après End With, je perdais finalement les bouttons minimize et maximize que je rajoute dans la méthode addBoxes (enfin, c'est ce qu'il me semble...).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    '
    Private Sub UserForm_initialize()
     
    #If DEBUGMODE Then
        Caption = "Macro Management - DEBUG MODE"
    #End If
     
        With windows.findBy(form:=Me) 'encapsule les appels à Win32 pour ne pas avoir à "trimballer" les handles
     
            .center
            .setIcon fileName:=PATH_SCRIPT_RESOURCE & "icon.ico"
            .addBoxes minimize:=True, maximize:=True
            .addTransparency
     
        End With
     
    '...
     
    End Sub
    J'avais effectivement rencontré un message sur un autre forum (que je ne retrouve plus) où il était question de passer outre le fait que l'on perdait dans la méthode Class_Initialize

Discussions similaires

  1. Réponses: 2
    Dernier message: 26/06/2019, 16h03
  2. Réponses: 0
    Dernier message: 24/12/2012, 21h32
  3. Réponses: 0
    Dernier message: 21/12/2012, 22h50
  4. Dessiner un rectangle dans la console
    Par Akastras dans le forum Langage
    Réponses: 2
    Dernier message: 02/12/2010, 15h55
  5. [MFC]dessiner un rectangle dans ma fenetre
    Par jiraya43 dans le forum MFC
    Réponses: 13
    Dernier message: 15/05/2006, 13h57

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo