Как получить размер проверки и устранения пробелов в флажке?

голоса
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 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

Короткий ответ:

введите описание изображения здесь

Длинная версия

Из 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;
}

Теперь, когда мы знаем , сколько пикселей ( 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

Ok чуваки мой путь может быть, а не fastes для использования во время выполнения, но это работает для меня в любом случае я испытал до сих пор. В beginnin моих proggys я поставил в функцию, чтобы получить размер и сохранить его в глобальной переменной (да я слышал, это было бы плохо, но я не забочусь об этом)

здесь объяснение:

  1. Создать TreeView (невидимый, если и хотят)
  2. Создание ImageList с по крайней мере 1 изображение внутри (размер 16x16)
  3. Установите ImageList в TreeView ( "TVSIL_NORMAL")
  4. Получить «TVSIL_STATE» ImageList с TreeView (и должны создать «TVSIL_NORMAL» прежде, в противном случае это один потерпит неудачу!)
  5. Используйте ImageList_GetIconSize (..) и хранить размер. Ничего себе, что checkboxs и-переключатели имеют один и тот же размер, что и государственные иконы TreeView. Теперь у вас, что у хочу!
  6. Уничтожить «TVSIL_NORMAL» ImageList
  7. Уничтожить TreeView

Этот коду нужна лишь несколько микросекунд в начале моего proggies и я могу использовать значение каждый раз мне это нужно.

Ответил 29/11/2015 в 18:09
источник пользователем

голоса
0

Преамбула: у
меня был тот же вопрос, пытаясь определить необходимый размер элемента управления CheckBox для данного текста и обнаружил , что существующие ответы на самом деле не работает для меня, по нескольким причинам:

  • SM_CXMENUCHECKне учитывает разрыв. На самом деле, я не уверен, что это даже для обычных флажков, хотя он может иметь такое же значение. Он также может зависеть от визуальных стилей быть включен.
  • Другие ответы были слишком сложными и чувствовали себя немного Hacky (не неуважения предназначенного, то MS, не делает это легко).
  • Поставленная расположение 12DLU было очень полезно, хотя опять чувствует себя произвольно без системы метрики полагаться на.
  • Ответы я пытался до сих пор не дал достаточно высокое значения пикселя, чтобы остановить текст флажка из упаковки.

Мое исследование:
Я смотрел на то, как вино воспроизводит поведение и обнаружил , что он также дает те же результаты, просто предполагая 12DLU. Тем не менее, текст все еще обернута , пока я не добавил дополнительные 3 пикселя по ширине (даже при том , что текст должен соответствовать хорошо и без). Я также заметил , что GetTextExtentPoint32дает значение 3 для пустой строки (хммм ...)
Выключение BS_MULTILINEстиль явно остановил перенос текста. Моя догадка в том , что DrawTextW«s слово расчеты упаковка несовершенны.
В этот момент я решил , что самое простое решение было просто добавить 1 дополнительное пространство GetTextExtentPoint32, так что, несомненно , будет достаточно пикселей. Переоценивать пары пикселей было приемлемо для меня.

Обратите внимание, что все это предполагает приложение проявляется как 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