背景
我正在开发一个 C++/MFC 应用程序,我们已经将其转换为显示 unicode 字符以支持外语。在大多数情况下,这是成功的并且 unicode 字符显示正确。但我遇到了一个问题,某些控件上的某些文本被截断。
Example
在这里,您可以看到一个应该显示“ログuaト/终了”的按钮,但被切断并在其位置显示未知字符。
但如果我用空格填充字符串,它会显示正常。所需的空格数量因字符串而异。该字符串需要4个空格才能正确显示,而另一个少一个字符的字符串则需要5个空格;似乎与所需空间的数量没有相关性或模式。而且,我不想在整个代码中随机填充字符串,特别是当其他语言根本不需要它时。
我尝试过的(不起作用)
- 缩小字体大小
- 调整控件大小
- 更改字体名称
- 更改字体字符集
- 从应用程序中不存在此问题的另一个控件复制控件属性
- 添加额外的空终止符
- 使用零宽度字符填充
- 使用SetWindowTextW
- 更改源和执行字符集
- 更改系统区域设置
我发现唯一有效的方法是填充任意数量的空格,这当然不是理想的解决方案。
其他信息
- 我只注意到日语字符的这个问题,但只测试了英语、德语和日语。
- 日语字符使用 3 个字节的数据,我怀疑这与此有关,但我不知道是什么或为什么。英语字符使用 1 个字节,某些德语字符使用 2 个字节。
- 一个地方的控件(按钮/标签/等)可能会出现问题,而位于不同位置且包含相同文本的控件则不会出现问题,即使它们都是按钮等。
- 当文本被截断时,它通常会在末尾显示一个问号框(如第一张图像)或一个随机字符/字母。每次运行应用程序时,该字符都会发生变化,但问题框是最常见的。
- 对于我的填充“修复”,空格位于字符串的开头还是结尾并不重要,只要空格数量足够即可。它也不需要是空格,任何非零宽度字符都可以。
- 使用 MBCS(多字节字符集)编译并启用 Windows 10 UTF-8 Unicode 支持设置。 (与使用定义的 UNICODE 进行编译相反,这不是一个选项。大型旧代码库)
EDIT:这是如何设置文本的示例
GetDlgItem(IDC_SOME_CTRL_ID)->SetWindowText(GetTranslation("Some String"));
其中 GetTranslation() 是我们自己的函数,用于查找“Some String”的翻译(基本上是一个查找表)并返回一个 CString。使用调试器我可以看到返回的 CString 始终具有正确的字符串值。我可以用硬编码的日语字符串替换 GetTranslation,但问题仍然会发生。
EDIT 2:我收到抱怨说这段代码不够。
myapp.rc
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
#include "afxres.h"
#undef APSTUDIO_READONLY_SYMBOLS
IDD_VIEW_MENU DIALOGEX 0, 0, 50, 232
STYLE DS_SETFONT | WS_CHILD
FONT 14, "Verdana", 0, 0, 0x1
BEGIN
CONTROL "btn0",IDC_BUTTON_MENU_0,"Button",BS_3STATE | BS_PUSHLIKE,12,38,25,13
END
#endif
资源.h
#define IDC_BUTTON_MENU_0 6040
视图菜单.cpp
#include "stdafx.h"
#include "ViewMenu.h"
CViewMenu::CViewMenu() : CFormView(CViewMenu::IDD)
{
}
void CViewMenu::DoDataExchange(CDateExchange* pDX)
{
CFormView::DoDataExchange(pDX);
DDX_Control(pDX, IDC_BUTTON_MENU_0, m_ctrlMenuButton0);
}
void CViewMenu::OnInitialUpdate()
{
CFormView::OnInitialUpdate();
}
void CViewMenu::OnDraw(CDC* pDC)
{
CFormView::OnDraw(pDC);
GetDlgItem(IDC_BUTTON_MENU_0)->SetWindowText("ログアウト/終了");
return;
}
查看菜单.h
#include "resource.h"
class CViewMenu : public CFormView
{
protected:
CViewMenu();
public:
enum { IDD = IDD_VIEW_MENU };
CButton m_ctrlMenuButton0;
}