¿Cómo obtener el tamaño del cheque y el espacio en la casilla de verificación?

votos
12

Tengo una casilla de verificación que quiero medir con precisión para poder colocar los controles en un cuadro de diálogo correctamente. Puedo medir fácilmente el tamaño del texto en el control, pero no conozco la forma oficial de calcular el tamaño de la casilla de verificación y el espacio antes (o después) del texto.

Publicado el 22/07/2009 a las 13:18
fuente por usuario
En otros idiomas...                            


7 respuestas

votos
12

Estoy bastante seguro de que el ancho de la casilla de verificación es igual a

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

A continuación, puede calcular el área interior restando lo siguiente ...

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

Lo uso en mi código y no he tenido ningún problema hasta ahora ...

Respondida el 22/07/2009 a las 13:53
fuente por usuario

votos
0

Este código no funciona en Win7 con la interfaz de usuario reducido (fuentes 125% más grande o 150% más grande). Lo único que parece funcionar es:

int WID = 13 * dc.GetDeviceCaps(LOGPIXELSX) / 96; 
int HEI = 13 * dc.GetDeviceCaps(LOGPIXELSY) / 96;
Respondida el 20/12/2011 a las 11:02
fuente por usuario

votos
1

Es una pena que Microsoft no proporcionó una manera de saber a ciencia cierta. He tenido problemas con la misma pregunta y la respuesta proporcionada anteriormente no es completa. El principal problema con esto es que si la fuente de la ventana de diálogo se establece en algo que no sea el tamaño predeterminado, esa solución no funcionará porque serán redimensionadas casillas de verificación.

He aquí cómo lo solucionó este problema (que es sólo una aproximación que parece haber funcionado para mí). El código es para el proyecto MFC.

1 - Crear dos controles de prueba en su forma, una casilla de verificación y una caja de radio:

introducir descripción de la imagen aquí

2 - Definir la siguiente estructura personalizada:

struct CHECKBOX_DIMS{
    int nWidthPx;
    int nHeightPx;
    int nSpacePx;       //Space between checkbox and text

    CHECKBOX_DIMS()
    {
        nWidthPx = 0;
        nHeightPx = 0;
        nSpacePx = 0;
    }
};

3 - llamar al código siguiente al formulario inicializa para cada uno de los controles de prueba (que medirlas y eliminarlos de modo que los usuarios finales no parecen ellos):

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 - Ahora se puede cambiar el tamaño fácilmente cualquier casilla de verificación o caja de radio llamando a esto:

//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;
}
Respondida el 09/06/2013 a las 03:06
fuente por usuario

votos
7

Respuesta corta:

introducir descripción de la imagen aquí

Versión larga

De MSDN formato de las especificaciones: Win32 , tenemos las especificaciones de las dimensiones de una casilla de verificación.

Es 12 unidades de diálogo desde el borde izquierdo del control al inicio del texto:

introducir descripción de la imagen aquí

Y un control de casilla de verificación es de 10 unidades de diálogo de altura:

Surfaces and Controls  Height (DLUs)  Width (DLUs)
=====================  =============  ===========
Check box              10             As wide as possible (usually to the margins) to accommodate localization requirements.

En primer lugar se calcula el tamaño de una horizontal y vertical de una unidad de diálogo:

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);

Utilizando la función auxiliar útil:

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

Ahora que sabemos que el número de píxeles ( checkboxSpacing) para añadir, calculamos el tamaño de la etiqueta de forma 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;

introducir descripción de la imagen aquí

Nota : Cualquier código liberado al dominio público. No se requiere la atribución.

Respondida el 04/01/2014 a las 21:27
fuente por usuario

votos
0

tipos ok mi camino no es tal vez los fastes a utilizar en tiempo de ejecución, pero funciona para mí en cualquier caso que he probado hasta ahora. En el beginnin de mis proggys puse en una función para obtener el tamaño y almacenarlo en una variable global (sí he oído esto sería malo, pero no me importa sobre esto)

Aquí la explicación:

  1. Crear una vista de árbol (invisible si quieres)
  2. Crear una lista de imágenes con al menos 1 imagen en el interior (16x16 tamaño)
  3. Establecer la lista de imágenes a la vista de árbol ( "TVSIL_NORMAL")
  4. Obtener la lista de imágenes "TVSIL_STATE" de la vista de árbol (u tiene que crear "TVSIL_NORMAL" antes, de lo contrario éste fallará!)
  5. Utilice ImageList_GetIconSize (..) y almacenar el tamaño. Vaya, los checkboxs y los botones de radio tienen el mismo tamaño que los iconos de estado de la vista de árbol. Ahora u tiene lo que quiere u!
  6. Destruir la lista de imágenes "TVSIL_NORMAL"
  7. Destruir la vista de árbol

este código sólo necesita unos pocos microsegundos al comienzo de mis proggies y puedo utilizar el valor cada vez que lo necesite.

Respondida el 29/11/2015 a las 15:09
fuente por usuario

votos
0

Preámbulo:
Yo tenía la misma pregunta al tratar de determinar el tamaño necesario del control de casilla de verificación de un texto dado y se encontró que las respuestas existentes no funcionan realmente para mí, por varias razones:

  • SM_CXMENUCHECKno da cuenta de la diferencia. De hecho, no estoy convencido de que esto es incluso para casillas de verificación regulares, aunque puede tener el mismo valor. También puede depender de que se habilitan los estilos visuales.
  • Las otras respuestas eran demasiado complicado y se sentía un poco hacky (sin faltarle el respeto empleo, no es MS que no hacen tan fácil).
  • La disposición 12DLU declarado era muy útil, aunque de nuevo se siente arbitraria sin un sistema métrico que confiar.
  • Las respuestas que he intentado todavía no dió un valor de píxel lo suficientemente alto como para detener el texto de la casilla de envolver.

Mi investigación:
Yo miraba cómo el vino reproduce el comportamiento y se encontró que también da los mismos resultados que simplemente asumiendo 12DLU. Sin embargo, el texto todavía envuelto a menos que añadí un extra de 3 píxeles a la anchura (a pesar de que el texto debe encajar bien sin). También he notado que GetTextExtentPoint32produce un valor de 3 para una cadena vacía (hmmm ...)
Apagar el BS_MULTILINEestilo, obviamente, se detuvo el ajuste de texto. Mi conjetura es que DrawTextW's cálculos de envoltura de palabras son imperfectos.
En este punto decidí que la solución más sencilla era simplemente agregar 1 espacio extra para GetTextExtentPoint32, para que no hubiera duda será suficientes píxeles. La sobre-estimación de un par de píxeles era aceptable para mí.

Tenga en cuenta que todo esto supone que su aplicación se manifiesta como DPI conscientes. De lo contrario, me encontré con la casilla de verificación apareció mucho mayor en algunos sistemas de Windows 7 (no todos, aunque).

Mi solución (en su mayoría del Vino):

// 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);
Respondida el 14/12/2016 a las 14:46
fuente por usuario

votos
1

Lo siento por la resurrección de este viejo hilo. Recientemente me encontré pensando en exactamente la misma pregunta. Actualmente, ninguna de las respuestas anteriores dan un resultado consistente con Windows 10 para diferentes fuentes y tamaños de fuente, especialmente en entornos de alto DPI.

En cambio, parece que el resultado correcto se obtiene por

SIZE szCheckBox;
GetThemePartSize(hTheme, hDC, BP_CHECKBOX, CBS_UNCHECKEDNORMAL, &rcBackgroundContent, TS_TRUE, &szCheckBox);

para el tamaño de la propia casilla de verificación. Y

SIZE szZeroCharacter;
GetTextExtentPoint32(hDC, L"0", 1, &szZeroCharacter);
int iGapWidth = szZeroCharacter.cx / 2;

para el ancho de la brecha. Después de probar un montón de diferentes métodos inspirados en los puestos de arriba, me encontré L"0"en el dissembly de comctl32.dll. Y si bien se ve como una broma para mí (no necesariamente una buena), sospecho que es un vestigio de los viejos tiempos en que esto podría haber sido una buena aproximación suficiente de 2DLU.

Renuncia: Si bien he probado el resultado con diversas fuentes y tamaños diferentes en Windows 10, no he tratado de comprobar que también lleva a cabo en cualquier otra versión (viejo) del sistema operativo.

Respondida el 17/12/2019 a las 18:00
fuente por usuario

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