Jak se dostat na velikosti kontrole a mezery v políčko?

hlasů
12

Mám políčko, že chci, aby přesně změřit, abych mohl správně umístit ovládací prvky dialogu. Mohu snadno změřit velikost textu o kontrole - ale nevím, „oficiální“ způsob výpočtu velikosti políčka a mezery před (nebo po) textu.

Položena 22/07/2009 v 13:18
zdroj uživatelem
V jiných jazycích...                            


7 odpovědí

hlasů
12

Jsem si jistý, že šířka políčka se rovná

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

Pak můžete přijít prostoru uvnitř odečtením následující ...

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

Já používám, že v mém kódu a neměli problém tak daleko ...

Odpovězeno 22/07/2009 v 13:53
zdroj uživatelem

hlasů
0

Tento kód nefunguje na Win7 s zmenšen UI (písma 125% větší, nebo 150% větší). Jediná věc, která se zdá fungovat, je:

int WID = 13 * dc.GetDeviceCaps(LOGPIXELSX) / 96; 
int HEI = 13 * dc.GetDeviceCaps(LOGPIXELSY) / 96;
Odpovězeno 20/12/2011 v 11:02
zdroj uživatelem

hlasů
1

Je škoda, že Microsoft neposkytl způsob, jak vědět to určitě. Jsem se snažila se stejnou otázkou a odpovědí je uvedeno výše, není kompletní. Hlavním problémem je, že v případě, že písmo v dialogovém okně je nastaven na jinou hodnotu než výchozí velikost, toto řešení nebude fungovat, protože políčka budou zmenšeny.

Zde je návod, jak jsem vyřešil tento problém (to je jen aproximace, která se zdá, že pracoval pro mě). Kód je pro projekt MFC.

1 - Vytvořte dvě testovací ovládací prvky na formuláři, zaškrtávací políčko a rozhlasové krabice:

zadejte popis obrázku zde

2 - Definujte následující vlastní struct:

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

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

3 - Výzva následující kód, když forma inicializuje pro každý z testovaných kontrol (které je budou měřit a odstranit tak, že koncoví uživatelé se nezdají jim):

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 - Nyní můžete snadno změnit velikost jakékoliv políčko nebo rozhlasový okno voláním toto:

//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;
}
Odpovězeno 09/06/2013 v 03:06
zdroj uživatelem

hlasů
7

Stručná odpověď:

zadejte popis obrázku zde

Long Version

Z MSDN rozvržení Specifikace: Win32 , máme specifikace rozměrů zaškrtávací políčko.

Je to 12 dialogová jednotek od levého okraje ovládacího prvku na začátku textu:

zadejte popis obrázku zde

A kontrolní políčko 10 Dialog Jednotky vysoký:

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

Nejdříve jsme vypočítat velikost vodorovné a svislé dialogové jednotky:

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

Pomocí šikovného pomocníka funkce:

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

Teď, když víme, kolik pixelů ( checkboxSpacing) pro přidání, spočítáme velikost štítku jako obvykle:

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;

zadejte popis obrázku zde

Poznámka : Jakýkoli kód propuštěn do veřejné domény. No uvedením zdroje.

Odpovězeno 04/01/2014 v 21:27
zdroj uživatelem

hlasů
0

Ok dudes moje cesta je možná ne fastes pro použití v běhu, ale funguje to pro mě v každém případě jsem doposud testovaných. V beginnin mých proggys i dát do funkce, aby velikost a uložit jej do globální proměnné (jo jsem slyšel to by bylo špatné, ale já dont starat o to)

Zde vysvětlení:

  1. Vytvořte TreeView (neviditelný-li u potřeba)
  2. Vytvořte ImageList se aspoň jeden obrázek uvnitř (velikost 16x16)
  3. Nastavit ImageList do stromu ( „TVSIL_NORMAL“)
  4. Získejte „TVSIL_STATE“ ImageList ze stromu (u muset vytvořit „TVSIL_NORMAL“ předtím, jinak tohle selže!)
  5. Použít ImageList_GetIconSize (..) a uložte velikosti. Wow, že checkboxs a radio-tlačítka mají stejnou velikost jako státní ikon stromu. Teď u to, co u chtějí!
  6. Zničit „TVSIL_NORMAL“ Imagelist
  7. Zničit TreeView

Tento kód je třeba jen několik mikrosekund na začátku mé proggies a mohu použít hodnotu pokaždé jsem ji potřebují.

Odpovězeno 29/11/2015 v 18:09
zdroj uživatelem

hlasů
0

Preambule:
Měl jsem stejnou otázku, když se snaží určit potřebnou velikost ovládacího prvku políčko u daného textu a zjistil, že stávající odpovědi se opravdu práce pro mě, z několika důvodů:

  • SM_CXMENUCHECKneodpovídá za mezery. Ve skutečnosti nejsem přesvědčen o tom, je to i pro pravidelné políček, i když může mít stejnou hodnotu. To může být také závislý na právě vizuální styly povoleny.
  • Ostatní odpovědi byly příliš složité a cítil trochu hacky (urazit určen, je MS, které nedělají to snadné).
  • Uvedený layout 12DLU bylo velmi užitečné, když se znovu cítí svévolné bez systému metrické spoléhat na.
  • Odpovědi jsem se snažil ještě nepřinesla dost vysokou hodnotu pixelu zastavit text políčka z obalu.

Moje vyšetřování:
Podíval jsem se na to, jak Wine reprodukuje chování a zjistil, že to také dává stejné výsledky jako jen za předpokladu, že 12DLU. Text však stále zabalený pokud jsem přidal další 3 pixelů na šířku (i přesto, že text by měl vešel dobře i bez). Také jsem si všiml, že GetTextExtentPoint32dává hodnotu 3 pro prázdný řetězec (hmmm ...)
Vypnutí BS_MULTILINEstyl zřejmě zastavil obtékání textu. Můj odhad je, že DrawTextWto slovo výpočty balení jsou nedokonalé.
V tomto bodě jsem se rozhodl, že nejjednodušším řešením bylo jen přidat 1 více prostoru pro GetTextExtentPoint32, takže tam určitě dostatek pixelů. Nadměrná odhad pár pixelů byl přijatelný pro mě.

Všimněte si, že to všechno předpokládá, vaše aplikace se projevuje jako DPI vědomi. Jinak jsem našel toto políčko se objevila mnohem větší, u některých systémů Windows 7 (ne všichni ačkoli).

My (většinou Wine) Řešení:

// 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);
Odpovězeno 14/12/2016 v 17:46
zdroj uživatelem

hlasů
1

Omlouvám se za vzkřísit tuhle starou nit. Nedávno jsem zjistil, že jsem přemýšlel o přesně stejnou otázku. V současné době žádná z výše uvedených odpovědí, jejímž výsledkem je konzistentní s Windows 10 různých písem a velikostí písma, zejména v prostředí s vysokou DPI.

Místo toho se zdá, že správný výsledek je získán

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

pro velikost samotného políčko. A

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

na šířku mezery. Poté, co se snaží mnoho různých metod, které mají čerpat z míst výše, jsem našel L"0"v dissembly of Comctl32.dll. A i když to vypadá jako vtip mě (ne nutně dobrý), mám podezření, že je to pozůstatek ze starých časů, kdy by to mohlo být dost dobrý přibližování 2DLU.

Upozornění: I když jsem testoval výsledek s různými fonty a různých velikostí na Windows 10, jsem se pokusil ověřit, že to platí také na všech ostatních (starší) verzi operačního systému.

Odpovězeno 17/12/2019 v 18:00
zdroj uživatelem

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