Jeg har en i boksen som jeg ønsker å måle slik at jeg kan plassere kontrollene på en dialog på riktig måte. Jeg kan lett måle størrelsen på teksten på kontroll - men jeg vet ikke offisielle måte å beregne størrelsen på boksen og gapet før (eller etter) teksten.
Hvordan få størrelsen på sjekk og gapet i boksen?
Jeg er ganske sikker på at bredden på boksen er lik
int x = GetSystemMetrics( SM_CXMENUCHECK );
int y = GetSystemMetrics( SM_CYMENUCHECK );
Du kan deretter jobbe ut området inne ved å trekke følgende ...
int xInner = GetSystemMetrics( SM_CXEDGE );
int yInner = GetSystemMetrics( SM_CYEDGE );
Jeg bruker det i min kode og har ikke hatt et problem så langt ...
Denne koden virker ikke på Win7 med skalert UI (fonter 125% større eller 150% større). Det eneste som ser ut til å fungere er:
int WID = 13 * dc.GetDeviceCaps(LOGPIXELSX) / 96;
int HEI = 13 * dc.GetDeviceCaps(LOGPIXELSY) / 96;
Det er en skam at Microsoft ikke gir en måte å vite dette sikkert. Jeg strevde med det samme spørsmålet og svaret ovenfor er ikke komplett. Hovedproblemet med det er at hvis skriften av dialogvinduet er satt til noe annet enn standardstørrelsen, vil den løsningen ikke fungerer fordi boksene vil bli endret.
Her er hvordan jeg løste dette problemet (det er bare en tilnærming som ser ut til å ha fungert for meg). Koden er for MFC-prosjektet.
1 - Lag to test kontrollene på skjemaet, en boksen og en radio boks:

2 - Definer følgende definert struct:
struct CHECKBOX_DIMS{
int nWidthPx;
int nHeightPx;
int nSpacePx; //Space between checkbox and text
CHECKBOX_DIMS()
{
nWidthPx = 0;
nHeightPx = 0;
nSpacePx = 0;
}
};
3 - Ring følgende kode når skjemaet initialiserer for hver av testkontroller (som vil måle dem og fjerne dem, slik at sluttbrukerne ikke synes dem):
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 - Nå kan du enkelt endre størrelse på boksen eller radio boksen ved å ringe dette:
//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;
}
Kort svar:

lang versjon
Fra MSDN layoutspesifikasjoner: Win32 , har vi spesifikasjonene til dimensjonene på en sjekkheftet.
Det er 12 dialog enheter fra venstre kant av kontrollen til starten av teksten:

Og en avkrysnings kontroll er 10 dialog enheter tall:
Surfaces and Controls Height (DLUs) Width (DLUs)
===================== ============= ===========
Check box 10 As wide as possible (usually to the margins) to accommodate localization requirements.
Først beregner vi på størrelse med en horisontal og en vertikal dialog enhet:
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);
Ved hjelp av den hendige hjelpefunksjonen:
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;
}
Nå som vi vet hvor mange piksler ( checkboxSpacing) for å legge til, beregner vi etikettstørrelsen som normalt:
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;

Merk : Enhver kode utgitt i public domain. Ingen attribusjon nødvendig.
Ok dudes min vei er kanskje ikke de fortest å bruke i runtime, men det fungerer for meg i alle fall jeg har testet så langt. I beginnin av mine proggys jeg satt i en funksjon for å få størrelsen og lagre den i en global variabel (ja jeg har hørt dette ville være dårlig, men jeg ikke bryr seg om dette)
Her forklaring:
- Lag en Utforsker (usynlig hvis u vil)
- Lag en imagelist med ihvertfall en bilde innsiden (størrelse 16x16)
- Sett imagelist til Utforsker ( "TVSIL_NORMAL")
- Få "TVSIL_STATE" imagelist fra Utforsker (u må skape "TVSIL_NORMAL" før, ellers vil mislykkes!)
- Bruk ImageList_GetIconSize (..) og lagre den størrelsen. Wow, checkboxs og radio-knappene har samme størrelse som de statlige ikoner av Utforsker. Nå u har hva u vil!
- Ødelegge "TVSIL_NORMAL" imagelist
- Ødelegge Utforsker
denne koden trenger bare noen få mikrosekunder på begynnelsen av mine proggies og jeg kan bruke den verdien hver gang jeg trenger det.
Innledningen:
Jeg hadde det samme spørsmålet mens du prøver å finne den nødvendige størrelsen på boksen kontroll for en gitt tekst og funnet ut at de eksisterende svarene ikke virkelig fungerer for meg, av flere grunner:
SM_CXMENUCHECKikke står for gapet. Faktisk, jeg er ikke overbevist om at dette er enda for vanlige boksene, selv om det kan ha samme verdi. Det kan også være avhengig av visuelle stiler blir aktivert.- De andre svarene var altfor komplisert og følte meg litt Hacky (ingen aktelse ment, er det MS som ikke gjør dette enkelt).
- Oppgitt 12DLU oppsettet var veldig nyttig, selv om igjen føles vilkårlig uten et system beregning for å stole på.
- Svarene jeg prøvde fortsatt ikke gi en høy nok pikselverdi for å stoppe boksen teksten fra innpakning.
Min undersøkelse:
Jeg så på hvordan Wine reproduserer atferd og funnet ut at det også gir de samme resultatene som bare antar 12DLU. Men teksten fortsatt innpakket med mindre jeg lagt en ekstra 3 piksler til bredden (selv om teksten skal passe fint uten). Jeg la også merke at GetTextExtentPoint32gir en verdi på 3 for en tom streng (hmmm ...)
Slå av BS_MULTILINEstilen åpenbart stoppet tekstbryting. Min gjetning er at DrawTextWOrd innpakning beregninger er ufullkomne.
På dette tidspunktet bestemte jeg meg for at den enkleste løsningen var å bare legge en ekstra plass til GetTextExtentPoint32, slik at det ville definitivt være nok piksler. Den over-estimat av et par piksler var akseptabelt for meg.
Legg merke til at alt dette forutsetter søknaden er manifestert som DPI klar. Ellers fant jeg boksen dukket opp mye større på enkelte Windows 7-systemer (ikke alle skjønt).
Min (for det meste Wine er) løsning:
// 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);
Sorry for å gjenopplive denne gamle tråden. Jeg har nylig funnet meg selv lurer på nøyaktig samme spørsmålet. Foreløpig har ingen av svarene ovenfor gir et resultat i tråd med Windows 10 for ulike fonter og fontstørrelser, spesielt i høy DPI miljøer.
I stedet ser det ut til at riktig resultat oppnås ved
SIZE szCheckBox;
GetThemePartSize(hTheme, hDC, BP_CHECKBOX, CBS_UNCHECKEDNORMAL, &rcBackgroundContent, TS_TRUE, &szCheckBox);
for størrelsen på boksen selv. Og
SIZE szZeroCharacter;
GetTextExtentPoint32(hDC, L"0", 1, &szZeroCharacter);
int iGapWidth = szZeroCharacter.cx / 2;
for bredden av gapet. Etter å ha prøvd mange forskjellige metoder inspirert av innleggene ovenfor, fant jeg L"0"i demontering av Comctl32.dll. Og mens det ser ut som en vits for meg (ikke nødvendigvis en god en), jeg mistenker at det er en etterlevning fra gamle dager da dette kan ha vært en god nok tilnærming til 2DLU.
Disclaimer: Mens jeg testet resultatet med ulike fonter og størrelser på Windows 10, jeg har ikke forsøkt å verifisere at den holder også på noen andre (eldre) versjon av operativsystemet.













