Ich habe ein Kontrollkästchen, das ich will genau messen, damit ich richtig Steuerelemente in einem Dialog positionieren kann. Ich kann einfach die Größe des Textes auf der Steuer messen - aber ich weiß nicht, den „offiziellen“ Weg, um die Größe des Kontrollkästchen zu berechnen und die Lücke vor (oder nach) dem Text.
Wie Größe der Prüfung und Lücke in dem Kontrollkästchen bekommen?
quelle vom benutzer Mark Ingram
In anderen Sprachen...
Ich bin mir ziemlich sicher, dass die Breite der Checkbox gleich
int x = GetSystemMetrics( SM_CXMENUCHECK );
int y = GetSystemMetrics( SM_CYMENUCHECK );
Sie können dann in den Bereich trainieren, indem Sie die folgende Subtraktion ...
int xInner = GetSystemMetrics( SM_CXEDGE );
int yInner = GetSystemMetrics( SM_CYEDGE );
Ich benutze das in meinem Code und haben kein Problem bisher hatte ...
Dieser Code funktioniert nicht auf Win7 mit skalierten UI (Fonts 125% größer oder 150% größer). Das einzige, was zu funktionieren scheint, ist:
int WID = 13 * dc.GetDeviceCaps(LOGPIXELSX) / 96;
int HEI = 13 * dc.GetDeviceCaps(LOGPIXELSY) / 96;
Es ist eine Schande, dass Microsoft keine Möglichkeit, dies sicher zu wissen vorsah. Ich war mit der gleichen Frage zu kämpfen und die Antwort zur Verfügung gestellt oben ist nicht vollständig. Das Hauptproblem dabei ist, dass, wenn die Schriftart des Dialogfensters auf etwas anderes als die Standardgröße festgelegt ist, wird diese Lösung nicht funktionieren, da Kontrollkästchen wird die Größe verändert werden.
Hier ist, wie ich dieses Problem gelöst (es ist nur eine Annäherung, die für mich gearbeitet zu haben scheint). Der Code ist für MFC-Projekt.
1 - Erstellen Sie zwei Testkontrollen auf dem Formular, eine Checkbox und Radio-Box:

2 - Legen Sie die folgende benutzerdefinierte Struktur:
struct CHECKBOX_DIMS{
int nWidthPx;
int nHeightPx;
int nSpacePx; //Space between checkbox and text
CHECKBOX_DIMS()
{
nWidthPx = 0;
nHeightPx = 0;
nSpacePx = 0;
}
};
3 - Rufen Sie den folgenden Code ein, wenn das Formular für jeden der Testkontrollen initialisiert (das wird sie, um sie zu messen und entfernen, so dass der Endnutzer sie scheint nicht):
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 - Jetzt können Sie leicht jedes Kontrollkästchen oder Radio-Box der Größe dieses durch den Aufruf:
//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;
}
Kurze Antwort:

Lange Version
Von MSDN Layoutspezifikationen: Win32 , haben wir die Spezifikationen der Abmessungen einer Checkbox.
Es ist 12 Dialogeinheiten von der linken Kante der Steuerung an den Anfang des Textes:

Und eine Checkbox Steuerung ist 10 Dialogeinheiten groß:
Surfaces and Controls Height (DLUs) Width (DLUs)
===================== ============= ===========
Check box 10 As wide as possible (usually to the margins) to accommodate localization requirements.
Zunächst berechnen wir die Größe einer horizontalen und einer vertikalen Dialogeinheit:
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);
Mit Hilfe der handliche Helfer-Funktion:
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;
}
Jetzt , da wir wissen , wie viele Pixel ( checkboxSpacing) hinzufügen, berechnen wir die Etikettengröße als 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;

Hinweis : Jeder Code in Public Domain freigegeben. Keine Zuordnung erforderlich.
Ok Jungs meine Art und Weise ist vielleicht nicht die schnellsten im laufenden Betrieb zu verwenden, aber es funktioniert für mich auf jeden Fall die ich bisher getestet haben. Im beginnin meiner proggys legte ich in einer Funktion, um die Größe zu erhalten und speichern sie in einer globalen Variablen (ja ich gehört habe, das schlecht wäre, aber ich interessiere mich nicht über diese)
hier, um die Erklärung:
- Erstellen Sie eine treeview (unsichtbar, wenn u wollen)
- Erstellen Sie eine Bildliste mit atleast 1 Bild nach innen (Größe 16x16)
- Stellen Sie die Bildliste zur Baum-Ansicht ( „TVSIL_NORMAL“)
- Holen Sie sich die „TVSIL_STATE“ Bildliste von Strukturansichts (u haben zu schaffen „TVSIL_NORMAL“ vor, andernfalls wird man nicht!)
- Verwenden Sie ImageList_GetIconSize (..) und speichern Sie die Größe. Wow, die checkboxs und die Radio-Tasten haben die gleiche Größe wie die Statussymbole der treeview. Nun u haben, was u wollen!
- Zerstören Sie die „TVSIL_NORMAL“ Imagelist
- Zerstören Sie die treeview
Dieser Code muss nur wenige Mikrosekunden am Anfang meiner proggies und ich kann den Wert jedes Mal wenn ich es brauche verwenden.
Präambel:
Ich hatte die gleiche Frage bei dem Versuch , die benötigte Größe der Checkbox Steuerung für einen bestimmten Text zu ermitteln und festgestellt , dass die vorhandenen Antworten wirklich für mich nicht funktioniert hat , aus mehreren Gründen:
SM_CXMENUCHECKberücksichtigt nicht die Lücke. In der Tat bin ich davon überzeugt, das nicht auch für regelmäßige Kontrollkästchen ist, obwohl sie den gleichen Wert haben. Es kann auch davon abhängig sein, visuelle Stile aktiviert werden.- Die anderen Antworten waren übermäßig kompliziert und fühlte mich ein bisschen hacky (keine Respektlosigkeit bestimmt, ist es MS, die machen das einfach nicht).
- Das erklärte 12DLU Layout war sehr hilfreich, wenn auch wieder willkürlich fühlt sich ohne ein System Metrik zu verlassen.
- Die Antworten, die ich immer noch versucht, nicht hoch genug Pixelwert ergeben die Checkbox Text von Verpackung zu stoppen.
Meine Untersuchung:
Ich sah , wie Wein reproduziert das Verhalten und stellte fest , dass es auch die gleichen Ergebnisse wie einfach vorausgesetzt 12DLU gibt. Allerdings wickelte der Text immer noch , wenn ich weitere 3 Pixel der Breite hinzugefügt (auch wenn der Text ohne passen fein sollte). Ich habe auch bemerkt , dass GetTextExtentPoint32ein Wert von 3 für einen leeren String ergibt (hmmm ...)
das Ausschalten BS_MULTILINEStil offensichtlich den Textumbruch gestoppt. Meine Vermutung ist , dass DrawTextW‚s Zeilenumbruch Berechnungen unvollkommen sind.
An dieser Stelle habe ich beschlossen , dass die einfachste Lösung war, nur 1 zusätzlichen Platz in dem GetTextExtentPoint32, so dass es auf jeden Fall genug Pixel sein würde. Die Überschätzung von ein paar Pixeln war mir akzeptabel.
Beachten Sie, dass diese alle Ihre Anwendung übernimmt als DPI bewusst manifestiert. Ansonsten fand ich die Checkbox auf einigen Windows-7-Systemen viel größer erschienen (nicht alle aber).
Meine (meist Wine) Lösung:
// 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 für diesen alten Thread wieder zu beleben. Vor kurzem fand ich frage mich, über die genau die gleiche Frage. Derzeit keine der Antworten über ein Ergebnis, das mit dem Windows 10 für verschiedene Schriftarten und Schriftgrößen geben, vor allem in High-DPI-Umgebungen.
Stattdessen scheint es, dass das richtige Ergebnis erhalten wird durch
SIZE szCheckBox;
GetThemePartSize(hTheme, hDC, BP_CHECKBOX, CBS_UNCHECKEDNORMAL, &rcBackgroundContent, TS_TRUE, &szCheckBox);
für die Größe der Checkbox selbst. Und
SIZE szZeroCharacter;
GetTextExtentPoint32(hDC, L"0", 1, &szZeroCharacter);
int iGapWidth = szZeroCharacter.cx / 2;
für die Breite des Spalts. Nach dem Versuch , über eine Menge verschiedener Methoden inspiriert von den Pfosten, fand ich L"0"in der dissembly von comctl32.dll. Und während es wie ein Witz mir (nicht unbedingt ein guter) sieht, vermute ich , es ist ein Überbleibsel aus den alten Zeiten , als könnte dies eine gute genug Angleichung des 2DLU gewesen.
Haftungsausschluss: Während ich das Ergebnis mit verschiedenen Schriftarten und verschiedenen Größen auf Windows 10 getestet, ich habe versucht, nicht zu bestätigen, dass es auch auf einem anderen (älteren) Version des Betriebssystems hält.