如何在checkbox中获取支票和差额的大小?

我有一个checkbox,我想准确测量,所以我可以正确地在一个对话框上的位置控件。 我可以很容易地测量控件上文本的大小 – 但我不知道计算checkbox大小和文本之前(或之后)空白的“官方”方式。

Solutions Collecting From Web of "如何在checkbox中获取支票和差额的大小?"

我很确定复选框的宽度是相等的

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

然后你可以通过减去以下内容来计算出里面的区域…

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

我在我的代码中使用,迄今没有问题…

简短的回答:

在这里输入图像说明

长版本

从MSDN 布局规格:Win32 ,我们有一个复选框的尺寸规格。

从控件的左边缘到文本的开头是12个对话单位

在这里输入图像说明

而一个复选框控件是10个对话单位高:

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

首先我们计算一个水平和垂直对话单元的大小:

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

使用便利的帮手功能:

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

现在我们知道要添加多少像素( checkboxSpacing ),我们按照正常的方式计算标签大小:

 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; 

在这里输入图像说明

注意 :任何代码发布到公共领域。 不需要归属

微软并没有提供一种确切的方式来了解这一点,这真是一个耻辱。 我在同一个问题上挣扎,上面提供的答案不完整。 它的主要问题是,如果对话窗口的字体设置为默认大小以外的东西,该解决方案将无法工作,因为复选框将被调整大小。

以下是我如何解决这个问题(这只是一个似乎已经为我工作的近似)。 代码是为MFC项目。

1 – 在您的表单,复选框和收音机框上创建两个测试控件:

在这里输入图像说明

2 – 定义下面的自定义结构:

 struct CHECKBOX_DIMS{ int nWidthPx; int nHeightPx; int nSpacePx; //Space between checkbox and text CHECKBOX_DIMS() { nWidthPx = 0; nHeightPx = 0; nSpacePx = 0; } }; 

3 – 当表单初始化为每个测试控件(这将测量它们,并删除它们,使最终用户似乎不是他们)时,调用以下代码:

 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 – 现在你可以通过调用这个来轻松调整任何复选框或者收音机的大小:

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

此代码不适用于Win7的缩放UI(字体大125%或大150%)。 似乎工作的唯一的事情是:

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

好吧,我的方式可能不是在运行时使用的fastes,但对我来说,无论如何,我已经测试到目前为止。 在我的proggys的开始,我把一个函数来获取大小和存储在一个全局变量(是的,我听说这将是坏的,但我不在乎这一点)

这里的解释是:

  1. 创建一个树形图(如果你想要的话不可见)
  2. 创建一个imagelist里面至少有1个图像(大小16×16)
  3. 将图像列表设置为树视图(“TVSIL_NORMAL”)
  4. 从treeview中获取“TVSIL_STATE”图像列表(你必须先创建“TVSIL_NORMAL”,否则这个会失败!)
  5. 使用ImageList_GetIconSize(..)并存储大小。 哇,复选框和单选按钮的大小与树状图的状态图标相同。 现在你有你想要的东西!
  6. 销毁“TVSIL_NORMAL”图片列表
  7. 销毁树形视图

这个代码在我的proggies开始时只需要几微秒,我可以每次使用它的值。

前言:
在尝试确定给定文本的复选框控件所需的大小时,我遇到了同样的问题,并发现现有的答案对我来说并不真正起作用,原因如下:

  • SM_CXMENUCHECK没有考虑到这个差距。 事实上,我不相信这是甚至对于常规复选框,尽管它可能具有相同的价值。 它也可能依赖于启用的视觉样式。
  • 其他的答案过于复杂,感觉有点不好意思(没有不敬的打算,这是MS不这么容易)。
  • 陈述的12DLU布局是非常有用的,虽然再次感觉是任意的系统度量依赖。
  • 我试过的答案仍然没有产生足够高的像素值来阻止复选框文本的包装。

我的调查:
我看了一下Wine如何重现这种行为,并发现它也与简单地假设12DLU一样给出了相同的结果。 然而,文本仍然包裹,除非我增加了额外的3个像素的宽度(即使文本应该适合罚款没有)。 我也注意到, GetTextExtentPoint32为空字符串(hmmm …)产生一个3的值
关闭BS_MULTILINE样式显然停止了文字换行。 我的猜测DrawTextW的文字换行计算是不完美的。
在这一点上,我决定最简单的解决方案就是给GetTextExtentPoint32添加一个额外的空间,这样肯定会有足够的像素。 高估了几个像素是可以接受的。

请注意,这一切都假定您的应用程序表现为DPI意识。 否则,我发现复选框出现在一些Windows 7系统(但不是所有的)都大得多。

我的(主要是葡萄酒的)解决方案:

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