J'ai une case à cocher que je veux mesurer avec précision afin que je puisse placer des commandes sur une boîte de dialogue correctement. Je peux facilement mesurer la taille du texte sur le contrôle - mais je ne sais pas la façon de calculer la taille « officielle » de la case à cocher et l'écart avant (ou après) le texte.
Comment obtenir la taille de l'enregistrement et de l'écart dans la case à cocher?
Je suis sûr que la largeur de la case à cocher est égale à
int x = GetSystemMetrics( SM_CXMENUCHECK );
int y = GetSystemMetrics( SM_CYMENUCHECK );
Vous pouvez alors travailler la zone à l'intérieur en soustrayant les éléments suivants ...
int xInner = GetSystemMetrics( SM_CXEDGE );
int yInner = GetSystemMetrics( SM_CYEDGE );
Je l'utiliser dans mon code et ne l'ai pas eu un problème jusqu'ici ...
Ce code ne fonctionne pas sur Win7 avec l'interface utilisateur réduite (polices 125% plus ou 150% plus). La seule chose qui semble fonctionner est:
int WID = 13 * dc.GetDeviceCaps(LOGPIXELSX) / 96;
int HEI = 13 * dc.GetDeviceCaps(LOGPIXELSY) / 96;
Il est dommage que Microsoft n'a pas fourni un moyen de savoir ce pour sûr. Je luttais avec la même question et la réponse fournie ci-dessus n'est pas complète. Le principal problème avec c'est que si la police de la fenêtre de dialogue est réglé sur autre chose que la taille par défaut, cette solution ne fonctionnera pas parce que les cases seront redimensionnées.
Voici comment je résolu cette question (il est juste une approximation qui semble avoir travaillé pour moi). Le code est pour le projet MFC.
1 - Créer deux commandes de test sur votre formulaire, une case à cocher et une boîte de radio:

2 - Définir le struct personnalisé suivant:
struct CHECKBOX_DIMS{
int nWidthPx;
int nHeightPx;
int nSpacePx; //Space between checkbox and text
CHECKBOX_DIMS()
{
nWidthPx = 0;
nHeightPx = 0;
nSpacePx = 0;
}
};
3 - Composez le code suivant lorsque le formulaire pour chacun des initialise les contrôles de test (qui les mesurer et de les supprimer afin que les utilisateurs finaux ne les ont pas l'air):
BOOL OnInitDialog()
{
CDialog::OnInitDialog();
//Calculate the size of a checkbox & radio box
VERIFY(GetInitialCheckBoxSize(IDC_CHECK_TEST, &dimsCheckBox, TRUE));
VERIFY(GetInitialCheckBoxSize(IDC_RADIO_TEST, &dimsRadioBox, TRUE));
//Continue with form initialization ...
}
BOOL GetInitialCheckBoxSize(UINT nCtrlID, CHECKBOX_DIMS* pOutCD, BOOL bRemoveCtrl)
{
//Must be called initially to calculate the size of a checkbox/radiobox
//'nCtrlID' = control ID to measure
//'pOutCD' = if not NULL, receives the dimensitions
//'bRemoveCtrl' = TRUE to delete control
//RETURN:
// = TRUE if success
BOOL bRes = FALSE;
//Get size of a check (not exactly what we need)
int nCheckW = GetSystemMetrics(SM_CXMENUCHECK);
int nCheckH = GetSystemMetrics(SM_CYMENUCHECK);
//3D border spacer (not exactly what we need either)
int nSpacerW = GetSystemMetrics(SM_CXEDGE);
//Get test checkbox
CButton* pChkWnd = (CButton*)GetDlgItem(nCtrlID);
ASSERT(pChkWnd);
if(pChkWnd)
{
CRect rcCheckBx;
pChkWnd->GetWindowRect(&rcCheckBx);
//We need only the height
//INFO: The reason why we can't use the width is because there's
// an arbitrary text followed by a spacer...
int h = rcCheckBx.Height();
CDC* pDc = pChkWnd->GetDC();
if(pDc)
{
//Get horizontal DPI setting
int dpiX = pDc->GetDeviceCaps(LOGPIXELSX);
//Calculate
if(pOutCD)
{
//Use height as-is
pOutCD->nHeightPx = h;
//Use height for the width
pOutCD->nWidthPx = (int)(h * ((double)nCheckW / nCheckH));
//Spacer is the hardest
//INFO: Assume twice and a half the size of 3D border &
// take into account DPI setting for the window
// (It will give some extra space, but it's better than less space.)
// (This number is purely experimental.)
// (96 is Windows DPI setting for 100% resolution setting.)
pOutCD->nSpacePx = (int)(nSpacerW * 2.5 * dpiX / 96.0);
}
//Release DC
pChkWnd->ReleaseDC(pDc);
if(bRemoveCtrl)
{
//Delete window
bRes = pChkWnd->DestroyWindow();
}
else
{
//Keep the window
bRes = TRUE;
}
}
}
return bRes;
}
4 - Maintenant, vous pouvez facilement redimensionner une case à cocher ou case radio en appelant ceci:
//Set checkbox size & new text
VERIFY(SetCheckBoxTextAndSize(this, IDC_CHECK_ID, &dimsCheckBox, L"New text") > 0);
//Just resize radio box
VERIFY(SetCheckBoxTextAndSize(this, IDC_RADIO_ID, &dimsRadioBox, NULL) > 0);
int SetCheckBoxTextAndSize(CWnd* pParWnd, UINT nCheckBoxID, CHECKBOX_DIMS* pDims, LPCTSTR pNewText)
{
//Set size of the checkbox/radio to 'pNewText' and update its size according to its text
//'pParWnd' = parent dialog window
//'nCheckBoxID' = control ID to resize (checkbox or radio box)
//'pDims' = pointer to the struct with checkbox/radiobox dimensions
//'pNewText' = text to set, or NULL not to change the text
//RETURN:
// = New width of the control in pixels, or
// = 0 if error
int nRes = 0;
ASSERT(pParWnd);
ASSERT(pDims);
CButton* pChkWnd = (CButton*)pParWnd->GetDlgItem(nCheckBoxID);
ASSERT(pChkWnd);
if(pChkWnd)
{
CDC* pDc = pChkWnd->GetDC();
CFont* pFont = pChkWnd->GetFont();
if(pDc)
{
if(pFont)
{
//Make logfont
LOGFONT lf = {0};
if(pFont->GetLogFont(&lf))
{
//Make new font
CFont font;
if(font.CreateFontIndirect(&lf))
{
//Get font from control
CFont* pOldFont = pDc->SelectObject(&font);
//Get text to set
CString strCheck;
if(pNewText)
{
//Use new text
strCheck = pNewText;
}
else
{
//Keep old text
pChkWnd->GetWindowText(strCheck);
}
//Calculate size
RECT rc = {0, 0, 0, 0};
::DrawText(pDc->GetSafeHdc(), strCheck, strCheck.GetLength(), &rc, DT_CALCRECT | DT_NOPREFIX | DT_SINGLELINE);
//Get text width
int nTextWidth = abs(rc.right - rc.left);
//See if it's valid
if(nTextWidth > 0 ||
(nTextWidth == 0 && strCheck.GetLength() == 0))
{
//Get location of checkbox
CRect rcChk;
pChkWnd->GetWindowRect(&rcChk);
pParWnd->ScreenToClient(rcChk);
//Update its size
rcChk.right = rcChk.left + pDims->nWidthPx + pDims->nSpacePx + nTextWidth;
//Use this line if you want to change the height as well
//rcChk.bottom = rcChk.top + pDims->nHeightPx;
//Move the control
pChkWnd->MoveWindow(rcChk);
//Setting new text?
if(pNewText)
{
pChkWnd->SetWindowText(pNewText);
}
//Done
nRes = abs(rcChk.right - rcChk.left);
}
//Set font back
pDc->SelectObject(pOldFont);
}
}
}
//Release DC
pChkWnd->ReleaseDC(pDc);
}
}
return nRes;
}
Réponse courte:

Version longue
A partir de MSDN mise en page Spécifications: Win32 , nous avons les spécifications des dimensions d'une case à cocher.
Il est 12 unités de dialogue à partir du bord gauche du contrôle au début du texte:

Et un contrôle de case à cocher est de 10 unités de dialogue de haut:
Surfaces and Controls Height (DLUs) Width (DLUs)
===================== ============= ===========
Check box 10 As wide as possible (usually to the margins) to accommodate localization requirements.
D'abord, nous calculons la taille d'une horizontale et une unité de dialogue verticale:
const dluCheckBoxInternalSpacing = 12; //12 horizontal dlus
const dluCheckboxHeight = 10; //10 vertical dlus
Size dialogUnits = GetAveCharSize(dc);
Integer checkboxSpacing = MulDiv(dluCheckboxSpacing, dialogUnits.Width, 4);
Integer checkboxHeight = MulDiv(dluCheckboxHeight, dialogUnits.Height, 8);
En utilisant la fonction d'assistance pratique:
Size GetAveCharSize(HDC dc)
{
/*
How To Calculate Dialog Base Units with Non-System-Based Font
http://support.microsoft.com/kb/125681
*/
TEXTMETRIC tm;
GetTextMetrics(dc, ref tm);
String buffer = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
Size result;
GetTextExtentPoint32(dc, buffer, 52, out result);
result.Width = (result.X/26 + 1) / 2; //div uses trunc rounding; we want arithmetic rounding
result.Height = tm.tmHeight;
return result;
}
Maintenant que nous savons combien de pixels ( checkboxSpacing) pour ajouter, on calcule la taille de l' étiquette comme normale:
textRect = Rect(0,0,0,0);
DrawText(dc, Caption, -1, textRect, DT_CALCRECT or DT_LEFT or DT_SINGLELINE);
chkVerification.Width = checkboxSpacing+textRect.Right;
chkVerification.Height = checkboxHeight;

Remarque : Tout code publié dans le domaine public. Aucune attribution nécessaire.
Ok dudes mon chemin est peut-être pas Fastes à utiliser dans l'exécution, mais il fonctionne pour moi en tout cas, je l'ai testé jusqu'à présent. Dans le beginnin de mes proggys je mets dans une fonction pour obtenir la taille et le stocker dans une variable globale (ouais j'ai entendu ce serait mauvais, mais je ne garde à ce sujet)
Voici l'explication:
- Créer un TreeView (invisible si tu veux)
- Créer un imagelist avec atleast une image à l'intérieur (taille 16x16)
- Réglez le imagelist au TreeView ( "TVSIL_NORMAL")
- Obtenez le « TVSIL_STATE » imagelist du TreeView (u doivent créer « TVSIL_NORMAL » avant, sinon celui-ci échouera!)
- Utilisez ImageList_GetIconSize (..) et stocker la taille. Wow, les checkboxs et les boutons radio-ont la même taille que les icônes d'état de l'arborescence. Maintenant u ont ce que tu veux!
- Détruire le imagelist « de TVSIL_NORMAL »
- Détruire le TreeView
ce code n'a besoin que de quelques microsecondes au début de mes proggies et je peux utiliser la valeur à chaque fois que je en ai besoin.
Préambule:
J'ai eu la même question tout en essayant de déterminer la taille nécessaire du contrôle de case à cocher pour un texte donné et a constaté que les réponses existantes ne fonctionnent pas vraiment pour moi, pour plusieurs raisons:
SM_CXMENUCHECKne tient pas compte de l'écart. En fait, je ne suis pas convaincu que c'est même régulièrement des cases à cocher, bien qu'il puisse avoir la même valeur. Il peut aussi dépendre des styles visuels sont activés.- Les autres réponses étaient trop compliquées et se sentait un peu hacky (pas vouloir manquer de respect, il est MS qui ne font pas facile).
- La mise en page 12DLU dit était très utile, bien qu'encore une fois se sent arbitraire sans système métrique à compter.
- Les réponses que j'essayées n'a toujours pas donné une valeur de pixel suffisante pour arrêter le texte de la case d'emballage.
Mon enquête:
Je regarde comment le vin reproduit le comportement et a constaté qu'il donne également les mêmes résultats que simplement supposer 12DLU. Cependant, le texte encore enveloppé à moins que j'ajouté un 3 pixels supplémentaires à la largeur (même si le texte doit tenir bien sans). J'ai aussi remarqué que GetTextExtentPoint32donne une valeur de 3 pour une chaîne vide (hmmm ...)
Mise hors BS_MULTILINEstyle est arrêté évidemment l'emballage de texte. Mon estimation est que DrawTextW« les calculs d'emballage de mots s sont imparfaits.
A ce stade , j'ai décidé que la solution la plus simple était d'ajouter seulement 1 espace supplémentaire pour GetTextExtentPoint32, de sorte qu'il y aurait certainement assez de pixels. La surévaluation d'un couple de pixels était acceptable pour moi.
Notez que tout cela suppose que votre demande se manifeste aussi au courant DPI. Sinon, je trouve la case à cocher est apparue beaucoup plus sur certains systèmes Windows 7 (pas tous cependant).
Mon (la plupart du temps de vin) solution:
// This code gets the size of a piece of text and adds the size of a
// checkbox and gap. Note that this is very rough code with no error handling.
BOOL isCheckbox = TRUE;
HWND dialog = ... // Your control or dialog
HFONT font = ... // The font your control will use if it hasn't been set yet
PTCHAR text = ... // Your text
HFONT currentFont;
SIZE size;
HDC dc = GetDC(dialog);
if (!font) {
font = (HFONT)SendMessage(dialog, WM_GETFONT, 0, 0);
}
currentFont = (HFONT)SelectObject(dc, font); // NB: You should add error handling here
if (isCheckbox) {
// Or you can disable BS_MULTILINE
_tcscat(text, TEXT(" ")); // NB: This assumes text is allocated for +1 char
}
GetTextExtentPoint32(dc, text, _tcslen(text), &size); // NB: You should add error handling here
if (isCheckbox) {
int checkBoxWidth = 12 * GetDeviceCaps(dc, LOGPIXELSX ) / 96 + 1;
int checkBoxHeight = 12 * GetDeviceCaps(dc, LOGPIXELSY ) / 96 + 1;
int textOffset;
GetCharWidthW(dc, '0', '0', &textOffset);
textOffset /= 2;
size->cx += checkBoxWidth + textOffset;
if (size->cy < checkBoxHeight) {
size->cy = checkBoxHeight;
}
}
if (currentFont) {
SelectObject(dc, currentFont);
}
ReleaseDC(dialog, dc);
Désolé pour ressusciter ce vieux fil. Je me suis récemment trouvé interroger sur la même question. À l'heure actuelle, aucune des réponses ci-dessus donnent un résultat cohérent avec Windows 10 pour différentes polices et tailles de police, en particulier dans des environnements de haute DPI.
Il semble plutôt que l'on obtient le résultat correct par
SIZE szCheckBox;
GetThemePartSize(hTheme, hDC, BP_CHECKBOX, CBS_UNCHECKEDNORMAL, &rcBackgroundContent, TS_TRUE, &szCheckBox);
pour la taille de la case à cocher lui-même. Et
SIZE szZeroCharacter;
GetTextExtentPoint32(hDC, L"0", 1, &szZeroCharacter);
int iGapWidth = szZeroCharacter.cx / 2;
pour la largeur de la fente. Après avoir essayé beaucoup de différentes méthodes inspirées par les postes ci - dessus, je trouve L"0"dans le désassemblage de comctl32.dll. Et alors qu'il ressemble à une blague pour moi (pas nécessairement un bon), je pense qu'il est un vestige de l'époque où cela aurait pu être une assez bonne approximation de 2DLU.
Avertissement: Alors que je l'ai testé le résultat avec différentes polices et de tailles différentes sur Windows 10, je ne l'ai pas essayé de vérifier qu'elle détient aussi une autre version (plus) du système d'exploitation.













