Mam pole wyboru, że chcę, aby dokładnie zmierzyć, więc mogę umieścić kontroli na dialog poprawnie. Mogę łatwo zmierzyć rozmiar tekstu na kontrolę - ale ja nie wiem „oficjalny” sposób obliczania wielkości pole wyboru i luki przed (lub po) tekstu.
Jak zdobyć rozmiar czeku i luki w polu wyboru?
Jestem prawie pewien, szerokość wyboru jest równa
int x = GetSystemMetrics( SM_CXMENUCHECK );
int y = GetSystemMetrics( SM_CYMENUCHECK );
Następnie można wypracować obszar wewnątrz poprzez odjęcie następujących ...
int xInner = GetSystemMetrics( SM_CXEDGE );
int yInner = GetSystemMetrics( SM_CYEDGE );
Używam że w moim kodu i nie miałem problemu do tej pory ...
Ten kod nie działa na Win7 z skalowane czcionki UI (125% lub 150% większe powiększenie). Jedyną rzeczą, która wydaje się działać to:
int WID = 13 * dc.GetDeviceCaps(LOGPIXELSX) / 96;
int HEI = 13 * dc.GetDeviceCaps(LOGPIXELSY) / 96;
To wstyd, że Microsoft nie zapewnia sposób to wiedzieć na pewno. Miałem problemy z tym samym pytaniem i odpowiedzią podane powyżej nie jest kompletna. Głównym problemem jest to, że jeśli czcionka okna dialogowego jest ustawiony na coś innego niż domyślny rozmiar, że rozwiązanie to nie będzie działać, ponieważ pola wyboru zostaną przeskalowane.
Oto jak rozwiązać ten problem (jest tylko przybliżeniem, że wydaje się, że pracował dla mnie). Kod jest dla projektu MFC.
1 - Utwórz dwie kontrole testów na formularzu, pole wyboru oraz pole radiowej:

2 - Definiowanie niestandardowego struct następujące:
struct CHECKBOX_DIMS{
int nWidthPx;
int nHeightPx;
int nSpacePx; //Space between checkbox and text
CHECKBOX_DIMS()
{
nWidthPx = 0;
nHeightPx = 0;
nSpacePx = 0;
}
};
3 - Call następujący kod gdy forma inicjuje dla każdego z testów kontrolnych (które będą je mierzyć i usunąć je tak, aby użytkownicy końcowi nie wydają je):
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 - Teraz można łatwo zmienić rozmiar dowolnego wyboru lub pola radiowego, wywołując w ten sposób:
//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;
}
Krótka odpowiedź:

Długa wersja
Od MSDN specyfikacji układ: Win32 , mamy specyfikacje wymiarów wyboru.
Jest to 12 jednostek dialogowych od lewej krawędzi kontroli na początku tekstu:

I kontrola wyboru jest 10 jednostek dialogowych wysoki:
Surfaces and Controls Height (DLUs) Width (DLUs)
===================== ============= ===========
Check box 10 As wide as possible (usually to the margins) to accommodate localization requirements.
Najpierw musimy obliczyć wielkość poziomej i pionowej jednostki dialogowym:
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);
Korzystanie z funkcji pomocnika poręczny:
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;
}
Teraz, gdy wiemy, ile pikseli ( checkboxSpacing), aby dodać, możemy obliczyć wielkość etykiety jako normalny:
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;

Uwaga : każdy kod wydany w domenie publicznej. Nie wymaga przypisanie.
Ok kolesie mój sposób nie jest być może fastes do wykorzystania w czasie wykonywania, ale to działa na mnie w każdym razie ja testowałem do tej pory. W beginnin moich proggys i umieścić w funkcji, aby uzyskać rozmiar i przechowywać ją w zmiennej globalnej (tak słyszałem to byłoby złe, ale ja nie dbają o to)
Oto wyjaśnienie:
- Tworzenie katalogów (niewidoczny jeśli u chcą)
- Załóż imagelist z conajmniej 1 obraz wewnątrz (rozmiar 16x16)
- Ustaw imagelist do katalogów ( „TVSIL_NORMAL”)
- Uzyskać „TVSIL_STATE” imagelist z katalogów (u trzeba tworzyć „TVSIL_NORMAL” przed, w przeciwnym razie ten jeden zawiedzie!)
- Użyj ImageList_GetIconSize (..) i przechowywać rozmiar. Wow, to checkboxs a radio-przyciski mają ten sam rozmiar co ikon państwowych katalogów. Teraz u mają co u chcą!
- Zniszczyć „TVSIL_NORMAL” imagelist
- Zniszczyć TreeView
Ten kod wymaga tylko kilka mikrosekund na początku moich proggies i mogę użyć wartości za każdym razem jest mi potrzebny.
Preambuła:
Miałem to samo pytanie, starając się ustalić potrzebną wielkość kontroli pole wyboru dla danego tekstu i okazało się, że istniejące odpowiedzi tak naprawdę nie działa na mnie, z kilku powodów:
SM_CXMENUCHECKnie uwzględnia szczeliny. W rzeczywistości, nie jestem przekonany, to nawet dla zwykłych wyboru, chociaż może mieć taką samą wartość. Może być również uzależniona od ich włączony style wizualne.- Pozostałe odpowiedzi były zbyt skomplikowane i czuł się nieco hacky (brak szacunku przeznaczony jest MS, że nie robią to łatwe).
- Podany układ 12DLU był bardzo pomocny, chociaż znowu czuje arbitralny bez systemu metrycznego, aby polegać.
- Odpowiedzi próbowałem jeszcze nie dały wystarczająco wysoką wartość piksela w celu zatrzymania tekstu pole wyboru z opakowania.
Moje dochodzenie:
Spojrzałem na jak wino powiela zachowanie i stwierdził, że to także daje takie same wyniki jak po prostu zakładając 12DLU. Jednak tekst nadal owinięte chyba dodałem dodatkowe 3 pikseli szerokości (chociaż tekst powinien pasować dobrze bez). Zauważyłem również, że GetTextExtentPoint32daje wartość 3 dla pusty ciąg (hmmm ...)
Wyłączanie BS_MULTILINEstyl oczywiście zatrzymał zawijanie tekstu. Moje przypuszczenie jest to, że DrawTextW„obliczenia zawijania s słowne są niedoskonałe.
W tym momencie zdecydowałem, że najprostszym rozwiązaniem było po prostu dodać 1 dodatkowe miejsce do GetTextExtentPoint32, tak, że na pewno będzie wystarczająca pikseli. Nadmierne oszacowanie kilka pikseli był do zaakceptowania dla mnie.
Zauważ, że to wszystko zakłada aplikacja objawia się jako DPI świadomy. Inaczej uważam, że o wiele większe pole pojawiła się na niektórych systemach Windows 7 (choć nie wszystkie).
My (głównie Wine) rozwiązanie:
// 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);
Niestety dla wskrzesza ten stary wątek. Niedawno znalazłem się zastanawiać, o dokładnie tej samej kwestii. Obecnie żadna z odpowiedzi powyżej dają wynik zgodny z systemem Windows 10 różnych czcionek i rozmiarów czcionek, zwłaszcza w środowiskach o wysokiej rozdzielczości.
Zamiast tego wydaje się, że prawidłowy wynik uzyskuje się poprzez
SIZE szCheckBox;
GetThemePartSize(hTheme, hDC, BP_CHECKBOX, CBS_UNCHECKEDNORMAL, &rcBackgroundContent, TS_TRUE, &szCheckBox);
dla rozmiaru samego wyboru. I
SIZE szZeroCharacter;
GetTextExtentPoint32(hDC, L"0", 1, &szZeroCharacter);
int iGapWidth = szZeroCharacter.cx / 2;
dla szerokości szczeliny. Po wypróbowaniu wielu różnych metod zainspirowanych powyższych stanowiskach, znalazłem L"0"w dissembly z pliku COMCTL32.DLL. I choć wygląda jak żart do mnie (nie koniecznie jeden dobry), podejrzewam, że to pozostałość po dawnych czasach, kiedy może to być wystarczająco dobrym przybliżeniem 2DLU.
Zastrzeżenie: A ja testowałem wynik z różnymi czcionkami i różnych rozmiarach w systemie Windows 10, nie próbowali sprawdzić, czy posiada ona również na każdej innej (starszej) wersji systemu operacyjnego.













