Πώς να πάρει το μέγεθος του ελέγχου και κενό πλαίσιο ελέγχου;

ψήφοι
12

Έχω ένα πλαίσιο ελέγχου που θέλω να μετρηθεί με ακρίβεια ώστε να μπορώ να τοποθετήσετε ελέγχους σε διάλογο σωστά. Μπορώ να μετρήσει εύκολα το μέγεθος του κειμένου για τον έλεγχο - αλλά δεν ξέρω το «επίσημο» τρόπο υπολογισμού του μεγέθους του πλαισίου ελέγχου και το κενό πριν (ή μετά) το κείμενο.

Δημοσιεύθηκε 22/07/2009 στις 13:18
πηγή χρήστη
Σε άλλες γλώσσες...                            


7 απαντήσεις

ψήφοι
12

Είμαι απόλυτα βέβαιος ότι το πλάτος του πλαισίου ελέγχου είναι ίση με

int x = GetSystemMetrics( SM_CXMENUCHECK );
int y = GetSystemMetrics( SM_CYMENUCHECK );

Στη συνέχεια μπορείτε να ασκηθείτε την περιοχή μέσα αφαιρώντας τα εξής ...

   int xInner = GetSystemMetrics( SM_CXEDGE );
   int yInner = GetSystemMetrics( SM_CYEDGE );

Μπορώ να χρησιμοποιήσω αυτό τον κωδικό μου και δεν είχα πρόβλημα μέχρι στιγμής ...

Απαντήθηκε 22/07/2009 στις 13:53
πηγή χρήστη

ψήφοι
0

Αυτός ο κωδικός δεν λειτουργεί σε Win7 με κλίμακα UI (γραμματοσειρές 125% μεγαλύτερη ή 150% μεγαλύτερο). Το μόνο πράγμα που φαίνεται να λειτουργεί είναι:

int WID = 13 * dc.GetDeviceCaps(LOGPIXELSX) / 96; 
int HEI = 13 * dc.GetDeviceCaps(LOGPIXELSY) / 96;
Απαντήθηκε 20/12/2011 στις 11:02
πηγή χρήστη

ψήφοι
1

Είναι κρίμα που η 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;
}
Απαντήθηκε 09/06/2013 στις 03:06
πηγή χρήστη

ψήφοι
7

Σύντομη απάντηση:

εισάγετε περιγραφή της εικόνας εδώ

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;

εισάγετε περιγραφή της εικόνας εδώ

Σημείωση : Κάθε κωδικός που τίθενται σε δημόσιο τομέα. Δεν απαιτείται απόδοση.

Απαντήθηκε 04/01/2014 στις 21:27
πηγή χρήστη

ψήφοι
0

Εντάξει dudes ο τρόπος μου δεν είναι ίσως οι fastes για χρήση σε χρόνο εκτέλεσης, αλλά λειτουργεί για μένα σε κάθε περίπτωση έχω δοκιμαστεί μέχρι σήμερα. Στο beginnin της proggys μου έβαλα σε λειτουργία για να πάρει το μέγεθος και αποθηκεύστε το σε μια καθολική μεταβλητή (ναι έχω ακούσει κάτι τέτοιο θα ήταν κακό, αλλά i dont φροντίδα γι 'αυτό)

εδώ να την εξήγηση:

  1. Δημιουργήστε ένα treeview (αόρατη αν και θέλουν)
  2. Δημιουργήστε μια ImageList με atleast 1 εικόνα μέσα (μέγεθος 16x16)
  3. Ρυθμίστε το ImageList στο treeview ( "TVSIL_NORMAL")
  4. Αποκτήστε το «TVSIL_STATE» ImageList από το treeview (u πρέπει να δημιουργήσει «TVSIL_NORMAL» πριν, διαφορετικά αυτό θα αποτύχει!)
  5. Χρησιμοποιήστε ImageList_GetIconSize (..) και αποθηκεύστε το μέγεθος. Πω πω, οι checkboxs και τα πλήκτρα ραδιόφωνο έχει το ίδιο μέγεθος με τις κρατικές εικόνες του treeview. Τώρα u ό, τι θες!
  6. Καταστρέψτε το «TVSIL_NORMAL» ImageList
  7. Καταστρέψτε το treeview

αυτός ο κώδικας χρειάζεται μόνο μερικά μικροδευτερόλεπτα στην αρχή της proggies μου και μπορώ να χρησιμοποιήσω την κάθε φορά αξία το χρειάζομαι.

Απαντήθηκε 29/11/2015 στις 18:09
πηγή χρήστη

ψήφοι
0

Προοίμιο:
Είχα την ίδια ερώτηση, ενώ προσπαθεί να καθορίσει την απαιτούμενη μέγεθος του ελέγχου πλαίσιο ελέγχου για ένα συγκεκριμένο κείμενο και διαπίστωσε ότι οι υπάρχουσες απαντήσεις δεν λειτουργούν πραγματικά για μένα, για διάφορους λόγους:

  • 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);
Απαντήθηκε 14/12/2016 στις 17:46
πηγή χρήστη

ψήφοι
1

Συγγνώμη για την ανάσταση αυτό το παλιό το νήμα. Βρήκα πρόσφατα τον εαυτό μου να αναρωτιέται για το ίδιο ακριβώς θέμα. Επί του παρόντος, καμία από τις απαντήσεις παραπάνω δίνουν ένα αποτέλεσμα σύμφωνο με τα 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, δεν έχω προσπαθήσει να εξακριβώσει ότι ισχύει και για οποιαδήποτε άλλη (παλαιότερη) έκδοση του λειτουργικού συστήματος.

Απαντήθηκε 17/12/2019 στις 18:00
πηγή χρήστη

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more