2009-07-22 31 views
11

Tôi có một hộp kiểm mà tôi muốn đo chính xác để tôi có thể định vị các điều khiển trên hộp thoại chính xác. Tôi có thể dễ dàng đo kích thước của văn bản trên điều khiển - nhưng tôi không biết cách "chính thức" tính toán kích thước của hộp kiểm và khoảng cách trước (hoặc sau) văn bản.Làm thế nào để có được kích thước của kiểm tra và khoảng cách trong hộp kiểm?

Trả lời

12

Tôi chắc rằng chiều rộng của hộp kiểm tương đương với

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

Sau đó bạn có thể làm việc ra khu vực bên trong bằng cách trừ đi sau ...

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

tôi sử dụng trong mã của tôi và chưa có sự cố ...

+0

Dường như làm việc tốt cho tôi :) (? Odd như thế nào đó là "kiểm tra menu" và không có một lựa chọn cho một hộp kiểm tra thường xuyên) –

+1

tôi biết đó là một chủ đề cũ, tôi đã tìm thấy nó qua Google. Thật không may câu trả lời này không hoàn toàn chính xác. Xem giải thích của tôi dưới đây ... – c00000fd

0

Mã này không hoạt động trên Win7 với giao diện người dùng được chia tỷ lệ (phông chữ lớn hơn 125% hoặc lớn hơn 150%). Điều duy nhất dường như hoạt động là:

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

Thật đáng tiếc là Microsoft không cung cấp cách để biết điều này chắc chắn. Tôi đã đấu tranh với cùng một câu hỏi và câu trả lời được cung cấp ở trên chưa hoàn chỉnh. Vấn đề chính với nó là nếu phông chữ của cửa sổ hộp thoại được đặt thành một cái gì đó khác với kích thước mặc định, giải pháp đó sẽ không hoạt động vì các hộp kiểm sẽ được thay đổi kích thước.

Đây là cách tôi giải quyết vấn đề này (nó chỉ là một xấp xỉ mà dường như đã làm việc cho tôi). Mã cho dự án MFC.

1 - Tạo hai điều khiển thử nghiệm trên mẫu của bạn, một hộp kiểm và một hộp radio:

enter image description here

2 - Xác định cấu trúc tùy chỉnh sau:

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

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

3 - Gọi đến sau mã khi biểu mẫu khởi tạo cho từng điều khiển kiểm tra (sẽ đo lường chúng và loại bỏ chúng để người dùng cuối dường như không có chúng):

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 - Bây giờ bạn có thể dễ dàng thay đổi kích thước bất kỳ hộp kiểm hoặc radio hộp bằng cách gọi này:

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

Câu trả lời ngắn:

enter image description here

Version dài

Từ MSDN Layout Specifications: Win32, chúng tôi có thông số kỹ thuật về kích thước của hộp kiểm.

Đó là 12 đơn vị thoại từ cạnh trái của điều khiển để bắt đầu của văn bản:

enter image description here

Và một điều khiển hộp kiểm là 10 đơn vị thoại cao:

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

Trước tiên, chúng tôi tính toán kích thước của đơn vị hộp thoại ngang và dọc:

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

Sử dụng chức năng helper ích:

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

Bây giờ chúng ta biết có bao nhiêu pixel (checkboxSpacing) để thêm, chúng tôi tính toán kích thước nhãn như bình thường:

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

Lưu ý: Bất kỳ mã nào được phát hành vào miền công cộng. Không yêu cầu ghi nhận tác giả.

0

Ok dudes cách của tôi có thể không phải là fastes để sử dụng trong thời gian chạy, nhưng nó hoạt động cho tôi trong mọi trường hợp tôi đã thử nghiệm cho đến nay. Trong sự bắt của proggys của tôi đưa vào một chức năng để có được kích thước và lưu nó trong một biến toàn cục (yeah tôi đã nghe nói đây sẽ là xấu, nhưng tôi không quan tâm về điều này)

đây giải thích:

  1. Tạo một treeview (vô hình nếu u muốn)
  2. Tạo một imagelist với ít nhất 1 hình ảnh bên trong (kích thước 16x16)
  3. Đặt imagelist vào treeview ("TVSIL_NORMAL")
  4. Lấy "TVSIL_STATE" imagelist từ treeview (u phải tạo ra " TVSIL_NORMAL "trước đây, nếu không điều này sẽ thất bại!)
  5. Sử dụng ImageList_GetIconSize (..) và lưu trữ kích thước. Ồ, các hộp kiểm và các nút radio có cùng kích thước với các biểu tượng trạng thái của ảnh treeview. Bây giờ bạn có những gì bạn muốn!
  6. Phá hủy "TVSIL_NORMAL" imagelist
  7. Phá hủy treeview

mã này chỉ cần một vài micro vào đầu proggies của tôi và tôi có thể sử dụng mọi giá trị tôi cần nó.

0

Preamble:
Tôi có cùng một câu hỏi trong khi cố gắng để xác định kích thước cần thiết của việc kiểm soát hộp kiểm cho một văn bản nhất định và phát hiện ra rằng câu trả lời hiện không thực sự làm việc cho tôi, vì nhiều lý do:

  • SM_CXMENUCHECK không tính đến khoảng trống. Trong thực tế, tôi không thuyết phục điều này là ngay cả đối với các hộp kiểm thông thường, mặc dù nó có thể có cùng giá trị. Nó cũng có thể phụ thuộc vào phong cách trực quan được kích hoạt.
  • Các câu trả lời khác quá phức tạp và cảm thấy một chút khó khăn (không tôn trọng dự định, đó là MS mà không làm cho điều này dễ dàng).
  • Bố cục 12DLU đã nêu là rất hữu ích, mặc dù lại cảm thấy tùy ý mà không có số liệu hệ thống dựa vào.
  • Câu trả lời tôi đã thử vẫn không mang lại giá trị pixel đủ cao để ngăn văn bản hộp kiểm khỏi gói.

Điều tra của tôi:
Tôi đã xem cách Wine tái tạo hành vi và nhận được kết quả tương tự như giả định 12DLU. Tuy nhiên, văn bản vẫn được bao bọc trừ khi tôi thêm 3 pixel vào chiều rộng (mặc dù văn bản phải vừa vặn mà không có). Tôi cũng nhận thấy rằng GetTextExtentPoint32 mang lại giá trị là 3 cho một chuỗi trống (hmmm ...)
Tắt kiểu BS_MULTILINE rõ ràng là đã dừng gói văn bản. My guess là các tính toán gói từ DrawTextW là không hoàn hảo.
Tại thời điểm này, tôi quyết định rằng giải pháp đơn giản nhất là chỉ thêm 1 khoảng trống cho GetTextExtentPoint32, để chắc chắn sẽ có đủ pixel. Tôi đã ước tính quá mức một vài pixel.

Lưu ý rằng tất cả điều này giả định rằng ứng dụng của bạn được thể hiện dưới dạng DPI. Nếu không, tôi thấy hộp kiểm xuất hiện lớn hơn nhiều trên một số hệ thống Windows 7 (không phải tất cả).

My (chủ yếu là rượu của) giải pháp:

// 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); 
Các vấn đề liên quan