| ♣_______ Page mise à jour le 23 février 2022 vers 19h30 TUC |
Le mode Sombre-plat
Ironie de l'Histoire : aux débuts de VisualBasic, le (pseudo-)relief de VB et le texte noir sur fond blanc de Windows se voulaient le comble de la modernité face au flat design de QuickBasic (avec, par exemple, des boutons au contour formé d'un simple trait) couplé au dark theme (texte clair sur fond noir) de la console MS-DOS. Deux décennies plus tard, la girouette a tourné… et il n'est pas simple de donner aux programmes écrits en VB6 (à son tour présenté comme obsolète) l'aspect sombre-plat aujourd'hui à la mode. Le code ci-dessous essaie de répondre à cet éventuel besoin.
Sommaire
I- Les problèmes
Ⓐ À première vue, il ne devrait pas y en avoir puisque les contrôles de VB6 disposent des propriétés adéquates :
- pour les couleurs, BackColor fixe celle du fond, ForeColor celle du texte ; cette couleur peut être exprimée en code RGB sous forme d'une valeur de six chiffres hexadécimaux, mais VB utilise par défaut une valeur Système symbolique de huit chiffres dont les deux premiers sont 80 ; par exemple, quand on crée une liste (ListBox ), BackColor vaut 80000005 (« fond de la page », soit blanc = FFFFFF) ; ce mécanisme ingénieux devrait donc permettre le changement automatique des couleurs système. Malheureusement, cet automatisme ne fonctionne pas (du moins dans les versions de Windows 10 et VB6 dont je dispose) ; il faut donc modifier directement les deux valeurs de chaque contrôle ;
- pour le relief, Appearance peut valoir soit 1 (3D , par défaut lors de la création du contrôle) soit 0 (Flat ) ;
__on peut aussi jouer sur BorderStyle = 1 (bordure) ou 0 (pas de bordure). Le système produit l'effet attendu pour les listes (ListBox )___aaa
ou les étiquettes (Label )___aaa | | |
Changer les valeurs de ces propriétés devrait donc permettre de passer de q à w ou e ___aaa Ⓑ Hélas ! d'autres contrôles se montrent beaucoup moins coopératifs, notamment les cadres (Frame ) et les boutons (CommandButton ), qui constituent une part importante de l'interface dans la plupart des programmes. D'abord, dans ces contrôles, mettre Appearance à 0 ne change rien, la bordure restant de type 3D . | |
Pis encore, les CommandButtons sont dépourvus
- de propriété BorderStyle ; il est donc impossible d'obtenir e ;
- de propriété ForeColor ; le texte est nécessairement noir, ce qui n'est pas particulièrement lisible sur un fond lui-même noir ; il faudrait donc remplacer le texte par une image ; mais, à titre d'exemple, ProPhp.exe (le programme servant à éditer ces pages) contient plus de deux cent cinquante de ces boutons ; de plus, l'image devrait être refaite à chaque fois que l'un d'eux voit changer son intitulé, sa police, sa taille ou sa couleur.
Les cases à cocher (CheckBox ) et les boutons d'option (OptionButton ) permettent bien de retrouver un texte en blanc (grâce à la présence d'une propriété ForeColor) mais
- la bordure en pseudo-relief reste impossible à modifier ou supprimer,
- le système impose une couleur différente quand le bouton est enfoncé,
- pour pouvoir les employer en lieu et place d'un CommandButton , il faut prévoir une procédure les remettant à chaque fois en position relâchée.
La seule solution est alors de remplacer les boutons, cases à cocher et boutons d'option par un autre type de contrôle.
La zone d'image (PictureBox ) offre une gestion satisfaisante de la bordure mais le texte ne peut être placé que comme image, rendant le procédé aussi complexe qu'avec la propriété Picture d'un bouton ; l'emploi semble donc limité aux boutons affichant seulement une image.
La solution habituellement conseillée est l'étiquette (Label ), d'un emploi plus souple ; c'est celle qui a été retenue ici dans la plupart des cas, bien qu'elle présente quelques inconvénients :
- la commande Bouton [(Index )].Value = VRAI (qui permet de cliquer virtuellement sur un bouton) n'est plus disponible ; seul est possible Bouton _Click [(Index )] ;
- les étiquettes n'ont pas de hWnd donc pas de SetFocus/GotFocus/LostFocus et ne peuvent pas servir de conteneur pour une image ;
- pour la même raison, il n'est pas possible de faire apparaître une étiquette par dessus un autre contrôle (liste, bouton, zone de texte ou d'image, cadre) en jouant sur la propriété ZOrder ;
NB- cette particularité se révèle d'ailleurs particulièrement gênante lors de la création dans l'interface graphique ; - alors que, dans un bouton, VB centre automatiquement le texte aussi bien horizontalement que verticalement, il faut mettre la propriété Alignment de l'étiquette à 2_Center pour le centrer horizontalement, et rien n'est prévu pour le centrage vertical ; on peut envisager un système à double étiquette, l'une pour la bordure et la couleur de fond, l'autre pour le texte, mais le code s'en trouve fortement alourdi ; il reste donc à jouer avec les polices, certaines plaçant le texte plus bas que d'autres (voir II-Ⓒ-NB3 ci-dessous).
Ⓒ Le remplacement des boutons par des étiquettes a été l'occasion de combler ce qui me semble une lacune de VB6 : quand un contrôle est désactivé, sa bulle d'aide ne s'affiche pas. Ici, la propriété Enabled a donc laissé la place à une fonction Actif et des procédures Active, ActiveSi et Désactive. Le principal inconvénient est de devoir placer une ligne
If Actif(…) = FAUX Then Exit Sub
à l'entrée de chaque procédure d'un contrôle susceptible d'être désactivé.
Ⓓ Dernier problème à résoudre : les procédures MsgBox. Comme on pouvait s'y attendre, rien ne permet de modifier l'apparence gris clair + relief des fenêtres utilisées pour ce type de message. Il a donc fallu créer Dial avec la même multiplicité d'options (procédure / fonction ; icône, nombre et libellé des boutons variables ; toutefois, des propriétés comme vbDefaultButton… ou vbMsgBox… n'ont pas été incluses).
II- Mode d'emploi
Ⓐ Pour mettre à jour un projet, il faut y inclure la feuille
PlatD (fichiers
@_PlatD.frm et
@_PlatD.frx) ainsi que le module
PlatM (fichier
@_PlatM.bas).
Ⓑ Comme on peut le voir dans les captures d'écran ci-dessus, on a le choix entre deux apparences :
- celle qui est numérotée w , dans laquelle les boutons (CommandButton ) sont bordés par un trait simple,
- celle qui est numérotée e , dans laquelle ils n'ont pas de bordure et ne se distinguent pas du fond de la feuille
quand ils ne sont ni survolés ni inactifs.
Dans les deux cas, le fond du bouton est
noir par défaut | brique lorsqu'il est actif et survolé par la souris | gris quand il est désactivé |
| | |
Le choix entre les deux apparences se fait par la variable booléenne globale Bord, dont la valeur FAUX entraîne l'apparence e -sans bordure (valeur par défaut) et VRAI, l'apparence w -trait simple ; pour obtenir ce dernier aspect, il faut placer une instruction Bord = VRAI dans la procédure Form_Load de la feuille.
Les cases d'option (OptionButton ) et cases à cocher (CheckBox ) sont aussi affectées par ce choix, comme il est précisé dans les sections Ⓓ et Ⓔ.
Le fonctionnement de l'ensemble est assuré par les procédures
| é#Nom _MouseMove Form|icNom _MouseMove | couleur de fond lors du survol, appelant couleur de fond par défaut, appelant | FixeFond|FixeFond2 ReNoir | fond brique fond noir |
| Active|Désactive ActiveSi Actif | remplace Nom .Enabled = Vrai|Faux remplace If … Then Nom .Enabled = Vrai remplace = Nom .Enabled |
<!>
Ci-dessous, seules sont mentionnées les propriétés dont la valeur par défaut doit être modifiée.
Ⓒ Les boutons de commande (
CommandButton ) sont remplacés par
Ⓓ Les cases d'option (
OptionButton ) sont remplacées par des étiquettes en groupe de contrôles:
- Name = éoNom
- Appearance = 0 (Flat)
- BackColor = &h0 (noir)
- ForeColor = &hFFFFFF (blanc)
- Index = X
Même comportement et mêmes procédures que pour les boutons avec en plus
_________Pointe (pour « enfoncer » le bouton cliqué) et Pointé (pour renvoyer son état).
L'état est figuré
- dans l'aspect w par
- Appearance : relâché = 0 (Flat) / enfoncé = 1 (3D)
- BorderStyle = 1 (Fixed Single)
- dans l'aspect e par
- Appearance = 0 (Flat)
- BorderStyle : relâché = 0 (None) / enfoncé = 1 (Fixed Single).
NB1- Si besoin est, l'index de la case enfoncée peut être enregistrée dans la propriété Tag d'un contrôle.
NB2- Dans VB6, c'est le conteneur qui crée la famille de boutons d'option ; par exemple, si l'on a dans un cadre deux cases d'option coAAA(0) et coBBB et, à l'extérieur de ce cadre, une case d'option coAAA(1), la selection de coAAA(0) entraîne automatiquement la remise à zéro de coBBB mais on peut sélectionner simultanément coAAA(0) et coAAA(1). Dans Plat, c'est le groupe de contrôles (donc le nom) qui crée la famille, sans tenir compte du conteneur.
Ⓔ Les cases à cocher (
CheckBox ) sont remplacées par une étiquette bouton inverseur éi
Nom .
Comme pour les cases d'option, l'état relâché|enfoncé est figuré par les propriétés Appearance et BorderStyle.
Procédures particulières : Inverse, Coche, Décoche et fonction Coché.
Ⓕ S'agissant des cadres (Frame ), ceux qui servent simplement de conteneur, sans bordure, peuvent être conservés en fixant la propriété BackColor à 0 (noir) ; ceux qui ont un rôle visuel et une bordure sont à remplacer par une zone d'image (PictureBox ) :
- Name = icNom
- Appearance = 0 (Flat)
- BorderStyle = 1 (Fixed Single)
- BackColor = &h0 (noir)
Ⓖ Pour permettre d'afficher les bulles d'aide même quand le contrôle est désactivé, la propriété
Enabled est remplacée par la couleur de fond du bouton :
BackColor | NOIR BRIQUE GRIS | activé non survolé activé + survolé désactivé |
Le fonctionnement est assuré par la fonction Actif et les procédures Active, ActiveSi et Désactive .
Notes complémentaires :
- L'instruction IniPlat Me doit être ajoutée dans la procédure Form_Load de la feuille.
- Cette commande doit être suivie de la liste des contrôles à désactiver par défaut.
- Dans les procédures _Click des contrôles susceptibles d'être désactivés, if faut placer comme première ligne
____If Not Actif(NomDuContrôle ) Then Exit Sub - La liste de ces boutons peut être placée dans le presse-papiers par l'instruction PropCtrl Me, "d" appelée à partir de la feuille ( voir la section Ⓙ plus bas)
- Active et Désactive peuvent traiter une liste de contrôles passée en paramètres mais pas un groupe de contrôles.
- lors du survol, si Actif = VRAI, le curseur de la souris (MousePointer ) prend la forme 15-Size All alors qu'il reste à 0-Default sur un contrôle inactif.
Ⓗ La fonction MsgBox est remplacée par Dial(Texte, Btn[, Ico, Ttr]) où
Btn est une chaîne de 1 à 3 caractères parmi | V vu | O oui | N non | A annuler | R réessayer | I ignorer |
Ico (facultatif), un caractère parmi | I information [par défaut] | E exclamation | Q question | C critique |
La fonction Dial renvoie la lettre du bouton sélectionné.
Ⓘ Constantes couleurs système :
fond courant | fond séléctionné | fond désactivé | texte courant |
Const PNOIR = &h0&, | PCHOIX = &h3060&, | PGRIS = &h808080, | PBLANC = &hFFFFFF |
NB- le P initial sert à distinguer ces constantes de celles qui pourraient être utilisées ailleurs dans le programme.
Ⓙ PropCtrl : procédure à appeler d'une feuille sous la forme PropCtrl Me, "[Q|q][C][D]" pour placer dans le presse-papiers diverses informations sur les contrôles de cette page, suivant le contenu du dernier paramètre :
Q | Container de chaque contrôle |
q | idem en omettant les contrôles placés directement dans la feuille |
C | couleur de fond de chaque contrôle (en hexadécimal) NB- les étiquettes transparentes (Label avec BackStyle = 0) sont signalées par un signe = |
D | contrôles susceptibles d'être désactivés NB- l'information est à corriger quand une instruction Désactive se trouve- placée en commentaire (faux positif),
- dans un module .bas (mention absente).
|
III- Le code
Les trois fichiers @_PlatD.frm, @_PlatD.frx et @_PlatM.bas sont rassemblés dans une archive Plat.zip que l'on peut télécharger en cliquant sur ce lien.
La version la plus récente est v1.0 du 24/02/2022.
Plan du site & Mentions légales_._Site éclos sur Skyrock, développé avec Axiatel et mûri sur Strato.com_._© 2015-2024 - XylonAkau