如何在Windows GUI中绘制垂直文本?

8

我需要在我的本地C ++ Win32 GUI应用程序中绘制一列竖排文字(用日语书写 - 它是从上到下绘制而不是从左到右)。我查看了MSDN,只找到如何绘制从右到左的文本。

除了逐个绘制每个字符外,我该如何输出从上到下的文本?

8个回答

7
直接使用 Win32 API 无法以任意字体绘制(未旋转)垂直文本,只能逐个字符绘制。您可以使用 GDI+ 实现更复杂的文本输出,但这也不是您想要的,因为文本将是垂直的,但字符也会旋转。同样地,您可以使用 lfEscapement 值为 900 或 2700 的 CreateFont 获取旋转后的文本,但这会旋转所有内容,因此也没有帮助。要进行日语从上到下的绘制,您需要使字符未旋转,但每个字符的位置在 Y 轴上前进而不是 X 轴。Windows 没有适用于所有字体的 API 进行此操作(您可以进行从右到左和从左到右的绘制,但不能进行从上到下的绘制)。
理论上,创建一个方向为900,逃逸为2700的字体可以实现您想要的效果,但是似乎如果您设置了逃逸,则大多数字体将忽略方向。对于日文字体,可能会有不同的工作方式。值得花些时间去尝试一下(有关此问题的更多信息,请参见附录)。
我认为最好的选择可能是使用ExtTextOut循环逐个字符绘制,并完全控制每个字符的位置。
如果您使用ETO_OPAQUE在列中绘制第一个字符,并且不是所有其他字符,则可以垂直调整字符间距(如果需要)。
附录
Roygbiv指出了一篇有趣的文章,该文章说当您使用CreateFont创建一个具有lfEscapement值为2700的字体时,以@开头命名的字体的行为与其他字体不同,这些特殊字体产生直立的字符,同时向下移动页面。因此,虽然没有办法针对任意字体做到您想要的效果,但是您可以尝试使用某些字体来使其正常工作。

显示文本的选项

出于好奇,我编写了一个小型的控制台应用程序来枚举字体并列出名称。我的 Windows Server 2003 机器上没有以 "@" 开头的字体名称。但是我的 Windows 7 机器上有几个。所有似乎都是中文字体,我在默认的 Windows 7 Ultimate 安装中没有看到任何日文字体。


2
不正确 - Win32 可以做到。请看我的帖子。 - RED SOFT ADAIR

5

正确答案是:

有三种方法可以实现此目的:

  • 使用编辑器或 RichEdit 控件来呈现文本。
  • 使用 Uniscribe API。
  • 使用以符号“@”开头的字体名称的TextOut函数。

这里有一篇文章讨论了这些方法之一。

幸运的是,在Win32中,您不需要编写旋转字符的代码。要在 Windows 2000 和 Windows XP 上垂直显示文本,请像往常一样枚举可用字体,并选择一个字体,其字体名称以符号“@”开头。然后创建一个 LOGFONT 结构,将 escapement 和 orientation 都设置为 270 度。对于水平文本,调用 TextOut 的方式也相同。


4
在Win32中,使用LOGFONT结构的lfEscapement成员来定义字体的旋转:
LOGFONT LogFont

LogFont.lfEscapement = 900;  // 90 degreees rotated text
... // Many more initializations
HFONT newFont = CreateFontIndirect(LogFont);
SelectObject(hdc, newFont);

char tx[255];
strcpy(tx, "vertical text");
TextOut(hdc, x, y, tx, strlen(tx)); // draw a vertical font

更多信息请参阅LOGFONT结构和CreateFontIndirect函数的在线帮助。


请再次阅读问题,旋转字符在这种情况下没有帮助。 - John Knoeller
我收回之前的说法,这个应该可以在某些字体上工作,只是不能在普通的英文字体上。 - John Knoeller

2
HFONT gui_font  =   CreateFont( -MulDiv( 9, GetDeviceCaps( GetDC( hWnd ), LOGPIXELSY ), 72 ),
                        0, 
                        900,  // here
                        0,
                        FW_THIN, 0, 0, 0,
                        DEFAULT_CHARSET,
                        OUT_DEFAULT_PRECIS,
                        CLIP_DEFAULT_PRECIS,
                        DEFAULT_QUALITY, FF_MODERN | FIXED_PITCH,
                        L"Segoe UI" );

1

使用lfEscapement(如果需要,还可以使用lfOrientation)在许多方面优于使矩形最小宽度(例如:荷兰语单词“wij”将具有“i”和“j”相邻,因为它们的组合宽度小于“w”),或在每个字符后插入换行符。


0

0
作为一种快速的解决方案,如果您使用标准控件(例如CEdit)并在每个键入的字符后插入一个换行符,会发生什么?

-1
只是一个想法: 你尝试使用一个非常窄的矩形来适应最宽的字符,使用DrawTextDrawTextEx吗?

1
考虑到日语混合使用汉字、平假名和片假名字符,这听起来似乎不是一个好主意。 - MSalters

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