在图形用户界面(GUI)开发中,经常会遇到文本绘制的问题。当文本内容超出了显示区域,如何优雅地处理这种情况,是提升用户体验的关键。一种常见的做法是在文本末尾添加省略号(…),以表示文本被截断。本文将介绍一种实现这一功能的方法,通过自定义DrawTextEx函数来实现文本的绘制与省略号的添加。
在Windows操作系统中,列表视图控件(list view control)在报表模式(report mode)下,如果文本单元格(text cells)的宽度不足以显示全部文本,通常会在末尾添加省略号(...)。然而,要模拟这种行为并不简单,尤其是在不使用MFC(Microsoft Foundation Classes)的情况下。
本文提出的解决方案简单直接,旨在保持桌面版本DrawText函数的精神。首先,需要提供一个额外的标志位:DT_MODIFYSTRING。这个标志位的作用是告知函数,字符串允许在原地进行修改。如果开发者没有提供这个标志位,函数将不会对字符串进行任何原地修改,也不会显示省略号。
在确保开发者理解了这一点之后,函数开始工作。首先计算字符串的长度(如果未提供),以及其在屏幕上的大小。如果字符串的屏幕大小(宽度)大于提供的矩形区域,就需要将其分割,并在末尾添加一个省略号Unicode字符。函数会尝试估计省略号字符的位置,以避免进入一个漫长的试错循环。只有在第一次大小估计比矩形区域的宽度还要宽时,才会进入这个循环。
最后,当带有附加省略号字符的截断字符串能够适应指定的矩形区域时,就可以使用传统的DrawText函数来显示它了。
#define ELLIPSIS ((TCHAR)0x2026)
int DrawTextEx(HDC hDC, LPCTSTR lpString, int nCount, LPRECT lpRect, UINT uFormat) {
if (uFormat & (DT_END_ELLIPSIS | DT_MODIFYSTRING)) {
SIZE szStr;
LPTSTR lpStr = (LPTSTR)lpString;
int nWidth = lpRect->right - lpRect->left;
if (nCount == -1)
nCount = _tcslen(lpStr);
GetTextExtentPoint32(hDC, lpStr, nCount, &szStr);
if (szStr.cx > nWidth) {
int nEstimate = (nCount * nWidth) / szStr.cx + 1;
if (nEstimate < nCount)
nCount = nEstimate;
lpStr[nCount-1] = ELLIPSIS;
GetTextExtentPoint32(hDC, lpStr, nCount, &szStr);
while (szStr.cx > nWidth && nCount > 1) {
lpStr[--nCount] = 0;
lpStr[nCount-1] = ELLIPSIS;
GetTextExtentPoint32(hDC, lpStr, nCount, &szStr);
}
}
uFormat &= ~(DT_END_ELLIPSIS | DT_MODIFYSTRING);
}
return DrawText(hDC, lpString, nCount, lpRect, uFormat);
}