Table des matières








télécharger 42.36 Kb.
titreTable des matières
date de publication09.10.2017
taille42.36 Kb.
typeDocumentos
l.21-bal.com > droit > Documentos




Utilisez l'effet Glass de Vista dans vos applications WinForm







Florian Casabianca

29/04/2007



Remerciements

J'adresse ici tous mes remerciements à l'équipe de rédaction de "developpez.com" pour le temps qu'ils ont bien voulu passer à la correction et à l'amélioration de cet article.






Table des matières




Table des matières 2

Introduction 3

Desktop Window Manager 3

Avant de commencer 4

L'API de DWM 4

Vérifier l'activation de la composition 5

Et la transparence fut. 7

Première technique 7

Deuxième technique 10

Dessiner sur la transparence 13

Conclusion 15

Liens 15


Introduction


Comme vous le savez probablement tous, Windows Vista introduit avec lui un nouveau thème: Aero. Un des aspects les plus connus de ce thème est le fait que la barre de titre et les contours des fenêtres sont transparents et laissent apparaître l'arrière des fenêtres légèrement flouté.

Toutes les fenêtres des applications écrites avant ou pour Windows Vista tirerons automatiquement parti de ces nouveautés sans que le développeur n'ait besoin d'y retoucher. Cependant vous avez peut-être remarqué que certaines applications étendent cet effet de transparence à toute la zone client et non pas seulement à la barre de titre et aux contours. C'est notamment le cas du lecteur Windows Media Player dont voici une image en mode réduit:



Pas mal, non ? Et bien sachez qu'il vous est possible d'utiliser l'API qui se cache derrière tout ça pour que vous puissiez vous aussi étendre la transparence à toute la zone cliente de vos applications WinForm. C'est ce que nous allons voir au travers de cet article.

Desktop Window Manager


Le Desktop Window Manager (DWM) est la nouvelle interface qui contrôle l’affichage et le rafraichissement des fenêtres en cours d'exécution sur le bureau Windows Vista. Le DWM contrôle la manière dont les fenêtres interagissent avec le moteur de composition de bureau. C'est grâce à lui que vous avez des fonctionnalités comme la transparence, le flip 3D, les miniatures des applications lancées, etc. Pour plus d'informations sur DWM, je vous invite à suivre les différents liens présents à la fin de cet article.

Toutes les applications que vous avez déjà programmées tirent profit du DWM sans avoir à subir de modification (comme la transparence des rebords des fenêtres). Toutefois, si vous souhaitez contrôler ou accéder aux fonctionnalités de DWM, vous devrez appeler les interfaces se trouvant dans dwmapi.dll (l'interface publique de DWM). C'est précisément ce que nous allons devoir faire pour étendre l'effet de transparence à la zone cliente d'une fenêtre.

Avant de commencer


Pour pouvoir utiliser l'effet de transparence, votre programme devra vérifier certaine conditions concernant son environnement.

Il faudra tout d'abord vérifier que l'application s'exécute bien sous Windows Vista. En effet, vouloir utiliser l'API de DWM sous Windows XP par exemple risque de vous poser quelques problèmes…

Vous pouvez donc par exemple insérer ce bout de code dans la fonction main de votre programme :

Ainsi, l'application se fermera si elle ne se trouve pas sous Vista. Cela peut être ennuyeux si vous souhaitez tout de même la faire tourner sous Windows XP par exemple. Pour contourner ce problème vous pouvez par exemple faire la vérification de la version de l'OS non pas dans la fonction main mais aux endroits où vous vous servez de l'API de DWM. Vous activerez ainsi la transparence si vous êtes sous Vista et pas dans les autres cas.

Un autre point à vérifier et l'activation ou non d'Aero. En effet, un utilisateur sous Windows Vista peut ne pas l'avoir activé (ou sa configuration matérielle ne lui permet pas de le faire). Cette vérification peut se faire en appelant la fonction DwmIsCompositionEnabled de l'API de DWM qui permet obtenir l'état de composition DWM du bureau. Nous verrons plus loin comment utiliser cette fonction.

L'API de DWM


C'est maintenant que les problèmes commencent. Nous voulons en effet utiliser la dll dwmapi.dll dans notre programme C#. Or cette dll n'a pas été écrite en .NET, elle est en code dit non géré (ou non managé). Pour pallier ce problème, on utilise le mécanisme de : P/Invoke (Platform Invoke). Le site MSDN nous donne une rapide définition de ce mécanisme: P/Invoke est l'abréviation de Platform Invoke et offre les fonctionnalités permettant d'accéder aux fonctions, structures et rappels dans les DLL non gérées. P/Invoke offre une couche de traduction permettant d'aider les développeurs en les autorisant à étendre la bibliothèque des fonctionnalités disponibles, au-delà de la bibliothèque gérée de la BCL (Base Class Library) du .NET Framework.

Pour plus d'informations sur ce mécanisme, je vous invite à aller consulter cet article (http://morpheus.developpez.com/dlldotnet/) de Thomas Lebrun ou encore celui-ci (http://www.microsoft.com/france/msdn/vcsharp/Utilisez-Pinvoke.mspx ) sur le site MSDN.

Vous y avez jetez un œil ? Parfait, nous allons pouvoir continuer. Vous avez donc compris que nous allions devoir créer des wrappers pour les fonctions et structures requises par le DWM afin que nous puissions les appeler à partir de notre programme C#. Une description de l'API de DWM est disponible sur MSDN à cette adresse: http://msdn2.microsoft.com/en-us/library/aa969540.aspx.

Vérifier l'activation de la composition


La première chose est donc de vérifier l'activation de la composition sous Vista en utilisant la fonction DwmIsCompositionEnabled dont voici la signature non gérée :



Nous déclarons le wrapper de la fonction P/Invoke gérée de la façon suivante :

Si vous voulez en savoir plus sur le tag PreserveSig, allez jetez un coup d'œil sur cette page MSDN. Sinon, sachez simplement qu'il permet de transformer la valeur de retour HRESULT directement en exception si besoin.

Ce wrapper n'est que le premier d'un longue liste. Pour une meilleur lisibilité vous devriez donc les déclarer dans une classe à part. Vous pouvez vous inspirer des sources données en exemple. A l'intérieur se trouve la classe WrappersDWM qui référence tous les wrappers déclarés.

N'oubliez pas de référencer l'espace de noms System.Runtime.InteropServices en utilisant la directive suivante:

Une fois cela terminée, vous serez en mesure d'appeler la fonction DwmIsCompositionEnabled comme s'il s'agissait d'une fonction managée.

Voici un exemple de code que vous pouvez utiliser pour traiter le cas ou la composition est active et le cas où elle ne l'est pas:

Nous sommes maintenant capables de savoir si la composition est activée ou non. Mais il reste un petit problème. En effet, l'utilisateur peut à tout moment désactiver Aero. Votre application doit être capable de réagir immédiatement (si besoin) à cette modification. Heureusement, lorsque l'état de composition du bureau est modifié, un message système WM_DWMCOMPOSITIONCHANGED est diffusé. Nous pouvons donc le récupérer et effectuer les traitements nécessaires si besoin. Par contre ce message ne nous informe pas sur l'état (activé ou non) de la composition. Vous devrez refaire un appel à la méthode DwmIsCompositionEnabled pour le déterminer.

Pour récupérer les messages Windows nous devons redéfinir la méthode WndProc. Cette technique n'est pas propre à Vista, elle existe depuis la version 1.0 du FrameWork. Si vous souhaitez plus d'informations sur le sujet rendez-vous à l'adresse suivante: http://msdn2.microsoft.com/fr-fr/library/system.windows.forms.control.wndproc(vs.80).aspx.

Voici à quoi pourrait ressembler le code de cette fonction:

Il existe d'autres messages système liés à DWM qu'il peut être intéressant d'écouter mais que nous ne détaillerons pas ici:

WM_DWMCOLORIZATIONCOLORCHANGED est envoyé lorsque la couleur ou l'opacité de l'effet de verre est modifié. Les paramètres vous informent de la nouvelle couleur et de la nouvelle opacité.
WM_DWMNCRENDERINGCHANGED est envoyé lorsque le rendu DWM change sur la zone non client.

WM_DWMWINDOWMAXIMIZEDCHANGE est envoyé lorsqu'une fenêtre compositée DWM est agrandie ou minimisée. Par exemple, la barre des tâches réagit à cet évènement en devenant opaque.

Et la transparence fut.


Nous pouvons maintenant entrer dans le vif du sujet. Pour rendre transparente une fenêtre il existe deux techniques. La première, la plus facile, utilise la fonction DwmExtendFrameIntoClientArea et permet d'étendre les bordures transparentes de la fenêtre à toute ou une partie de la zone client. La deuxième technique, un peu plus complexe mais qui permet plus de souplesse, utilise la fonction DwmEnableBlurBehindWindow et permet d'afficher une zone transparente de n'importe quelle forme à l'intérieur de la zone cliente de la fenêtre.

Première technique


Nous allons ici utiliser la fonction DwmExtendFrameIntoClientArea dont voici la signature non gérée:

Et le wrapper associé:

Cette fonction prend en paramètre le handle de la fenêtre dont les bords doivent être étendus ainsi qu'une structure MARGINS qui décrit comment les quatre marges de la fenêtre doivent être étendues.

Voici la version non gérée de cette structure:

Et sa version gérée:

La première chose à faire est donc de construire un objet MARGINS qui permet d'indiquer pour chaque marge la distance (en pixel) à laquelle elle doit s'étendre à l'intérieur de la zone cliente. Une valeur de -1 indique que la marge doit s'étendre sur toute la zone cliente. Pour annuler l'extention de la marge il suffit de redéfinir un objet MARGINS avec des valeurs à 0.

Il faut ensuite d'appeler la méthode DwmExtendFrameIntoClientArea en lui passant le handle de la fenêtre et l'objet MARGINS.

Voici un exemple de code afin d'étendre la marge gauche à toute la zone cliente (c'est-à-dire étendre la transparence à toute la fenêtre):

Notez l'appel à la méthode Invalidate qui permet de repeindre la fenêtre. En effet, la dernière chose à faire est de peindre les zones que l'on souhaite voir transparente avec un brush noir. Pour cela on redéfinit la méthode OnPaint de la fenêtre.

Le code ci-dessous permet de peindre l'ensemble de la zone cliente en noir:

Tout cela nous permet d'obtenir le résultat suivant:



Prenons un deuxième exemple où l'on ne souhaite rendre transparent qu'un bandeau de 100 pixels de hauteur en haut de la fenêtre.

Il nous faut construire l'objet MARGINS de cette façon:

Puis modifier la fonction OnPaint pour ne peindre en noir que ce bandeau:

Cela nous permet d'obtenir le résultat ci-dessous:


Deuxième technique


La plupart des personnes qui souhaitent ajouter de la transparence à leur fenêtre vont probablement se satisfaire de la première méthode. Il existe néanmoins une autre méthode permettant d'avoir plus de contrôle sur la façon dont l'effet de transparence est construit. Il ne s'agit pas ici d'utiliser les bordures de la fenêtre pour les étendre mais d'indiquer une région de la fenêtre (au sens GDI) à rendre floue.

Nous allons utiliser ici la fonction DwmEnableBlurBehindWindow dont voici la signature non gérée:

Et son wrapper:

Cette fonction ressemble à la fonction DwmExtendFrameIntoClientArea sauf que la structure à passer en paramètre est différente. En voici d'ailleurs la signature en code non managé:

Et son équivalent en code managé:

Nous allons voir un peu plus loin à quoi vont servir les constantes déclarées.

Voici un descriptif des différents champs:

fEnable: booléen à mettre à vrai si l'on veut appliquer la transparence.

hRegionBlur: représente la région à rendre floue.

fTransitionOnMaximized: indique si l'effet de transparence doit devenir opaque quand une fenêtre (n'importe laquelle) du bureau est maximisée. Pour mieux comprendre, pensez à la barre des tâches de Vista: en temps normal elle est transparente; mais si on maximise une fenêtre elle devient opaque.

dwFlags: ce champ est une combinaison de constantes permettant de d'indiquer quels membres (parmi les trois précédents) ont été définis. Les constantes à utiliser sont celles déclarées dans le code de la structure DWM_BLURBEHIND plus haut. Ainsi, si l'on renseigne les trois champs ci-dessus, il faudra remplir ce membre de cette façon:

Pour construire une région on passe généralement par un objet GraphicsPath. N'oubliez pas d'importer l'espace de nom System.Drawing.Drawing2D.

Voici un exemple de code où l'on construire une région de forme ovale:

Pour illustrer cette technique nous allons construire une fenêtre un peu spéciale. Elle ne sera pas rectangulaire comme les fenêtres par défaut, mais ovale et sans bordure ni barre de titre. Bien sûr on lui appliquera l'effet de transparence.

Pour mémoire, définir une forme particulière à une fenêtre s'effectue en lui assignant une nouvelle valeur à sa propriété Region. Cette dernière est de type Region, le même que celui dont nous avons parlé juste au dessus.

Ainsi, rendre une fenêtre de forme elliptique se fera de cette manière:

Mettons maintenant tout ceci en pratique. Voici le code permettant de créer une fenêtre ovale et transparente:

Bien sûr il vous faut toujours peindre le fond de la fenêtre en noir dans la méthode OnPaint:



Au final nous obtenu le résultat ci-dessous:


Dessiner sur la transparence


Maintenant que votre fenêtre est transparente, vous voudriez sans doute la garnir et y ajouter du texte.

Vous allez malheureusement être confronté à quelques petits soucis:

Voici un label simple avec du texte en noir à l'intérieur.



Le même label mais avec le fond transparent. Pas génial.

Encore le même mais avec un fond noir (c'est la couleur qui détermine les zones transparentes). Ce n'est pas encore ça…

Une solution ici est de ne pas utiliser de label mais de peindre directement le texte que l'on souhaite afficher en utilisant les classes du GDI+. Par contre n'utilisez pas la méthode DrawString de la classe Graphics. Il faut passer par l'intermédiaire d'un objet GraphiquePath.

Voici un exemple de code que vous pouvez mettre dans méthode OnPaint:

Et le résultat obtenu:



Il faut utiliser la même technique pour les images (pictureBox déconseillée). Vous pouvez par contre ici simplement utiliser la fonction DrawImage de la classe Graphics.

Une simple ligne ajoutée à la méthode OnPaint suffit pour afficher une image qui se trouve en ressource:

Et le résultat obtenu:


Conclusion


Notre petit tour dans le monde de la transparence touche à sa fin. Nous avons vu les bases pour la création de fenêtres WinForm avec l'effet Aero Glass de Windows Vista. N'hésitez pas à consulter les différents sites Web référencés ci-dessous pour plus d'informations.

Liens


Windows Vista Display Driver Model
Desktop Window Manager

Créez des effets spéciaux avec le Gestionnaire de fenêtres du Bureau
Utilisation de P/Invoke pour appeler des API non gérées à partir de vos classes gérées
Les DLL natives en .NET
PreserveSig
API de DWM



similaire:

Table des matières iconTable des matières

Table des matières iconTable des matières

Table des matières iconTable des matières

Table des matières iconTable des matières

Table des matières iconTable des matières

Table des matières iconI. Table des matières

Table des matières iconTable des matières

Table des matières iconTable des matieres

Table des matières iconTable des matières

Table des matières iconTable des matieres








Tous droits réservés. Copyright © 2016
contacts
l.21-bal.com