Έχω ένα πλαίσιο ελέγχου που θέλω να μετρηθεί με ακρίβεια ώστε να μπορώ να τοποθετήσετε ελέγχους σε διάλογο σωστά. Μπορώ να μετρήσει εύκολα το μέγεθος του κειμένου για τον έλεγχο - αλλά δεν ξέρω το «επίσημο» τρόπο υπολογισμού του μεγέθους του πλαισίου ελέγχου και το κενό πριν (ή μετά) το κείμενο.
Πώς να πάρει το μέγεθος του ελέγχου και κενό πλαίσιο ελέγχου;
Είμαι απόλυτα βέβαιος ότι το πλάτος του πλαισίου ελέγχου είναι ίση με
int x = GetSystemMetrics( SM_CXMENUCHECK );
int y = GetSystemMetrics( SM_CYMENUCHECK );
Στη συνέχεια μπορείτε να ασκηθείτε την περιοχή μέσα αφαιρώντας τα εξής ...
int xInner = GetSystemMetrics( SM_CXEDGE );
int yInner = GetSystemMetrics( SM_CYEDGE );
Μπορώ να χρησιμοποιήσω αυτό τον κωδικό μου και δεν είχα πρόβλημα μέχρι στιγμής ...
Αυτός ο κωδικός δεν λειτουργεί σε Win7 με κλίμακα UI (γραμματοσειρές 125% μεγαλύτερη ή 150% μεγαλύτερο). Το μόνο πράγμα που φαίνεται να λειτουργεί είναι:
int WID = 13 * dc.GetDeviceCaps(LOGPIXELSX) / 96;
int HEI = 13 * dc.GetDeviceCaps(LOGPIXELSY) / 96;
Είναι κρίμα που η Microsoft δεν παρέχει έναν τρόπο να το γνωρίζουν αυτό στα σίγουρα. Ήμουν αγωνίζονται με την ίδια ερώτηση και η απάντηση που προβλέπονται παραπάνω δεν είναι πλήρης. Το κύριο πρόβλημα με αυτό είναι ότι αν η γραμματοσειρά του παραθύρου διαλόγου έχει οριστεί σε κάτι άλλο εκτός από το προεπιλεγμένο μέγεθος, η λύση αυτή δεν θα λειτουργήσει, επειδή πλαίσια ελέγχου θα πρέπει να αλλάξει το μέγεθός τους.
Εδώ είναι το πώς θα λυθεί αυτό το ζήτημα (αυτό είναι μόνο μια προσέγγιση που φαίνεται να έχουν εργαστεί για μένα). Ο κωδικός είναι για το έργο MFC.
1 - Δημιουργία δύο ελέγχους δοκιμών στη φόρμα σας, ένα πλαίσιο ελέγχου και ένα κουτί ραδιόφωνο:

2 - Ορίστε τα εξής έθιμο struct:
struct CHECKBOX_DIMS{
int nWidthPx;
int nHeightPx;
int nSpacePx; //Space between checkbox and text
CHECKBOX_DIMS()
{
nWidthPx = 0;
nHeightPx = 0;
nSpacePx = 0;
}
};
3 - Καλέστε τον παρακάτω κωδικό όταν το έντυπο προετοιμάζει για κάθε ένα από τα χειριστήρια ελέγχου (που θα τα μετρήσει και να τα αφαιρέσετε, έτσι ώστε οι τελικοί χρήστες δεν τους φαίνεται):
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 - Τώρα μπορείτε εύκολα να αλλάξετε το μέγεθος κάθε κουτάκι ή το ραδιόφωνο κουτί με την κλήση αυτή:
//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;
}
Σύντομη απάντηση:

Long Έκδοση
Από MSDN Διάταξη Προδιαγραφές: Win32 , έχουμε τις προδιαγραφές των διαστάσεων του πλαισίου ελέγχου.
Είναι 12 διαλόγου μονάδες από το αριστερό άκρο του ελέγχου στην αρχή του κειμένου:

Και ένας έλεγχος πλαίσιο ελέγχου είναι 10 μονάδες διαλόγου ψηλά:
Surfaces and Controls Height (DLUs) Width (DLUs)
===================== ============= ===========
Check box 10 As wide as possible (usually to the margins) to accommodate localization requirements.
Πρώτα υπολογίζουμε το μέγεθος της οριζόντιας και κάθετης μονάδας διαλόγου:
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);
Χρησιμοποιώντας την εύχρηστη λειτουργία βοηθός:
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;
}
Τώρα που ξέρουμε πόσα pixels ( checkboxSpacing) για να προσθέσετε, υπολογίζουμε το μέγεθος της ετικέτας ως συνήθως:
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;

Σημείωση : Κάθε κωδικός που τίθενται σε δημόσιο τομέα. Δεν απαιτείται απόδοση.
Εντάξει dudes ο τρόπος μου δεν είναι ίσως οι fastes για χρήση σε χρόνο εκτέλεσης, αλλά λειτουργεί για μένα σε κάθε περίπτωση έχω δοκιμαστεί μέχρι σήμερα. Στο beginnin της proggys μου έβαλα σε λειτουργία για να πάρει το μέγεθος και αποθηκεύστε το σε μια καθολική μεταβλητή (ναι έχω ακούσει κάτι τέτοιο θα ήταν κακό, αλλά i dont φροντίδα γι 'αυτό)
εδώ να την εξήγηση:
- Δημιουργήστε ένα treeview (αόρατη αν και θέλουν)
- Δημιουργήστε μια ImageList με atleast 1 εικόνα μέσα (μέγεθος 16x16)
- Ρυθμίστε το ImageList στο treeview ( "TVSIL_NORMAL")
- Αποκτήστε το «TVSIL_STATE» ImageList από το treeview (u πρέπει να δημιουργήσει «TVSIL_NORMAL» πριν, διαφορετικά αυτό θα αποτύχει!)
- Χρησιμοποιήστε ImageList_GetIconSize (..) και αποθηκεύστε το μέγεθος. Πω πω, οι checkboxs και τα πλήκτρα ραδιόφωνο έχει το ίδιο μέγεθος με τις κρατικές εικόνες του treeview. Τώρα u ό, τι θες!
- Καταστρέψτε το «TVSIL_NORMAL» ImageList
- Καταστρέψτε το treeview
αυτός ο κώδικας χρειάζεται μόνο μερικά μικροδευτερόλεπτα στην αρχή της proggies μου και μπορώ να χρησιμοποιήσω την κάθε φορά αξία το χρειάζομαι.
Προοίμιο:
Είχα την ίδια ερώτηση, ενώ προσπαθεί να καθορίσει την απαιτούμενη μέγεθος του ελέγχου πλαίσιο ελέγχου για ένα συγκεκριμένο κείμενο και διαπίστωσε ότι οι υπάρχουσες απαντήσεις δεν λειτουργούν πραγματικά για μένα, για διάφορους λόγους:
SM_CXMENUCHECKδεν ευθύνονται για το χάσμα. Στην πραγματικότητα, δεν είμαι πεπεισμένος ότι αυτό είναι ακόμη και για την τακτική πλαίσια ελέγχου, αν και μπορεί να έχουν την ίδια αξία. Μπορεί επίσης να εξαρτάται από οπτικά εφέ που ενεργοποιούνται.- Οι άλλες απαντήσεις ήταν υπερβολικά περίπλοκη και αισθάνθηκε λίγο Hacky (έλλειψη σεβασμού που προορίζονται, είναι τα κράτη μέλη που δεν κάνουν αυτό το εύκολο).
- Το δήλωσε διάταξη 12DLU ήταν πολύ χρήσιμη, αν και πάλι αισθάνεται αυθαίρετα, χωρίς ένα σύστημα μέτρησης για να βασιστείτε.
- Οι απαντήσεις δοκίμασα ακόμα δεν απέδωσε μια αρκετά υψηλή τιμή pixel για να σταματήσει το κείμενο πλαίσιο ελέγχου από το περιτύλιγμα.
Έρευνα μου:
Κοίταξα τον τρόπο Wine αναπαράγει τη συμπεριφορά και διαπίστωσε ότι δίνει τα ίδια αποτελέσματα με απλά υποθέτοντας 12DLU. Ωστόσο, το κείμενο παραμένει τυλιγμένο αν δεν προστεθεί ένα επιπλέον 3 pixels στο πλάτος (έστω και αν το κείμενο θα πρέπει να ταιριάζει μια χαρά χωρίς). Παρατήρησα επίσης ότι GetTextExtentPoint32αποδίδει την τιμή 3 για μια κενή συμβολοσειρά (χμμμ ...)
Απενεργοποίηση του BS_MULTILINEστυλ προφανώς σταμάτησε το αναδίπλωσης κειμένου. Μου εικασία είναι ότι DrawTextW«οι υπολογισμοί περιτυλίγματος s λέξη είναι ατελής.
Στο σημείο αυτό αποφάσισε ότι η πιο απλή λύση ήταν να προσθέσω μόνο 1 επιπλέον χώρο για να GetTextExtentPoint32, έτσι ώστε σίγουρα θα υπάρξουν αρκετά pixels. Η υπερβολική εκτίμηση ενός ζευγαριού των εικονοστοιχείων ήταν αποδεκτή για μένα.
Σημειώστε ότι όλα αυτά προϋποθέτει την εφαρμογή σας εκδηλώνεται ως επίγνωση DPI. Διαφορετικά, βρήκα το πλαίσιο ελέγχου εμφανίστηκε πολύ μεγαλύτερη σε ορισμένα συστήματα Windows 7 (όχι όλα όμως).
(Κυρίως κρασιού) Η λύση μου:
// 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);
Συγγνώμη για την ανάσταση αυτό το παλιό το νήμα. Βρήκα πρόσφατα τον εαυτό μου να αναρωτιέται για το ίδιο ακριβώς θέμα. Επί του παρόντος, καμία από τις απαντήσεις παραπάνω δίνουν ένα αποτέλεσμα σύμφωνο με τα Windows 10 για διαφορετικές γραμματοσειρές και μεγέθη γραμματοσειρών, ειδικά σε περιβάλλοντα υψηλού DPI.
Αντ 'αυτού, φαίνεται ότι το σωστό αποτέλεσμα επιτυγχάνεται με
SIZE szCheckBox;
GetThemePartSize(hTheme, hDC, BP_CHECKBOX, CBS_UNCHECKEDNORMAL, &rcBackgroundContent, TS_TRUE, &szCheckBox);
για το μέγεθος του ίδιου του πλαισίου ελέγχου. Και
SIZE szZeroCharacter;
GetTextExtentPoint32(hDC, L"0", 1, &szZeroCharacter);
int iGapWidth = szZeroCharacter.cx / 2;
για το πλάτος του διακένου. Μετά την προσπάθεια πολλές διαφορετικές μεθόδους εμπνευσμένες από τις παραπάνω θέσεις, βρήκα L"0"στο dissembly του Comctl32.dll. Και ενώ φαίνεται σαν ένα αστείο για μένα (δεν είναι απαραίτητα καλό), υποψιάζομαι ότι είναι μια συνεχιστής από τις παλιές μέρες, όταν αυτό θα μπορούσε να έχει μια αρκετά καλή προσέγγιση της 2DLU.
Αποποίηση: Αν και δοκίμασα το αποτέλεσμα με διάφορες γραμματοσειρές και μεγέθη για τα Windows 10, δεν έχω προσπαθήσει να εξακριβώσει ότι ισχύει και για οποιαδήποτε άλλη (παλαιότερη) έκδοση του λειτουργικού συστήματος.













