Comment obtenir la taille de l'enregistrement et de l'écart dans la case à cocher?

voix
12

J'ai une case à cocher que je veux mesurer avec précision afin que je puisse placer des commandes sur une boîte de dialogue correctement. Je peux facilement mesurer la taille du texte sur le contrôle - mais je ne sais pas la façon de calculer la taille « officielle » de la case à cocher et l'écart avant (ou après) le texte.

Créé 22/07/2009 à 13:18
source utilisateur
Dans d'autres langues...                            


7 réponses

voix
12

Je suis sûr que la largeur de la case à cocher est égale à

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

Vous pouvez alors travailler la zone à l'intérieur en soustrayant les éléments suivants ...

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

Je l'utiliser dans mon code et ne l'ai pas eu un problème jusqu'ici ...

Créé 22/07/2009 à 13:53
source utilisateur

voix
0

Ce code ne fonctionne pas sur Win7 avec l'interface utilisateur réduite (polices 125% plus ou 150% plus). La seule chose qui semble fonctionner est:

int WID = 13 * dc.GetDeviceCaps(LOGPIXELSX) / 96; 
int HEI = 13 * dc.GetDeviceCaps(LOGPIXELSY) / 96;
Créé 20/12/2011 à 11:02
source utilisateur

voix
1

Il est dommage que Microsoft n'a pas fourni un moyen de savoir ce pour sûr. Je luttais avec la même question et la réponse fournie ci-dessus n'est pas complète. Le principal problème avec c'est que si la police de la fenêtre de dialogue est réglé sur autre chose que la taille par défaut, cette solution ne fonctionnera pas parce que les cases seront redimensionnées.

Voici comment je résolu cette question (il est juste une approximation qui semble avoir travaillé pour moi). Le code est pour le projet MFC.

1 - Créer deux commandes de test sur votre formulaire, une case à cocher et une boîte de radio:

entrez la description d'image ici

2 - Définir le struct personnalisé suivant:

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

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

3 - Composez le code suivant lorsque le formulaire pour chacun des initialise les contrôles de test (qui les mesurer et de les supprimer afin que les utilisateurs finaux ne les ont pas l'air):

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 - Maintenant, vous pouvez facilement redimensionner une case à cocher ou case radio en appelant ceci:

//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;
}
Créé 09/06/2013 à 03:06
source utilisateur

voix
7

Réponse courte:

entrez la description d'image ici

Version longue

A partir de MSDN mise en page Spécifications: Win32 , nous avons les spécifications des dimensions d'une case à cocher.

Il est 12 unités de dialogue à partir du bord gauche du contrôle au début du texte:

entrez la description d'image ici

Et un contrôle de case à cocher est de 10 unités de dialogue de haut:

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

D'abord, nous calculons la taille d'une horizontale et une unité de dialogue verticale:

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

En utilisant la fonction d'assistance pratique:

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

Maintenant que nous savons combien de pixels ( checkboxSpacing) pour ajouter, on calcule la taille de l' étiquette comme normale:

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;

entrez la description d'image ici

Remarque : Tout code publié dans le domaine public. Aucune attribution nécessaire.

Créé 04/01/2014 à 21:27
source utilisateur

voix
0

Ok dudes mon chemin est peut-être pas Fastes à utiliser dans l'exécution, mais il fonctionne pour moi en tout cas, je l'ai testé jusqu'à présent. Dans le beginnin de mes proggys je mets dans une fonction pour obtenir la taille et le stocker dans une variable globale (ouais j'ai entendu ce serait mauvais, mais je ne garde à ce sujet)

Voici l'explication:

  1. Créer un TreeView (invisible si tu veux)
  2. Créer un imagelist avec atleast une image à l'intérieur (taille 16x16)
  3. Réglez le imagelist au TreeView ( "TVSIL_NORMAL")
  4. Obtenez le « TVSIL_STATE » imagelist du TreeView (u doivent créer « TVSIL_NORMAL » avant, sinon celui-ci échouera!)
  5. Utilisez ImageList_GetIconSize (..) et stocker la taille. Wow, les checkboxs et les boutons radio-ont la même taille que les icônes d'état de l'arborescence. Maintenant u ont ce que tu veux!
  6. Détruire le imagelist « de TVSIL_NORMAL »
  7. Détruire le TreeView

ce code n'a besoin que de quelques microsecondes au début de mes proggies et je peux utiliser la valeur à chaque fois que je en ai besoin.

Créé 29/11/2015 à 18:09
source utilisateur

voix
0

Préambule:
J'ai eu la même question tout en essayant de déterminer la taille nécessaire du contrôle de case à cocher pour un texte donné et a constaté que les réponses existantes ne fonctionnent pas vraiment pour moi, pour plusieurs raisons:

  • SM_CXMENUCHECKne tient pas compte de l'écart. En fait, je ne suis pas convaincu que c'est même régulièrement des cases à cocher, bien qu'il puisse avoir la même valeur. Il peut aussi dépendre des styles visuels sont activés.
  • Les autres réponses étaient trop compliquées et se sentait un peu hacky (pas vouloir manquer de respect, il est MS qui ne font pas facile).
  • La mise en page 12DLU dit était très utile, bien qu'encore une fois se sent arbitraire sans système métrique à compter.
  • Les réponses que j'essayées n'a toujours pas donné une valeur de pixel suffisante pour arrêter le texte de la case d'emballage.

Mon enquête:
Je regarde comment le vin reproduit le comportement et a constaté qu'il donne également les mêmes résultats que simplement supposer 12DLU. Cependant, le texte encore enveloppé à moins que j'ajouté un 3 pixels supplémentaires à la largeur (même si le texte doit tenir bien sans). J'ai aussi remarqué que GetTextExtentPoint32donne une valeur de 3 pour une chaîne vide (hmmm ...)
Mise hors BS_MULTILINEstyle est arrêté évidemment l'emballage de texte. Mon estimation est que DrawTextW« les calculs d'emballage de mots s sont imparfaits.
A ce stade , j'ai décidé que la solution la plus simple était d'ajouter seulement 1 espace supplémentaire pour GetTextExtentPoint32, de sorte qu'il y aurait certainement assez de pixels. La surévaluation d'un couple de pixels était acceptable pour moi.

Notez que tout cela suppose que votre demande se manifeste aussi au courant DPI. Sinon, je trouve la case à cocher est apparue beaucoup plus sur certains systèmes Windows 7 (pas tous cependant).

Mon (la plupart du temps de vin) solution:

// 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);
Créé 14/12/2016 à 17:46
source utilisateur

voix
1

Désolé pour ressusciter ce vieux fil. Je me suis récemment trouvé interroger sur la même question. À l'heure actuelle, aucune des réponses ci-dessus donnent un résultat cohérent avec Windows 10 pour différentes polices et tailles de police, en particulier dans des environnements de haute DPI.

Il semble plutôt que l'on obtient le résultat correct par

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

pour la taille de la case à cocher lui-même. Et

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

pour la largeur de la fente. Après avoir essayé beaucoup de différentes méthodes inspirées par les postes ci - dessus, je trouve L"0"dans le désassemblage de comctl32.dll. Et alors qu'il ressemble à une blague pour moi (pas nécessairement un bon), je pense qu'il est un vestige de l'époque où cela aurait pu être une assez bonne approximation de 2DLU.

Avertissement: Alors que je l'ai testé le résultat avec différentes polices et de tailles différentes sur Windows 10, je ne l'ai pas essayé de vérifier qu'elle détient aussi une autre version (plus) du système d'exploitation.

Créé 17/12/2019 à 18:00
source utilisateur

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