How to get size of check and gap in check box?

前端 未结 7 1448
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-12-15 06:46

I have a check box that I want to accurately measure so I can position controls on a dialog correctly. I can easily measure the size of the text on the control - but I don\'

7条回答
  •  悲哀的现实
    2020-12-15 07:14

    It is a shame that Microsoft did not provide a way to know this for sure. I was struggling with the same question and the answer provided above is not complete. The main problem with it is that if the font of the dialog window is set to something other than the default size, that solution will not work because checkboxes will be resized.

    Here's how I solved this issue (it is just an approximation that seems to have worked for me). The code is for MFC project.

    1 - Create two test controls on your form, a checkbox and a radio box:

    enter image description here

    2 - Define the following custom struct:

    struct CHECKBOX_DIMS{
        int nWidthPx;
        int nHeightPx;
        int nSpacePx;       //Space between checkbox and text
    
        CHECKBOX_DIMS()
        {
            nWidthPx = 0;
            nHeightPx = 0;
            nSpacePx = 0;
        }
    };
    

    3 - Call the following code when form initializes for each of the test controls (that will measure them and remove them so that end-users don't seem them):

    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 - Now you can easily resize any checkbox or radio box by calling this:

    //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;
    }
    

提交回复
热议问题