Le problème de la précédente version était que l'on ne pouvait pas saisir ou sélectionner dans un contrôle transparent. C'est je crois résolu dans cette version.
Vous pouvez ...
- créer des contrôles réagissant différemment et indépendamment à l'opacification
- bouger ceux-ci dans ou en dehors de la Form
- et bien entendu saisir ou sélectionner ...
J'avais espéré pouvoir utiliser le CreateWindowEx pour créer des windows qui encapsuleraient certains contrôles. J'ai réussi à créer dynamiquement ces forms mais elles conservaient leur barre de titre. Aussi ais-je abandonné et suis-je passé à la création de windows par duplication d'une window modèle pré établie (Form2 dans le programme)
remarque : Les contrôles Listbox et Text1 sont regroupés dans un frame. Pour les faire bouger cliquez entre ces deux contrôles
Source / Exemple :
CONTENU de MODULE 1 :
Option Explicit
'POSTULAT : Tout contrôle possédant la propriété "Hwnd" doit être considéré comme une sorte de WINDOW
'Permet à une Window de devenir plus ou moins transparente
Public Declare Function SetLayeredWindowAttributes Lib "user32.dll" (ByVal hwnd As Long, ByVal crKey As Long, ByVal bAlpha As Byte, ByVal dwFlags As Long) As Long
'Rentre une valeur particulière dans une Window
Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
'Récupère une valeur particulière d'une Window
Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
'Calcule les coordonnées d'un contrôle ou form dans le Screen (établi en pixels - ne prend pas en compte la barre de titre d'une form si celle-ci existe)
Public Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, lpRect As Rect) As Long
'Offre un nouveau parent à une window (contrôle y compris - ne pas oublier la notion de Hwnd)
Public Declare Function SetParent Lib "user32" (ByVal hWndChild As Long, ByVal hWndNewParent As Long) As Long
'Indique quelle est la window qui a adoptée une window (fille - hors MDI)
Public Declare Function GetParent Lib "user32" (ByVal hwnd As Long) As Long
'Repositionne une window en indiquant entre autre comment elle doit se comporter via hwndInsertAfter entre autre )
Public Declare Function SetWindowPos Lib "user32" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal X As Long, ByVal Y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
'constante dwStyle
Public Const WS_CHILD = &H40000000 'La fenêtre est une fille
'transparence d'une form, contrôle ...
Public Const GWL_STYLE = (-16)
Public Const GWL_EXSTYLE = (-20)
Public Const LWA_COLORKEY = &H1
Public Const LWA_ALPHA = &H2
Public Const WS_EX_LAYERED = &H80000
Public Const SWP_FRAMECHANGED = &H20
Public Type Rect 'Réceptacle de coordonnées Screen
Left As Long
Top As Long
right As Long
Bottom As Long
End Type
Public Type Encapsuleur 'Réceptacle d'une Window "encapsulant" un contrôle
NumForm As Long 'La position de celle-ci dans la hiérarchie FORMS (par défaut, dans le programme Form1 est en position 0)
LeftOrigine As Long 'Coordonnée "Origine" pour permettre de repositionner dans Form1 un contrôle suite à un désencapsulage
TopOrigine As Long ' " "
widthOrigine As Long ' " "
heightOrigine As Long ' " "
hwnd As Long ' Numéro de la Window "Encapsuleur"
NameControlAsservi As String 'NAME du contrôle encapsulé
HwndControlAsservi As Long 'Numéro de window du contrôle encapsulé
End Type
Public NomWndRect As Rect
Public FrmRect As Rect
Public PictRect As Rect
Public TheEncapsule(2) As Encapsuleur 'Tableau de windows "Encapsuleur" (Dans le prog on en utilise 3)
Public CompteurForm As Long 'sert à attribuer un N° ordre initial aux windows "Encapsuleur" dans la hiérarchie "FORMS"
Public Compteur As Integer
Sub Main()
CompteurForm = 0 'Initialisation du compteur de création de forms "Encapsuleur"
'Présentation de l'écran principal"
Form1.Show
Form1.Caption = "Fenêtre primaire"
'Afin de pouvoir rendre plus ou moins transparent certains contrôles de FORM1, et éventuellement de pouvoir les sortir de celle-ci,
'on va créer une window "encapsuleut" qui servira de réceptacle à chacun d'eux
'Remarque : si on veut créer un groupe de contrôles (dans leur fonctionnement) il est souhaitable de les mettre dans un "FRAME" et d'encapsuler
' ce dernier - Dans le programme, List1 (ListBox) et Text1 (TextBox) sont regroupés dans Frame1 (Il existe, mais son Appearance = 0
' et son Borderstyle = 0)
TheEncapsule(0) = EncapsulerControl(Form1.Text2, Form1) 'Text2 est encapsulé - TheEncapsule(0) récupère les valeurs concernant cette opération
TheEncapsule(1) = EncapsulerControl(Form1.Combo1, Form1) 'Combo1 est encapsulé ...
TheEncapsule(2) = EncapsulerControl(Form1.Frame1, Form1) 'Frame1 est encapsulé ...
'Détails des opérations dans la fonction "EncapsulerControl ..."
'Ici on voit une autre manière de rendre un contrôle plus ou moins transparent. Il semble ne convenir qu'à tout contrôle ne nécessitant pas un "KEY INPUT/OUTPUT"
'En effet utilisé avec un ListBox, par exemple, il sera possible de mouvoir le scrollbar mais pas de sélectionner un item ...
'Dans le prog il est utilisé avec la picture LDX. Imaginez qu'à la place vous ayez un bouton ...
Call SetParent(Form1.Picture1.hwnd, GetParent(Form1.hwnd))
Call GetWindowRect(Form1.hwnd, FrmRect) 'Position de Form1 dans l'écran (coordonnées en Pixels)
Call GetWindowRect(Form1.Picture1.hwnd, PictRect) 'Position de Picture1 dans ...
Call SetWindowPos(Form1.Picture1.hwnd, -1, FrmRect.Left + (Form1.Picture1.Left / 15), FrmRect.Top + PictRect.Top + 30, (Form1.Picture1.Width / 15), (Form1.Picture1.Height / 15), SWP_FRAMECHANGED)
'REMARQUE : 30 pixels sont rajoutés au "Top" prendre en compte la barre de titre qui ne l'est pas dans les coordonnées RECT de Form1
' Vous pouvez remarquer également que dans la barre de tâche du bureau une nouvelle fenêtre sans titre a été créée.
End Sub
Public Function WndSetOpacity(ByVal hwnd As Long, Optional ByVal crKey As Long = vbBlack, Optional ByVal Alpha As Byte = 255, Optional ByVal ByAlpha As Boolean = True) As Boolean
'(de Greengold)
'Return : True si il n'y a pas eu d'erreur.
'hWnd : hWnd de la fenêtre à rendre transparente
'crKey : Couleur à rendre transparente si ByAlpha=False (utiliser soit les constantes vb:vbWhite ou en hexa:&HFFFFFF)
'Alpha : 0-255 0=transparent 255=Opaque si ByAlpha=true (défaut)
Dim ExStyle As Long
ExStyle = GetWindowLong(hwnd, GWL_EXSTYLE)
If ExStyle <> (ExStyle Or WS_EX_LAYERED) Then
ExStyle = (ExStyle Or WS_EX_LAYERED)
Call SetWindowLong(hwnd, GWL_EXSTYLE, ExStyle)
End If
WndSetOpacity = (SetLayeredWindowAttributes(hwnd, crKey, Alpha, IIf(ByAlpha, LWA_ALPHA, LWA_COLORKEY)) <> 0)
End Function
Public Function EncapsulerControl(ControlAEncapsuler As Object, FormPrincipal As Form) As Encapsuleur
Dim NomWnd As ModeleForm 'ModeleForm est une form qui va servir de modèle aux forms "Encapsuleur"
'S'il est possible de créer une form via "CreateWindowEx" il ne semble toutefois pa possible
'd'en supprimer la barre de titre. Pour cette raison, j'ai préféré revenir à une forme plus traditionnelle.
With EncapsulerControl
.NumForm = CompteurForm + 1 'Incrémentons le compteur de Form
.LeftOrigine = ControlAEncapsuler.Left 'Sauvons les coordonnées "origine" du contrôle à encapsuler
.TopOrigine = ControlAEncapsuler.Top
.widthOrigine = ControlAEncapsuler.Width
.heightOrigine = ControlAEncapsuler.Height
.HwndControlAsservi = ControlAEncapsuler.hwnd 'Reprenons le NAME du contrôle, cela peut servir en cas de vérif (non utilisé dans ce prog)
.NameControlAsservi = ControlAEncapsuler.Name 'reprenons le Hwnd ...
End With
Set NomWnd = New ModeleForm 'Créons une forme "Encapsuleur" par duplication du modèle
With NomWnd
.Visible = True
.Width = ControlAEncapsuler.Width 'Adaptons les coordonnées de ce nouveau Form à la taille du contrôle
.Height = ControlAEncapsuler.Height
End With
Call GetWindowRect(ControlAEncapsuler.hwnd, NomWndRect) 'Reprenons les coordonnées SCREEN du contrôle à encapsuler
'Positionnons le form "Encapsuleur" en lieu et place du contrôle ...
Call SetWindowPos(NomWnd.hwnd, -1, (NomWndRect.Left), (NomWndRect.Top), (NomWnd.Width / 15), (NomWnd.Height / 15), SWP_FRAMECHANGED)
'Le Form "Encapsuleur" ADOPTE le contrôle à ...
Call SetParent(ControlAEncapsuler.hwnd, NomWnd.hwnd)
'Indiquons que celui-ci (qui est une sorte de window) devient sa fille. Elle devient donc dépendante du nouveau Form
Call SetWindowLong(ControlAEncapsuler.hwnd, GWL_STYLE, WS_CHILD)
'Positionnons le contrôle dans sa nouvelle window
ControlAEncapsuler.Move 0, 0
ControlAEncapsuler.Visible = True
'Incrémentons d'une unité le compteur de forme. Cela nous servira lors du désencapsulage
CompteurForm = CompteurForm + 1
'Retournons les éléments (de type Encapsuleur) à "TheEncapsule" qui l'a demandé
EncapsulerControl.hwnd = NomWnd.hwnd
End Function
Public Sub LibereMemoire(NumID As Long, DonneesControl() As Encapsuleur, ControlADesencapsuler As Object, ARemettreDansForm As Form, LiaisonFormASupprimer As Form)
'Il peut être intéressant parfois d'encapsuler temporairement un contrôle (exemple : lors de la saisie d'une fiche)
'Il faut donc lors de la validation de celle-ci, désencapsuler, puis refaire une opération d'encapsulage si nécessaire ...
Dim Compteur As Integer
'Commençons à rendre à Form1 le contrôle à désencapsuler
Call SetParent(ControlADesencapsuler.hwnd, ARemettreDansForm.hwnd)
'Supprimons le window "encapsuleur" qui n'est plus nécessaire
Unload Forms(DonneesControl(NumID).NumForm)
'En remettons son NumForm à 0 indiquons que TheEncapsule(NumId) correspondant n'est plus "actif"
DonneesControl(NumID).NumForm = 0
'Rétablissons dans Form1, le contrôle désencapsulé à sa position d'origine
ControlADesencapsuler.Move DonneesControl(NumID).LeftOrigine, DonneesControl(NumID).TopOrigine
'Puisque l'on a supprimé une window "Encapsuleur", les restantes descendent d'une unité dans la hiérarchie FORMS(x)
'Remarque : Dans le prog on part de TheEncapsule(0) vers ...(2). On aurait pu commencer par l'inverse, d'où autre instruction ... (non mise)
For Compteur = 0 To 2
If DonneesControl(Compteur).NumForm > 0 Then DonneesControl(Compteur).NumForm = DonneesControl(Compteur).NumForm - 1
Next
End Sub
CONTENU de FORM1 :
Option Explicit
Public XDepart, YDepart As Single '=> Positions Départ de la souris (ATTENTION : SCREEN pour les FORMS, WINDOW pour les contrôles)
Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
WndSetOpacity Picture1.hwnd, 0, Val(Text4.Text) 'Là on rend transparent Picture1
End Sub
Private Sub Form_Unload(Cancel As Integer)
Call SetParent(Picture1.hwnd, Form1.hwnd) 'N'oublions pas la picture. Elle n'est pas dans le proc "LibereMemoire"
End 'Fin de programme, on décharge la mémoire de tous les composants résiduels
End Sub
Private Sub Frame1_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button = vbLeftButton Then 'Bouton souris enfoncé
If XDepart = 0 Then XDepart = X 'la première fois que l'on passe dans cette proc il faut aue XDepart prenne une "position départ" exacte
'Les passages suivants modifieront uniquement la valeur de X
'Quand on relachera le bouton souris, il sera possible de calculer la valeur de déplacement dans l'axe X
'par soustraction entre X et XDépart
If YDepart = 0 Then YDepart = Y ' idem
Forms(TheEncapsule(2).NumForm).Left = Forms(TheEncapsule(2).NumForm).Left + (X - XDepart)
Forms(TheEncapsule(2).NumForm).Top = Forms(TheEncapsule(2).NumForm).Top + (Y - YDepart)
'Repositionnons la Window "Encapsuleur" à sa nouvelle position
Call SetWindowPos(Forms(TheEncapsule(2).NumForm).hwnd, -1, (Forms(TheEncapsule(2).NumForm).Left / 15), (Forms(TheEncapsule(2).NumForm).Top / 15), (Frame1.Width / 15), (Frame1.Height / 15), SWP_FRAMECHANGED)
'Frame1.Move 0, 0 Comme la Window "Encapsuleur" a pour coordonnées celles du Frame, il n'est pas nécessaire ici de repositionner ce dernier
Else
XDepart = 0 'On n'appuie pas sur le bouton de la souris, remettons la valeur départ à 0
YDepart = 0
End If
End Sub
Private Sub Picture1_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim PictRect As Rect
If Button = vbLeftButton Then 'Bouton souris enfoncé, on veut seulement déplacer le TextBox
'Coordonnées souris dans le SCREEN pas dans Form1
If XDepart = 0 Then XDepart = X
If YDepart = 0 Then YDepart = Y
'A l'inverse de Frame1 qui est encapsulé, picture1 ne l'est pas. Il est donc nécessaire de le bouger
Picture1.Move (Picture1.Left + X) - XDepart, (Picture1.Top + Y) - YDepart
Call SetWindowPos(Picture1.hwnd, -1, (Picture1.Left / 15), (Picture1.Top / 15), (Picture1.Width / 15), (Picture1.Height / 15), SWP_FRAMECHANGED)
Else
XDepart = 0
YDepart = 0
End If
Call Module1.WndSetOpacity(Picture1.hwnd, 0, 255) 'Ca, c'est uniquement pour montrer que l'on peut changer la transparence ...
End Sub
Private Sub List1_Click()
Text1.Text = List1.List(List1.ListIndex) 'reprend la valeur sélectionnée dans List1
Text3.Text = List1.List(List1.ListIndex) 'Idem ici sauf que Text3 n'est pas encapsulé. Tout cela pour montré qu'une valeur saisie, sélectionnée
' dans un environnement "Encapsulé" peut toujours communiquer avec ceux qui ne le sont pas
End Sub
Public Sub BtTranspOpaque_Click()
'Change l'opacité des éléments encapsulés en fonction de la valeur saisie dans Text4
Call Module1.WndSetOpacity(TheEncapsule(0).hwnd, 0, Val(Text4.Text))
Call Module1.WndSetOpacity(TheEncapsule(1).hwnd, 0, Val(Text4.Text))
Call Module1.WndSetOpacity(TheEncapsule(2).hwnd, 0, Val(Text4.Text))
End Sub
Private Sub Command1_Click()
'Désencapsuler ...
'Ici les 3 cas ont été pris. Il est évident que l'on peut n'en choisir qu'un seul ou deux ...
Module1.LibereMemoire 0, TheEncapsule, Form1.Text2, Form1, ModeleForm
Module1.LibereMemoire 1, TheEncapsule, Form1.Combo1, Form1, ModeleForm
Module1.LibereMemoire 2, TheEncapsule, Form1.Frame1, Form1, ModeleForm
'Remarque : un élément désencapsulé ne répond plus à l'opacification. Il faut l'encapsuler de nouveau pour ...
End Sub
Conclusion :
voilà ! j'espère avoir apporté ma pierre. Vu le nombre de personnes qui sont venus, en quelques jours, voir la première version, j'imagine que c'est un sujet qui en intéresse pas mal
Portez vous bien
Vous n'êtes pas encore membre ?
inscrivez-vous, c'est gratuit et ça prend moins d'une minute !
Les membres obtiennent plus de réponses que les utilisateurs anonymes.
Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.
Le fait d'être membre vous permet d'avoir des options supplémentaires.