Hogyan juthat mérete ellenőrzés és rés négyzetet?

szavazat
12

Van egy négyzetet, hogy szeretnék, hogy pontosan mérjük, így tudok elhelyezni ellenőrzések egy párbeszédablak helyesen. Én könnyen mérni a szöveg méretét a vezérlő -, de nem tudom, a „hivatalos” számítási módja a méret a négyzetet, és a rés előtt (vagy után) a szövegben.

A kérdést 22/07/2009 13:18
a forrás felhasználó
Más nyelveken...                            


7 válasz

szavazat
12

Biztos vagyok benne, a szélessége a négyzetet egyenlő

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

Ezután dolgozza ki a területen belül, kivonva a következő ...

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

Tudom használni, hogy a kód, és nem volt probléma eddig ...

Válaszolt 22/07/2009 13:53
a forrás felhasználó

szavazat
0

Ez a kód nem működik Win7 a skálázott UI (betűtípus 125% -kal nagyobb, illetve 150% -kal nagyobb). Az egyetlen dolog, ami úgy tűnik, működik is:

int WID = 13 * dc.GetDeviceCaps(LOGPIXELSX) / 96; 
int HEI = 13 * dc.GetDeviceCaps(LOGPIXELSY) / 96;
Válaszolt 20/12/2011 11:02
a forrás felhasználó

szavazat
1

Szégyen, hogy a Microsoft nem nyújt olyan módon, hogy tudja ezt, az biztos. Én küzd ugyanazzal a kérdés és a válasz fentiekben nem teljes. A fő probléma az, hogy ha a font a párbeszéd ablak van beállítva, hogy valami más, mint az alapértelmezett méret, ez a megoldás nem fog működni, mert a négyzeteket lesz kicsinyítve.

Itt van, hogyan oldotta meg ezt a kérdést (ez csak közelítés, amely úgy tűnik, hogy nekem dolgozott). A kód az MFC projekt.

1 - Készítsen két vizsgálati ellenőrzések az űrlap, egy négyzetet és egy rádió box:

írja kép leírása itt

2 - Adjuk meg a következő egyéni struct:

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

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

3 - Hívd a következő kódot, amikor forma inicializálja az egyes vizsgálati kontrollok (ami méri őket, és távolítsa el őket úgy, hogy a végfelhasználók nem tűnnek őket):

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 - Most könnyen átméretezni bármilyen négyzetet vagy rádiós doboz hívja ezt:

//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;
}
Válaszolt 09/06/2013 03:06
a forrás felhasználó

szavazat
7

Rövid válasz:

írja kép leírása itt

Long verzió

MSDN Layout adatok: Win32 , mi az előírások a méreteit négyzetet.

Ez 12 dialógus egység a bal szélén a vezérlést a kezdete a szöveg:

írja kép leírása itt

És egy kapcsolót vezérlő 10 dialógus egység magas:

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

Először kiszámítjuk a mérete egy vízszintes és egy függőleges párbeszéd egység:

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

A praktikus segítő funkció:

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

Most, hogy tudjuk, hány pixel ( checkboxSpacing), hogy adjunk, kiszámítjuk a címke méretét a szokásos módon:

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;

írja kép leírása itt

Megjegyzés : Bármely kód bocsátott közkincs. Nincs forrásmegjelölés szükséges.

Válaszolt 04/01/2014 21:27
a forrás felhasználó

szavazat
0

Ok srácok én utam talán nem a fastes használni runtime, de nekem működik minden esetben Kipróbáltam eddig. A beginnin én proggys tettem be a funkciót, hogy a méret és tárolja egy globális változó (igen én hallottam ezt a rossz lenne, de én dont care erről)

Itt a magyarázat:

  1. Hozzon létre egy treeview (láthatatlan, ha u akar)
  2. Hozzon létre egy Imagelist atleast 1 kép belsejében (méret 16x16)
  3. Állítsa be a Imagelist a treeview ( "TVSIL_NORMAL")
  4. Szerezd meg a „TVSIL_STATE” Imagelist a treeview (u kell létrehozni „TVSIL_NORMAL” előtt, különben ez sikertelen lesz!)
  5. Használja ImageList_GetIconSize (..), és tárolja a méret. Wow, a checkboxs és a rádió-gomb azonos méretű, mint az állam ikonjai treeview. Most u van, amit u akar!
  6. Elpusztítani a „TVSIL_NORMAL” Imagelist
  7. Megsemmisíti a treeview

ezt a kódot igényel csak néhány ezredmásodperc elején én proggies és tudom használni az értéket Everytime I szüksége van rá.

Válaszolt 29/11/2015 18:09
a forrás felhasználó

szavazat
0

Preambulum:
Ugyanez volt a kérdés, miközben megpróbálja meghatározni a szükséges méret a négyzetet ellenőrzés egy adott szöveget, és megállapította, hogy a meglévő válaszok nem igazán működik nekem, több okból is:

  • SM_CXMENUCHECKnem veszi figyelembe a különbség. Tény, hogy nem vagyok meggyőződve arról, ez még a rendszeres négyzeteket, bár lehet, hogy ugyanaz az érték. Az is lehet, függ a vizuális stílusok vannak engedélyezve.
  • Az egyéb válaszok voltak túlságosan bonyolult, és úgy érezte, egy kicsit hacky (nem tiszteletlenség tervezett, akkor az MS, hogy ezt ne tegye könnyű).
  • A megadott 12DLU elrendezés nagyon hasznos volt, bár ismét úgy érzi, önkényes nélkül rendszer metrikus támaszkodni.
  • A válaszok Próbáltam mindig nem kaptunk elég magas pixelérték megállítani a négyzetet szöveg tördelése.

Saját vizsgálat:
megnéztem, hogyan Wine átveszi a viselkedését, és úgy találta, hogy ez is ad ugyanazt az eredményt, mint egyszerűen feltételezve 12DLU. A szöveg azonban még csomagolva, ha nem adunk további 3 pixel szélességének (bár a szöveg illeszkedjen finom nélkül). Azt is észrevettem, hogy GetTextExtentPoint32értéket kapunk 3 üres string (hmmm ...)
kikapcsolása BS_MULTILINEstílus nyilván megállt a szöveg tördelése. Saját hiszem , hogy DrawTextW„s szótördelést számítások nem tökéletes.
Ezen a ponton úgy döntöttem, hogy a legegyszerűbb megoldás az volt, hogy csak adjunk hozzá 1 extra helyet GetTextExtentPoint32, úgyhogy biztosan lesz elég képpont. A túlzott becslés pár pixel elfogadható volt számomra.

Megjegyzendő, hogy ez minden feltételezi az alkalmazás nyilvánul DPI tisztában. Egyébként találtam a négyzetet sokkal nagyobbnak tűnt, bizonyos Windows 7 rendszerek (nem minden bár).

Saját (többnyire A bor) oldat:

// 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);
Válaszolt 14/12/2016 17:46
a forrás felhasználó

szavazat
1

Elnézést feltámadó ezt a régi téma. Nemrég találtam magam kíváncsi a pontosan ugyanezt a kérdést. Jelenleg sem a választ a fenti eredmények is összhangban a Windows 10 különböző betűtípusok és méretek, különösen a magas DPI környezetben.

Ehelyett úgy tűnik, hogy a helyes eredményt kapunk

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

A méret a négyzetet is. És

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

A rés szélességét. Miután megpróbálta sok különböző módszerek által inspirált üzenetét fent találtam L"0"az dissembly COMCTL32.DLL. És bár úgy néz ki, mint egy vicc, hogy nekem (nem feltétlenül jó egy), gyanítom, hogy ez egy holdover a régi időkben, amikor ez lett volna elég jó közelítése 2DLU.

Fontos: Bár teszteltem az eredményt a különböző betűtípusok és különböző méretű Windows 10, én még nem próbálta ellenőrizni, hogy ez is tart bármely más (régebbi) változata az operációs rendszer.

Válaszolt 17/12/2019 18:00
a forrás felhasználó

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