Taille des caractères

 

Pour finir avec le chapitre des fontes, la question de la taille qu'occupe un caractère à l'écran:

Comme vous l'avez constaté, il y a les fontes dont les caractères sont tous de la même taille en largeur comme en hauteur. Ce sont les fontes ayant des caractères de taille fixe. Mais il y a aussi les fontes à caractères de tailles variables. Ces fontes peuvent donc poser quelques problèmes à l'affichage comme : Où doit-on positionner le curseur texte (encore appelé caret), faut-il gérer des ascenseurs car le texte sort de la zone client ?

Pour résoudre ces problèmes, il faut comprendre comment sont gérer les informations sur les caractères dans une fonte:

Voici donc un schéma que vous avez déjà dû voir dans de nombreux ouvrages ou sites:

Image non trouvée !

 

On voit bien que la taille des caractères peut varier en hauteur suivant différent critères: L'interligne ascendant ou descendant, la hauteur par rapport à la ligne de base, ...

 

Les valeurs qui vont être intéressantes sont:

Tout d'abord tmExternal : C'est l'espace minimum que Windows conseil entre deux caractères en hauteur.

et surtout tmHeight : C'est la hauteur total du caractère.

Grace à ces deux valeurs, vous pouvez calculer le nombre de lignes affichables dans une fenêtre:

1 ligne occupe donc en hauteur tmExternal + tmHeight pixels.

 

Bien entendu, il est possible de récupérer ces différentes valeurs. Pour cela, vous utiliserez la fonction GetTextMetrics() qui, suivant le contexte périphérique, va renseigner une structure de type TEXTMETRIC avec les valeurs récupérées de la fonte courante.

Ces valeurs seront retournées en pixels (du moins si vous n'avez pas changé l'unité de mesure par défaut).

BOOL GetTextMetrics(
HDC hdc, // handle sur une device contexte
LPTEXTMETRIC lptm // Pointeur sur une structure de type textmetric
);

typedef struct tagTEXTMETRIC {

LONG tmHeight;
LONG tmAscent;
LONG tmDescent;
LONG tmInternalLeading;
LONG tmExternalLeading;
LONG tmAveCharWidth;
LONG tmMaxCharWidth;
LONG tmWeight;
LONG tmOverhang;
LONG tmDigitizedAspectX;
LONG tmDigitizedAspectY;
TCHAR tmFirstChar;
TCHAR tmLastChar;
TCHAR tmDefaultChar;
TCHAR tmBreakChar;
BYTE tmItalic;
BYTE tmUnderlined;
BYTE tmStruckOut;
BYTE tmPitchAndFamily;
BYTE tmCharSet;

} TEXTMETRIC, *PTEXTMETRIC;

 

Les champs intéressant pour ce chapitre sont évidemment ceux sités dans le shéma ci-dessus ainsi que:

tmAveCharWidth qui est la valeur moyenne qu'occupe un caractère minuscule en largeur.

Et éventuellement tmMaxCharWidth qui est la largeur la plus importante occupée par un caractère minuscule.

Exemple d'utilisation:


TEXTMETRIC tm;

hdc = GetDC(hwnd)
GetTextMetrics(hdc, &tm);
cx = tm.tmAveCharWidth;
cy = tm.tmHeight + t.tmExternalLeading;

ReleaseDC(hwnd, hdc);

Avec cx la largeur du caractère, et cy la hauteur.

Cependant, pour la largeur d'un caractère, si vous n'utilisez que des caractères majuscules sur une fonte à taille variable, cela ne marchera pas. (ce ne sont que des valeurs pour les caractères minuscules !)

Dans ce cas, vous utilisez les mêmes champs, mais "on estime" (qui ? je ne sais pas !) que la taille d'un caractère majuscule est de 150 % la taille moyenne en largeur d'un caractère minuscule.

D'où une écriture suivante:

Lecture des informations du champ tmPitchAndFamily pour savoir si la fonte est à taille variable ou fixe:

Le bit de poids faible de tmPitchAndFamily vaut 1 si police à largeur variable. 0 sinon
D'où la formule : cxCaps = (tm.tmpitchAndFamily & 1 ? 3 : 2) * cxChar / 2;

 

Vous pouvez coder ces calculs dans la procédure de gestion des messages pour le message WM_CREATE pour demander ces informations plutôt que dans WM_PAINT. Car ces informations ne changeront pas durant la durée de votre session, du moins tant que la fonte ne change pas.

case WM_CREATE :
hdc = GetDC(wnd);

GetTextMetrics(hdc, &tm);
cxChar = tm.tmAveCharWidth;
cyChar = tm.tmHeight + tm.tmExternalLeading;
cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2;


ReleaseDC(hwnd, hdc);

break;

Voir aussi le message WM_SETFONT. Dans le cas de changement de fonte.

 

Une autre fonction qui est peut-être intéressant : Pour connaître la taille en pixels que va occuper un texte à l'écran, est la fonction GetTextExtentPoint32().

BOOL GetTextExtentPoint32(
HDC hdc, // handle DC
LPCTSTR lpString, // Chaîne de caractères
int cbString, // Taille de la chaîne
LPSIZE lpSize // Pointeur sur une structure size qui recevra les informations sur l'occupation du texte
);

Cette fonction va retourner dans lpSize la taille sous forme de structure SIZE en hauteur et en largeur qu'occupe (ou occuperait) la chaine sur un device contexte.

Avec (SIZE) cx qui est la largeur du texte et cy qui est la hauteur.

 

Toutes ces informations seront bien utiles lors de la gestion des ascenseurs dans une fenêtre.