Mám políčko, že chci, aby přesně změřit, abych mohl správně umístit ovládací prvky dialogu. Mohu snadno změřit velikost textu o kontrole - ale nevím, „oficiální“ způsob výpočtu velikosti políčka a mezery před (nebo po) textu.
Jak se dostat na velikosti kontrole a mezery v políčko?
Jsem si jistý, že šířka políčka se rovná
int x = GetSystemMetrics( SM_CXMENUCHECK );
int y = GetSystemMetrics( SM_CYMENUCHECK );
Pak můžete přijít prostoru uvnitř odečtením následující ...
int xInner = GetSystemMetrics( SM_CXEDGE );
int yInner = GetSystemMetrics( SM_CYEDGE );
Já používám, že v mém kódu a neměli problém tak daleko ...
Tento kód nefunguje na Win7 s zmenšen UI (písma 125% větší, nebo 150% větší). Jediná věc, která se zdá fungovat, je:
int WID = 13 * dc.GetDeviceCaps(LOGPIXELSX) / 96;
int HEI = 13 * dc.GetDeviceCaps(LOGPIXELSY) / 96;
Je škoda, že Microsoft neposkytl způsob, jak vědět to určitě. Jsem se snažila se stejnou otázkou a odpovědí je uvedeno výše, není kompletní. Hlavním problémem je, že v případě, že písmo v dialogovém okně je nastaven na jinou hodnotu než výchozí velikost, toto řešení nebude fungovat, protože políčka budou zmenšeny.
Zde je návod, jak jsem vyřešil tento problém (to je jen aproximace, která se zdá, že pracoval pro mě). Kód je pro projekt MFC.
1 - Vytvořte dvě testovací ovládací prvky na formuláři, zaškrtávací políčko a rozhlasové krabice:

2 - Definujte následující vlastní struct:
struct CHECKBOX_DIMS{
int nWidthPx;
int nHeightPx;
int nSpacePx; //Space between checkbox and text
CHECKBOX_DIMS()
{
nWidthPx = 0;
nHeightPx = 0;
nSpacePx = 0;
}
};
3 - Výzva následující kód, když forma inicializuje pro každý z testovaných kontrol (které je budou měřit a odstranit tak, že koncoví uživatelé se nezdají jim):
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 - Nyní můžete snadno změnit velikost jakékoliv políčko nebo rozhlasový okno voláním toto:
//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;
}
Stručná odpověď:

Long Version
Z MSDN rozvržení Specifikace: Win32 , máme specifikace rozměrů zaškrtávací políčko.
Je to 12 dialogová jednotek od levého okraje ovládacího prvku na začátku textu:

A kontrolní políčko 10 Dialog Jednotky vysoký:
Surfaces and Controls Height (DLUs) Width (DLUs)
===================== ============= ===========
Check box 10 As wide as possible (usually to the margins) to accommodate localization requirements.
Nejdříve jsme vypočítat velikost vodorovné a svislé dialogové jednotky:
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);
Pomocí šikovného pomocníka funkce:
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;
}
Teď, když víme, kolik pixelů ( checkboxSpacing) pro přidání, spočítáme velikost štítku jako obvykle:
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;

Poznámka : Jakýkoli kód propuštěn do veřejné domény. No uvedením zdroje.
Ok dudes moje cesta je možná ne fastes pro použití v běhu, ale funguje to pro mě v každém případě jsem doposud testovaných. V beginnin mých proggys i dát do funkce, aby velikost a uložit jej do globální proměnné (jo jsem slyšel to by bylo špatné, ale já dont starat o to)
Zde vysvětlení:
- Vytvořte TreeView (neviditelný-li u potřeba)
- Vytvořte ImageList se aspoň jeden obrázek uvnitř (velikost 16x16)
- Nastavit ImageList do stromu ( „TVSIL_NORMAL“)
- Získejte „TVSIL_STATE“ ImageList ze stromu (u muset vytvořit „TVSIL_NORMAL“ předtím, jinak tohle selže!)
- Použít ImageList_GetIconSize (..) a uložte velikosti. Wow, že checkboxs a radio-tlačítka mají stejnou velikost jako státní ikon stromu. Teď u to, co u chtějí!
- Zničit „TVSIL_NORMAL“ Imagelist
- Zničit TreeView
Tento kód je třeba jen několik mikrosekund na začátku mé proggies a mohu použít hodnotu pokaždé jsem ji potřebují.
Preambule:
Měl jsem stejnou otázku, když se snaží určit potřebnou velikost ovládacího prvku políčko u daného textu a zjistil, že stávající odpovědi se opravdu práce pro mě, z několika důvodů:
SM_CXMENUCHECKneodpovídá za mezery. Ve skutečnosti nejsem přesvědčen o tom, je to i pro pravidelné políček, i když může mít stejnou hodnotu. To může být také závislý na právě vizuální styly povoleny.- Ostatní odpovědi byly příliš složité a cítil trochu hacky (urazit určen, je MS, které nedělají to snadné).
- Uvedený layout 12DLU bylo velmi užitečné, když se znovu cítí svévolné bez systému metrické spoléhat na.
- Odpovědi jsem se snažil ještě nepřinesla dost vysokou hodnotu pixelu zastavit text políčka z obalu.
Moje vyšetřování:
Podíval jsem se na to, jak Wine reprodukuje chování a zjistil, že to také dává stejné výsledky jako jen za předpokladu, že 12DLU. Text však stále zabalený pokud jsem přidal další 3 pixelů na šířku (i přesto, že text by měl vešel dobře i bez). Také jsem si všiml, že GetTextExtentPoint32dává hodnotu 3 pro prázdný řetězec (hmmm ...)
Vypnutí BS_MULTILINEstyl zřejmě zastavil obtékání textu. Můj odhad je, že DrawTextWto slovo výpočty balení jsou nedokonalé.
V tomto bodě jsem se rozhodl, že nejjednodušším řešením bylo jen přidat 1 více prostoru pro GetTextExtentPoint32, takže tam určitě dostatek pixelů. Nadměrná odhad pár pixelů byl přijatelný pro mě.
Všimněte si, že to všechno předpokládá, vaše aplikace se projevuje jako DPI vědomi. Jinak jsem našel toto políčko se objevila mnohem větší, u některých systémů Windows 7 (ne všichni ačkoli).
My (většinou Wine) Řešení:
// 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);
Omlouvám se za vzkřísit tuhle starou nit. Nedávno jsem zjistil, že jsem přemýšlel o přesně stejnou otázku. V současné době žádná z výše uvedených odpovědí, jejímž výsledkem je konzistentní s Windows 10 různých písem a velikostí písma, zejména v prostředí s vysokou DPI.
Místo toho se zdá, že správný výsledek je získán
SIZE szCheckBox;
GetThemePartSize(hTheme, hDC, BP_CHECKBOX, CBS_UNCHECKEDNORMAL, &rcBackgroundContent, TS_TRUE, &szCheckBox);
pro velikost samotného políčko. A
SIZE szZeroCharacter;
GetTextExtentPoint32(hDC, L"0", 1, &szZeroCharacter);
int iGapWidth = szZeroCharacter.cx / 2;
na šířku mezery. Poté, co se snaží mnoho různých metod, které mají čerpat z míst výše, jsem našel L"0"v dissembly of Comctl32.dll. A i když to vypadá jako vtip mě (ne nutně dobrý), mám podezření, že je to pozůstatek ze starých časů, kdy by to mohlo být dost dobrý přibližování 2DLU.
Upozornění: I když jsem testoval výsledek s různými fonty a různých velikostí na Windows 10, jsem se pokusil ověřit, že to platí také na všech ostatních (starší) verzi operačního systému.













