如何轻松判断当前字体是否支持Unicode字符?

10

我正在使用 Borland C++ Builder 2009,我要展示向右和向左的箭头,代码如下:

Button2->Hint = L"Ctrl+\u2190" ;
Button3->Hint = L"Ctrl+\u2192" ; 

在Windows 7上,这个应用程序使用字体 'Segoe UI' 运行得很好。

在XP上,我得到了一个方块,而不是箭头,我在XP上使用的是字体 'Tahoma'。换句话说,在XP上的Tahoma字体中没有提到的Unicode字符。

是否有一种简单快捷的方法来检查所请求Unicode字符是否支持当前使用的字体?如果是这样,我可以将箭头替换为 '>' 或 '<'。虽然不完美,但已足够。我不想在此阶段开始更改字体。

感谢您的帮助。


这与特定的编程语言无关,而与库有关。由于这些是特定于语言的,您应该提供您实际使用的语言,C或C ++。请注意,绝对没有标准兼容的方法。 - too honest for this site
3
@Olaf,由于C语言的解决方案可以在C++中使用,因此我认为在这种情况下同时使用这两个标签是合适的。它不在标准中并不重要,因为问题显然是关于Windows特定解决方案的,并指定了编译器。 - Mark Ransom
@MarkRansom:C语言和C++语言是不同的。它们有不兼容的语义和特性,而C++语言则没有。至少如果你使用标准的C语言,也就是C11 - 或者至少是C99(C11主要添加了一些特性,但并未改变语义)。如果你的编译器不遵循标准,那么它就是有问题的,或者至少可以被称为过时的。请注意,在Windows上您也可以使用其他编译器。 - too honest for this site
@Olaf,Windows API 是纯 C 的,尽管有 C++ 包装器。大多数 C 兼容的答案在 C++ 中也适用,包括当前带有选中标记的答案。如果问题更多地涉及语言特性或标准库,我可能会倾向于同意你的观点。 - Mark Ransom
@MarkRansom:但反过来则不行。因此,C++标签是错误的。不过,这取决于代码的编译方式。如果编译为C,则不能使用C++功能。实际上,应该有一个标签来表示这两种语言的共同子集(比许多人想象的要小)。 - too honest for this site
2个回答

8
您可以使用GetFontUnicodeRanges()来查看当前选择到DC中的字体支持哪些字符。请注意,此API需要您调用一次以查找缓冲区需要多大,并再次调用以获取实际数据。
DWORD dwSize = GetFontUnicodeRanges(hDC, nullptr);
BYTE* bBuffer = new BYTE[dwSize];
GLYPHSET* pGlyphSet = reinterpret_cast<GLYPHSET*>(bBuffer);
GetFontUnicodeRanges(hDC, pGlyphSet);
// use data in pGlyphSet, then free the buffer
delete[] bBuffer;

GLYPHSET 结构体有一个名为 ranges 的成员数组,可以帮助您确定字体支持的字符范围。


1
你可以使用 std::vector 代替 new/delete 来创建可变大小的缓冲区。 - Mark Ransom
1
抱歉,Peter。我以为你已经有那段代码了。是的,使用 GetDC() 然后将所需字体选择进去。 - Jonathan Potter
1
@Peter 这些是WinAPI的概念,如果你不熟悉它们,恐怕你需要做一些研究(或者也许有人了解c++ builder可以帮助你)。 - Jonathan Potter
1
Canvas->Handle 实际上是我需要获取 GetFontUnicodeRanges() 正常工作所需的 hDC 句柄!现在我已经有了可行的代码,在 W7 和 XP 上都经过确认。谢谢。 - Peter
1
还想指出的是,在 Windows 8.1 和 Windows 10 上,GetFontUnicodeRanges 对我不起作用。它可以处理简单的 Unicode 字符,但此 API 没有包括任何新字符。例如,L'৳'。此外,更简单的 API GetGlyphIndices 似乎也不起作用。因此,如果有人能发布一种更新的解决方法,那就太好了。 - c00000fd
显示剩余5条评论

3

仅供参考和Google搜索引擎:

bool UnicodeCharSupported(HWND Handle, wchar_t Char)
{
if (Handle)
    {
    DWORD dwSize = GetFontUnicodeRanges(Handle, NULL);
    if (dwSize)
        {
        bool Supported = false ;
        BYTE* bBuffer = new BYTE[dwSize];
        GLYPHSET* pGlyphSet = reinterpret_cast<GLYPHSET*>(bBuffer);
        if (GetFontUnicodeRanges(Handle, pGlyphSet))
            {
            for (DWORD x = 0 ; x < pGlyphSet->cRanges && !Supported ; x++)
                {
                Supported = (Char >= pGlyphSet->ranges[x].wcLow &&
                             Char < (pGlyphSet->ranges[x].wcLow + pGlyphSet->ranges[x].cGlyphs)) ;
                }
            }
        delete[] bBuffer;
        return Supported ;
        }
    }
return false ;
}

例如,与我提出的问题相关:

if (!UnicodeCharSupported(Canvas->Handle, 0x2190))
    { /* Character not supported in current Font, use different character */ }

1
当您找到Char的匹配项时,您可能需要考虑从循环中使用break来退出。 - c00000fd

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