2009-07-22 17 views

Respuesta

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 de restar el siguiente ...

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

uso que, en mi código y no he tenido ningún problema hasta el momento ...

+0

parece funcionar bien para mí :) (? Odd cómo es "cheque menú" y no es una opción para una casilla de verificación regular) –

+1

I Sé que es un hilo viejo, lo encontré a través de Google. Lamentablemente, esta respuesta no es del todo correcta. Ver mi explicación a continuación ... – c00000fd

0

Este código no funciona en Win7 con UI escalada (fuentes 125% más grandes o 150% más grandes). Lo único que parece funcionar es:

int WID = 13 * dc.GetDeviceCaps(LOGPIXELSX)/96; 
int HEI = 13 * dc.GetDeviceCaps(LOGPIXELSY)/96; 
1

Es una pena que Microsoft no haya proporcionado una forma de saber esto con certeza. Estaba luchando con la misma pregunta y la respuesta proporcionada anteriormente no está completa. El problema principal es que si la fuente de la ventana de diálogo está configurada en un valor diferente al tamaño predeterminado, esa solución no funcionará porque las casillas de verificación se redimensionarán.

Así es como he resuelto este problema (es solo una aproximación que parece haber funcionado para mí). El código es para el proyecto MFC.

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

enter image description here

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 - Llame a la siguiente código cuando el formulario se inicializa para cada uno de los controles de prueba (que los medirá y eliminará para que los usuarios finales no los parezcan):

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 usted puede fácilmente cambiar el tamaño de cualquier cuadro de casilla o radio llamando a este:

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

Respuesta corta:

enter image description here

Versión larga

De MSDN Layout Specifications: Win32, nos tener 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:

enter image description here

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. 

Primero calculamos el tamaño de una unidad de diálogo horizontal y vertical:

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

Uso de la práctica función de ayudante:

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

enter image description here

Nota: Cualquier código publicado en el dominio público. No se requiere atribución.

0

Ok dudes my way es posible que no sean los tiempos de uso en tiempo de ejecución, pero a mí me funciona en cualquier caso que haya 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 la imagen 1 en el interior (16x16 tamaño)
  3. Establecer la lista de imágenes a la vista de árbol ("TVSIL_NORMAL")
  4. obtener el "TVSIL_STATE" lista de imágenes de treeview (tienes que crear " TVSIL_NORMAL "antes, de lo contrario, esta fallara!)
  5. Use ImageList_GetIconSize (..) y almacene el tamaño. Guau, las casillas de verificación y los botones de radio tienen el mismo tamaño que los íconos de estado de la vista de árbol. ¡Ahora tienes lo que quieres!
  6. Destruir al "TVSIL_NORMAL" imagelist
  7. Destruye la vista de árbol

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

0

Preámbulo:
que 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_CXMENUCHECK no da cuenta de la brecha. De hecho, no estoy convencido de que esto sea incluso para casillas de verificación regulares, aunque puede tener el mismo valor. También puede depender de estilos visuales habilitados.
  • Las otras respuestas fueron demasiado complicadas y se sintieron un poco hacky (sin intención de falta de respeto, es MS que no lo hacen fácil).
  • El diseño de 12DLU indicado fue muy útil, aunque nuevamente se siente arbitrario sin una métrica de sistema en la que confiar.
  • Las respuestas que probé todavía no dieron un valor de píxel lo suficientemente alto como para detener el ajuste del texto de la casilla de verificación.

Mi investigación:
Miré a cómo vino reproduce el comportamiento y encontraron que también da los mismos resultados que simplemente asumiendo 12DLU. Sin embargo, el texto todavía está envuelto, a menos que agregue 3 píxeles adicionales al ancho (aunque el texto debería quedar bien sin). También noté que GetTextExtentPoint32 produce un valor de 3 para una cadena vacía (hmmm ...)
Desactivar el estilo BS_MULTILINE obviamente detuvo el ajuste del texto. Mi conjetura es que los cálculos de ajuste de palabras de DrawTextW son imperfectos.
En este punto, decidí que la solución más simple era simplemente agregar 1 espacio adicional a GetTextExtentPoint32, por lo que definitivamente habría suficientes píxeles. La sobreestimación de un par de píxeles fue aceptable para mí.

Tenga en cuenta que todo esto supone que su aplicación se manifiesta como DPI consciente. De lo contrario, me pareció que la casilla de verificación parecía mucho más grande en algunos sistemas con Windows 7 (aunque no todos).

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