Nasıl onay kutusunu kontrol ve boşluk boyutunu almak için?

oy
12

Ben doğru bir iletişim üzerindeki kontrolleri konumlandırmak böylece doğru ölçmek isteyen bir onay kutusu var. Ben kolayca kumanda üzerindeki metnin boyutunu ölçebilir - ama onay kutusunun boyutunu ve metinden önce (veya sonra) fark hesaplan resmi yolunu bilmiyorum.

Oluştur 22/07/2009 saat 13:18
kaynak kullanıcı
Diğer dillerde...                            


7 cevaplar

oy
12

Ben onay kutusunun genişliği eşittir eminim

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

Sonra aşağıdaki çıkarılarak iç bölgeyi çalışabilir ...

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

Benim kodunda kullanan ve bugüne kadar bir sorun olmadı ...

Cevap 22/07/2009 saat 13:53
kaynak kullanıcı

oy
0

Bu kod, ölçekli UI (yazı% 125 daha büyük veya% 150 daha büyük) sahip Win7'de çalışmaz. iş gibi görünüyor tek şey:

int WID = 13 * dc.GetDeviceCaps(LOGPIXELSX) / 96; 
int HEI = 13 * dc.GetDeviceCaps(LOGPIXELSY) / 96;
Cevap 20/12/2011 saat 11:02
kaynak kullanıcı

oy
1

Microsoft bu emin olmanın bir yol sunmadı bir utanç. Ben aynı soruyla mücadele ve yukarıda sağlanan cevap tamamlanmadı. onunla asıl sorun iletişim penceresinin yazı varsayılan boyuttan farklı bir şey olarak ayarlanırsa onay kutuları yeniden ayarlanacak, çünkü o çözüm işe yaramaz olmasıdır.

İşte (bu benim için çalışmış gibi görünüyor sadece bir tahmindir) bu sorunu çözmüş nasıl. kod MFC projesi içindir.

1 - Formunuz, bir onay kutusu ve bir radyo kutusundaki iki test kontrolleri oluşturun:

Burada görüntü açıklama girin

2 - Aşağıdaki özel yapı tanımlayın:

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

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

3 - form test kontrollerin her (onları ölçmek ve son kullanıcılar bunları görünmüyor böylece onları kaldırır) için başlatır aşağıdaki kodu arayın:

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 - Şimdi kolayca bu arayarak herhangi onay kutusunu veya radyo kutusunu yeniden boyutlandırabilirsiniz:

//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;
}
Cevap 09/06/2013 saat 03:06
kaynak kullanıcı

oy
7

Kısa cevap:

Burada görüntü açıklama girin

Uzun versiyon

MSDN itibaren Düzen Özellikler: Win32 , bir onay kutusu boyutlarının özelliklere sahiptir.

Öyle 12 iletişim birimleri metnin başlangıcına kontrolü sol kenarından:

Burada görüntü açıklama girin

Ve bir onay kutusu denetimi 10 iletişim üniteleri boyunda:

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

Önce bir yatay ve dikey iletişim biriminin boyutunu hesaplamak:

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

Kullanışlı yardımcı fonksiyonunu kullanarak:

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

Şimdi kaç piksel (biliyorum checkboxSpacingeklemek için) normal olarak etiket boyutunu hesaplamak:

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;

Burada görüntü açıklama girin

Not : kamu malı olarak yayınlanmıştır Herhangi bir kod. Hiçbir atıfta bulunulması gereklidir.

Cevap 04/01/2014 saat 21:27
kaynak kullanıcı

oy
0

Tamam ahbaplar yolumu belki zamanında kullanmak hızlısı değil, ama o ben şimdiye kadar test ettik her durumda benim için çalışıyor. Benim proggys ait beginnin i boyutunu almak ve (evet ben bu kötü olurdu duymuş, ama bu umurumda değil) genel değişken depolamak için bir işlevde koymak

açıklama Buraya:

  1. (U isterseniz görünmez) bir ağaç oluşturma
  2. en az 1 resim içine (boyut 16x16) ile bir ımagelist oluştur
  3. ağaç ( "TVSIL_NORMAL") için ImageList ayarlayın
  4. ağaç görüntüsü üzerinde "TVSIL_STATE" ImageList alın (u aksi takdirde bu bir başarısız olacaktır, daha önce "TVSIL_NORMAL" oluşturmak zorunda!)
  5. ImageList_GetIconSize (..) kullanın ve boyutunu saklayın. Vay, onay kutularının ve radyo-düğmeleri ağaç devlet simgeleri aynı boyutta. Şimdi u istediğini var!
  6. "TVSIL_NORMAL" ImageList yok
  7. ağaç yok

Bu kod benim proggies başında sadece birkaç mikrosaniye ihtiyacı vardır ve ben gerek değer her şey kullanabilirsiniz.

Cevap 29/11/2015 saat 18:09
kaynak kullanıcı

oy
0

Önsöz:
Ben belirli bir metin için onay kutusu kontrolünün gerekli boyutunu belirlemek için çalışırken aynı soru vardı ve mevcut cevaplar gerçekten çeşitli nedenlerden dolayı, benim için işe yaramadı bulundu:

  • SM_CXMENUCHECKboşluğu dikkate almaz. aynı değere sahip olsa da Aslında, bu düzenli işaret kutusu bile olduğunu ikna olmadım. görsel stiller, etkinleştirme işleminden sonra ayrıca bağımlı olabilir.
  • Diğer cevaplar aşırı karmaşık ve hacky biraz keçe (amaçlanan saygısızlık, bu kolay yapmazlar MS ise).
  • Tekrar güvenmek metrik bir sistem olmadan keyfi hissediyor rağmen belirtilen 12DLU düzen, çok yardımcı oldu.
  • Yeterince yüksek bir piksel değeri elde etmedi hala çalışılan yanıtlar ambalajından onay kutusu metni durdurmak için.

Araştırmam:
Ben Şarap davranışını nasıl yeniden ürettiğini baktı ve aynı zamanda basitçe 12DLU varsayarak aynı sonuçları verdiğini gördük. I (metin olmadan iyi uyması bile) genişliği için fazladan bir 3 piksel ilave edilmedikçe, metin yine tamamladı. Ben de fark ettim GetTextExtentPoint32boş bir dize (hmmm ...) için 3 değerini verir
kapatılması BS_MULTILINEaçıkçası metin kaydırma durduruldu tarzı. Benim tahminim olduğunu DrawTextWs sözcük kaydırma hesaplamalar kusurlu olduğu'.
Bu noktada basit çözüm sadece 1 ekstra alan eklemek olduğuna karar verdi GetTextExtentPoint32kesinlikle yeterli piksel olacağını, böylece. Piksel bir çiftin aşırı tahmini benim için kabul edilebilir.

Bu, tüm uygulama DPI farkında olarak kendini gösterir varsayar. Aksi takdirde onay kutusu bazı Windows 7 sistemlerinde (hepsinde olmasa bile) çok daha büyük göründü buldum.

Benim (çoğunlukla şarap'ın) çözümü:

// 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);
Cevap 14/12/2016 saat 17:46
kaynak kullanıcı

oy
1

Maalesef bu eski iplik diriltmeyi için. Geçenlerde kendimi tam aynı soru hakkında merak buldum. Şu anda, cevapların hiçbiri yukarıda özellikle yüksek DPI ortamlarda farklı yazı tipleri ve yazı tipi boyutları, Windows 10 ile uyumlu bir sonuç verir.

Bunun yerine, doğru sonuç elde edilir gibi görünüyor

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

onay kutusu kendisinin boyutu. Ve

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

boşluğun genişliği için. Yukarıdaki mesajların esinlenerek farklı yöntemlerin bir çok denedikten sonra buldum L"0"dissembly comctl32.dll içinde. Bana bir şaka (şart değil iyi bir) benziyor ederken, ben bu 2DLU yeterince iyi bir yaklaşım olabilir eski günlerden kalmadır şüpheli.

Yasal Uyarı: Windows 10'a çeşitli yazı tipleri ve farklı boyutlarda sonucu test ederken, ben de işletim sisteminin herhangi bir başka (eski) sürümü üzerinde tutan doğrulamak için teşebbüs değil.

Cevap 17/12/2019 saat 18:00
kaynak kullanıcı

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