Am o casetă de validare pe care vreau să măsoare cu precizie, astfel că pot poziționa controale pe un dialog corect. Pot măsura cu ușurință dimensiunea textului privind controlul - dar eu nu cunosc modul în care „oficial“ de calcul dimensiunea casetei de selectare și diferența înainte (sau după) textul.
Cum să obțineți dimensiunea de selectare și decalaj în caseta de validare?
sursa de către utilizator Mark Ingram
În alte limbi...
Sunt destul de sigur că lățimea este egală cu caseta
int x = GetSystemMetrics( SM_CXMENUCHECK );
int y = GetSystemMetrics( SM_CYMENUCHECK );
Apoi, puteți lucra în zona din interiorul scăzând cu următorul text ...
int xInner = GetSystemMetrics( SM_CXEDGE );
int yInner = GetSystemMetrics( SM_CYEDGE );
Eu folosesc ca în codul meu și nu au avut o problemă până acum ...
Acest cod nu funcționează pe Win7 cu UI scalate (fonturi 125% mai mare sau 150% mai mare). Singurul lucru care pare să funcționeze este:
int WID = 13 * dc.GetDeviceCaps(LOGPIXELSX) / 96;
int HEI = 13 * dc.GetDeviceCaps(LOGPIXELSY) / 96;
Este o rușine că Microsoft nu a oferit o modalitate de a ști acest lucru sigur. Am fost luptă cu aceeași întrebare și răspunsul oferit de mai sus nu este completă. Problema principală cu aceasta este că, dacă fontul ferestrei de dialog este setat la altceva decât dimensiunea implicită, această soluție nu va funcționa, deoarece casetele de selectare vor fi redimensionate.
Iată cum am rezolvat această problemă (este doar o aproximare care pare să fi lucrat pentru mine). Codul este pentru proiectul MFC.
1 - Crearea două controale de test pe formular, o casetă de selectare și o casetă de radio:

2 - Definiți următoarele struct personalizate:
struct CHECKBOX_DIMS{
int nWidthPx;
int nHeightPx;
int nSpacePx; //Space between checkbox and text
CHECKBOX_DIMS()
{
nWidthPx = 0;
nHeightPx = 0;
nSpacePx = 0;
}
};
3 - Apelați următorul cod atunci când formularul inițializează pentru fiecare dintre comenzile de testare (care le va măsura și a le elimina, astfel încât utilizatorii finali nu par le):
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 - Acum puteți redimensiona cu ușurință orice casetă de selectare sau o casetă de radio prin apelarea acestui:
//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ăspuns scurt:

Versiune pe termen lung
De la MSDN Aspect Specificatii: Win32 , avem specificațiile dimensiunile unei casetă de selectare.
Este de 12 de unități de dialog de la marginea din stânga a controlului la începutul textului:

Și un control casetă de selectare este de 10 de unități de dialog înalt:
Surfaces and Controls Height (DLUs) Width (DLUs)
===================== ============= ===========
Check box 10 As wide as possible (usually to the margins) to accommodate localization requirements.
În primul rând vom calcula dimensiunea orizontală și o unitate de dialog verticală:
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);
Cu ajutorul funcției de ajutor la îndemână:
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;
}
Acum , că știm cât de mulți pixeli ( checkboxSpacing) pentru a adăuga, vom calcula dimensiunea etichetei în mod normal:
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;

Notă : Orice cod eliberat în domeniu public. Nu atribuire necesară.
dudes Ok drumul meu nu este, poate FASTELOR de a utiliza în timpul rulării, dar funcționează pentru mine, în orice caz, am testat până acum. În beginnin de proggys mele am pus într-o funcție pentru a obține dimensiunea și păstrați-l într-o variabilă globală (Da, am auzit acest lucru ar fi rău, dar i dont de îngrijire despre acest lucru)
aici explicația:
- Creați un TreeView (invizibil u dacă doriți)
- Creați un Imagelist cu atleast 1 imagine interior (16x16 dimensiune)
- Setați Imagelist la treeview ( "TVSIL_NORMAL")
- Ia „TVSIL_STATE“ Imagelist din treeview (u trebuie să creeze „TVSIL_NORMAL“ înainte, în caz contrar acesta va eșua!)
- Utilizați ImageList_GetIconSize (..) și se păstrează dimensiunea. Wow, a checkboxs și butoane radio au aceeași dimensiune ca pictogramele de stat ale treeview. Acum u au ceea ce vrei u!
- Distruge „TVSIL_NORMAL“ Imagelist
- Distruge treeview
acest cod are nevoie doar de câteva microsecunde la începutul proggies mele și i se poate utiliza valoarea Everytime am nevoie de ea.
Preambul:
Am avut aceeași întrebare în timp ce încerca să determine dimensiunea necesară a controlului casetă de selectare pentru un anumit text și a constatat că răspunsurile existente nu au de lucru într - adevăr pentru mine, din mai multe motive:
SM_CXMENUCHECKnu ține cont de diferența. De fapt, eu nu sunt convins că acest lucru este chiar și pentru casetele de selectare regulate, deși poate avea aceeași valoare. Acesta poate fi, de asemenea, depinde de stiluri vizuale fiind activate.- Celelalte răspunsuri au fost mult prea complicate și a simțit un pic Hacky (fără lipsă de respect intenționat, este SM care nu fac acest lucru ușor).
- Scopul declarat aspect 12DLU a fost foarte util, deși, din nou se simte arbitrar, fără un sistem metric să se bazeze pe.
- Răspunsurile am încercat încă nu a produs o valoare mare de pixeli suficient pentru a opri textul caseta de selectare din ambalaj.
Investigația mea:
M - am uitat la modul de vin reproduce comportamentul și a constatat că oferă , de asemenea , aceleași rezultate ca pur și simplu presupunând 12DLU. Cu toate acestea, textul încă înfășurat excepția cazului în care am adăugat un plus de 3 pixeli pentru lățimea (chiar dacă textul ar trebui să se potrivească bine fără). De asemenea , am observat că GetTextExtentPoint32dă o valoare de 3 pentru un șir gol (hmmm ...)
Oprirea BS_MULTILINEstilul , evident , sa oprit ambalajul de text. Mea presupunere este că DrawTextWe cuvânt calculele de ambalaj sunt imperfecte.
În acest moment am decis că cea mai simplă soluție a fost de a adăuga doar un spațiu suplimentar pentru a GetTextExtentPoint32, astfel încât nu ar fi cu siguranta suficient de pixeli. Supra-estimare a unui cuplu de pixeli a fost acceptabil pentru mine.
Rețineți că acest lucru presupune toate cererea dumneavoastră se manifestă ca DPI conștient. În caz contrar, am găsit caseta de selectare a apărut mult mai mare pe unele pentru Windows 7 sisteme (nu toate, deși).
(Cea mai mare parte vinului) Soluția mea:
// 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);
Ne pare rău pentru înviind acest thread vechi. Recent m-am trezit întrebam despre exact aceeași întrebare. În prezent, nici unul dintre răspunsurile de mai sus dau un rezultat consistent cu Windows 10 pentru diferite fonturi și dimensiuni de font, în special în mediile de înaltă DPI.
In schimb, se pare că rezultatul corect este obținut prin
SIZE szCheckBox;
GetThemePartSize(hTheme, hDC, BP_CHECKBOX, CBS_UNCHECKEDNORMAL, &rcBackgroundContent, TS_TRUE, &szCheckBox);
pentru dimensiunea caseta de selectare în sine. Și
SIZE szZeroCharacter;
GetTextExtentPoint32(hDC, L"0", 1, &szZeroCharacter);
int iGapWidth = szZeroCharacter.cx / 2;
pentru lățimea diferenței. După ce a încercat o mulțime de metode diferite inspirate de posturile de mai sus, am găsit L"0"în dissembly de COMCTL32.DLL. Și , în timp ce se pare ca o glumă pentru mine (nu neapărat unul bun), bănuiesc că este o relicvă din vremurile de demult , atunci când acest lucru ar fi fost o aproximare destul de bună de 2DLU.
Disclaimer: In timp ce am testat rezultatul cu diferite fonturi și dimensiuni diferite pe Windows 10, nu am încercat să verifice că deține, de asemenea, pe orice altă versiune (mai veche) a sistemului de operare.