win32 - 如何在文本字符串周围绘制一个矩形?

6
我是新手,正在尝试使用C++编写基于GDI的代码(由于技术原因不想使用GDI+)。
编辑:简化问题:
我需要在窗口中央绘制文本周围的矩形。 - 如何填充矩形坐标? - 谁能帮忙解决这一行 - Rectangle(x1,y1,x2,y2)?如何计算这些(x1,y1)和(x2,y2)值?
谢谢。
        hdc = BeginPaint(hWnd, &ps);
    GetClientRect(hWnd, &rcClient);
    SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT));
    SetTextColor(hdc, RGB(255, 0, 0));

    DrawText(hdc, wstring(s.begin(),s.end()).c_str(), -1, &rectResult, DT_SINGLELINE | DT_CALCRECT);

    DrawText(hdc, wstring(s.begin(),s.end()).c_str(), -1, &rcClient, DT_SINGLELINE | DT_CENTER | DT_VCENTER);

    // Here I need help - How to I place the rectangle around the Text - which is drawn in the middle of the window?
    // It looks like need to use - rectResult.bottom/top/left/right - but don't know how.. 
    Rectangle(hdc, 0,0,100,100);   

1
G.Y - 同意这更像是一项家庭作业 - 但由于我相对新于win32编程 - 并且基于我所读到的 - 需要创建一个临时的基于内存的DC来计算文本的大小/宽度 - 在这个线程中找到了大部分答案,但不知道如何创建一个临时的DC来执行此任务。即使只是一个被矩形包围的单个文本 - 我也可以进一步扩展它 - http://stackoverflow.com/questions/1835749/win32-text-drawing-puzzle - ejuser
1
这是我目前为止的最小版本代码(适用于单个文本): case WM_PAINT: hdc = BeginPaint(hWnd, &ps); GetClientRect(hWnd, &rcClient); SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT)); SetTextColor(hdc, RGB(255, 0, 0)); DrawText(hdc, wstring(s.begin(),s.end()).c_str(), -1, &rcClient, DT_SINGLELINE | DT_CENTER | DT_VCENTER); // TODO: 在此处添加任何绘图代码... EndPaint(hWnd, &ps); break; - ejuser
1
阅读以下所有内容: http://www.functionx.com/win32/Lesson10.htm https://dev59.com/5VnUa4cB1Zd3GeqPXBSo 最重要的是: http://msdn.microsoft.com/en-us/library/windows/desktop/dd145203(v=vs.85).aspx - G.Y
1
感谢G.Y.提供的链接(其中一条是GDI+,我想避免使用它)。如果您或其他人能够提供一个绘制文本在窗口中心并用矩形环绕它的代码片段,我将非常感激-之所以要求矩形是因为它可以让我更好地理解文字像素计算,澄清很多事情。目前正在进一步探索... 谢谢! - ejuser
1
您可以通过单击问题下方的[编辑]链接,然后按照我们的格式说明(橙色?图标)发布代码。与传统论坛不同,Stack Overflow 鼓励您添加问题和答案的信息,而不是留下一堆评论。 - Cody Gray
显示剩余7条评论
3个回答

12
您实际上不必自己将文本居中。如果您传递适当的标志,GDI文本输出函数可以为您完成这项工作。
例如,如果您调用DrawText并传递DT_CENTER标志,它将自动在指定矩形的中心绘制文本(水平居中)。
假设您只有一行文本(听起来像是这样),您可以通过传递DT_SINGLELINEDT_VCENTER标志来使其自动垂直居中文本。
所以您真正需要做的就是编写代码将您窗口的客户区分成4个等分,并将这些矩形传递给DrawText函数。这并不是非常困难的。如果您无法在脑海中想象,请用铅笔和纸尝试一下。
void PaintWindow(HWND hWnd)
{
   // Set up the device context for drawing.
   PAINTSTRUCT ps;
   HDC hDC = BeginPaint(hWnd, &ps);
   HPEN hpenOld = static_cast<HPEN>(SelectObject(hDC, GetStockObject(DC_PEN)));
   HBRUSH hbrushOld = static_cast<HBRUSH>(SelectObject(hDC, GetStockObject(NULL_BRUSH)));

   // Calculate the dimensions of the 4 equal rectangles.
   RECT rcWindow;
   GetClientRect(hWnd, &rcWindow);

   RECT rc1, rc2, rc3, rc4;
   rc1 = rc2 = rc3 = rc4 = rcWindow;

   rc1.right  -= (rcWindow.right - rcWindow.left) / 2;
   rc1.bottom -= (rcWindow.bottom - rcWindow.top) / 2;

   rc2.left   = rc1.right;
   rc2.bottom = rc1.bottom;

   rc3.top   = rc1.bottom;
   rc3.right = rc1.right;

   rc4.top  = rc1.bottom;
   rc4.left = rc1.right;

   // Optionally, deflate each of the rectangles by an arbitrary amount so that
   // they don't butt up right next to each other and we can distinguish them.
   InflateRect(&rc1, -5, -5);
   InflateRect(&rc2, -5, -5);
   InflateRect(&rc3, -5, -5);
   InflateRect(&rc4, -5, -5);

   // Draw (differently-colored) borders around these rectangles.
   SetDCPenColor(hDC, RGB(255, 0, 0));    // red
   Rectangle(hDC, rc1.left, rc1.top, rc1.right, rc1.bottom);
   SetDCPenColor(hDC, RGB(0, 255, 0));    // green
   Rectangle(hDC, rc2.left, rc2.top, rc2.right, rc2.bottom);
   SetDCPenColor(hDC, RGB(0, 0, 255));    // blue
   Rectangle(hDC, rc3.left, rc3.top, rc3.right, rc3.bottom);
   SetDCPenColor(hDC, RGB(255, 128, 0));  // orange
   Rectangle(hDC, rc4.left, rc4.top, rc4.right, rc4.bottom);

   // Draw the text into the center of each of the rectangles.
   SetBkMode(hDC, TRANSPARENT);
   SetBkColor(hDC, RGB(0, 0, 0));   // black
   // TODO: Optionally, set a nicer font than the default.
   DrawText(hDC, TEXT("Hello World!"), -1, &rc1, DT_CENTER | DT_SINGLELINE | DT_VCENTER);
   DrawText(hDC, TEXT("Hello World!"), -1, &rc2, DT_CENTER | DT_SINGLELINE | DT_VCENTER);
   DrawText(hDC, TEXT("Hello World!"), -1, &rc3, DT_CENTER | DT_SINGLELINE | DT_VCENTER);
   DrawText(hDC, TEXT("Hello World!"), -1, &rc4, DT_CENTER | DT_SINGLELINE | DT_VCENTER);

   // Clean up after ourselves.
   SelectObject(hDC, hpenOld);
   SelectObject(hDC, hbrushOld);
   EndPaint(hWnd, &ps);
}

 


谢谢Cody。你的假设关于单行是正确的。这确实有帮助。不知道是否已知(X,Y)坐标 - 可以将文本围绕它居中(而不是矩形)?想象一下 - 为此需要计算文本高度和宽度 - 以围绕(X,Y)居中?(对于这个问题我很抱歉,因为我实际上正在尝试找到围绕(x,y)(垂直和水平)居中文本的解决方案)。谢谢。 - ejuser
@ejuser 如果您知道坐标,可以创建一个填充了它们的RECT结构,并将其传递给DrawText。是的,如果您想要计算文本字符串所需的宽度和高度,可以自己计算。为此,您将使用GetTextExtentPoint32,就像我在问题中提到的那样。这比让Windows为您完成更多的工作。有关更多信息,请参见此处 - Cody Gray
谢谢Cody。我会进一步探索并回复 - 希望能够根据您提供的提示解决这个问题。 - ejuser
使用正常的方法解决了这个问题并进行了进一步的探索。有谁能帮忙告诉如何在评论栏下发布“格式化”的代码(是否可能?)- 放弃并将格式化的代码发布为答案,因为那似乎是我能找到的唯一发表格式化代码的方法。 - ejuser
@ejuser 使用反引号来进行内联代码格式化,无论是在注释还是常规帖子中。像这样:` ` 但是你不会得到语法高亮或换行,所以只适用于非常短的片段。如果你的回答实际上是对问题的回答,那么发布一个答案是正确的选择。否则,如果它只是关于问题的更多信息,你应该编辑问题。:-) - Cody Gray
当设置hbrushOld时,应该使用GetStockObject(DC_BRUSH)而不是GetStockObject(NULL_BRUSH)来检索当前DC画刷句柄,对吗? - DocKimbel

1
RECT rect={0,0,0,0};
const char *str="Test Text";
DrawText(hDC, str, strlen(str), &rect, DT_CALCRECT | DT_NOCLIP);
Rectangle(hDC,rect.left,rect.top,rect.right,rect.bottom);
DrawText(hDC, str, strlen(str), &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE|DT_NOCLIP);

1

终于搞定了 :) 非常感谢Cody Gray指引我正确的方向 :)

GetTextExtentPoint32(hDC, str, strlen(str), &sz2); 
rect2.top=rect2.bottom+sz2.cy;
rect2.right=rect2.top+sz2.cx;
Rectangle(hDC,rect2.left,rect2.top,rect2.right,rect2.bottom);
DrawText(hDC, str, -1, &rect2, DT_CENTER | DT_VCENTER | DT_SINGLELINE|DT_NOCLIP);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接