La fonction DrawFocusRect de l'API windows dessine un rectangle de sélection en XOR avec le fond d'un contexe de périphérique.
Un rectangle est une structure (au sens du C) comportant quatre entiers : (left, top, right, bottom). Malheureusement VFP ne connait pas les structures. C'est la raison pour laquelle j’utilise une string pour passer le rectangle à la fonction DrawFocusRect. Mais c'est finalement très simple avec la fonction Rect présentée.
"en XOR avec le fond" cela veut dire en "ou exclusif" avec le fond. L'intéret du "ou exclusif" est qu'il possède la propriété remarquable suivante : Quel que soit les entiers f et x on a toujours (f XOR x) XOR x = f. En d'autres termes si on dessine deux fois la même chose (x) en XOR sur le fond (f) on restitue le fond d'origine.
Un contexte de périphérique (device context) est une surface sur laquelle on peut dessiner. Il est fourni par Windows. Pourquoi ce nom barbare? Et bien, c'est le même type d'objet que l'on utilise pour une partie d'écran ou une imprimante.
La fonction GetWindowDC de l'API window permet de demander à Windows une référence (handle) vers le contexte de périphérique d'une fenêtre identifiée par son hWnd. Or les objets descendant de form ont la propriété hWnd qui va bien. Mais quand on exécute hDC = GetWindowDC( thisform.hWnd ) on obtient une zone à dessiner qui comprend toute la fenêtre, y compris la barre de titre, les bordures, etc.. Pour pouvoir dessiner dans le même repère de coordonnées que FoxPro, il faut faire une petite translation pour se retrouver dans ce que l'on appelle la zone cliente de la fenêtre. C'est là que la fonction GetSystemMetrics intervient.
La fonction GetSystemMetrics donne des informations sur un certaines caractéristiques graphiques du genre "hauteur de la barre de titre", "hauteur d'un menu", "largeur de la bordure client", etc... Avec elle on peut retrouver les coordonnées de l'origine de la zone cliente dans le contexte de la forme. Il y a pas loin d’une petite centaine de valeurs récupérables. Je n'en utilise que 4.
Lancez le programme ci-dessous
A suivre ...
Code source :
*/* FocusRect.prg * Using DrawFocusRect API function * Run this prg * Robert Plagnard feb 25, 2007
* paramètre à passer à GetSysMetrics pour obtenir
#define SM_CYCAPTION 4 && hauteur de la barre de titre
#define SM_CXSIZEFRAME 32 && largeur de la bordure verticale
#define SM_CYSIZEFRAME 33 && hauteur de la bordure horizontale
#define SM_CYMENU 15 && hauteur d’un menu
declareinteger DrawFocusRect in win32api integer, string @ declareinteger GetWindowDC in win32api integer declareinteger ReleaseDC in win32api integer, integer declareinteger GetSystemMetrics in win32api integer
public gf
gf = CreateObject( "CForm1" )
gf.Show
defineclass CForm1 asForm
caption = "Click on the form"
hidden nXClientOrigin && X Origin of client zone in window hidden nYClientOrigin && Y Origin of client zone in window
Apres DrawFocusRect(), il serait bien de mettre = ReleaseDC(thisform.HWnd, m.hdc)
&& declare integer ReleaseDC in user32 integer, integer
le 02/03/2007, FredA a écrit : Bonjour. En utilisant GetDC au lieu de GetWindowDC on a acces directement à la zone client de la fenêtre...
le 02/03/2007, Robert Plagnard a écrit : Vous avez parfaitement raison tous les deux. Il faut absolument libérer le device context, et puis GetDC, c'est évident. Merci.
le 06/03/2007, Robert Plagnard a écrit : Finalement, GetDC n'est pas si évident que ça, car ca ne marche pas dans tous les cas. En particulier si ShowWindow = 2 (top-level). Dans ce cas il y a 2 fenêtres. Ma solution avec GetWindowDC marche dans tous les cas. GetDC aussi mais là il faut utiliser la formule magique (ou lire la doc!) et mettre : hDC = GetDC( sys( 2327, sys( 2325, sys( 2326, thisform.HWnd )))) Et ce qui est beau, c'est que cette formule est correcte pour toutes les valeurs de ShowWIndow!
Robert,
Apres DrawFocusRect(), il serait bien de mettre
= ReleaseDC(thisform.HWnd, m.hdc)
&& declare integer ReleaseDC in user32 integer, integer