问题描述
背景
我正在开发一个 C++/MFC 应用程序,我们一直在将其转换为显示 unicode 字符以支持外语.在大多数情况下,这是成功的,并且 unicode 字符显示正确.但是我遇到了某些控件上的某些文本被截断的问题.
I'm working on a C++/MFC application and we've been converting it to display unicode characters to support foreign languages. For the most part this has been successful and unicode characters are displayed correctly. But I've encountered an issue where certain text on certain controls gets cut off.
示例
在这里你可以看到一个按钮,应该显示ログアウト/终了";但被截断并在其位置显示未知字符.
Here you can see a button that should display "ログアウト/終了" but gets cutoff and displays an unknown character in it's place.
但是如果我用空格填充字符串,它显示正常.所需的空格数因字符串而异.这个字符串需要 4 个空格才能正确显示,而另一个少一个字符的字符串需要 5 个空格;与所需的空格数似乎没有相关性或模式.而且,我不想在整个代码中随机填充字符串,尤其是当其他语言根本不需要它时.
But if I pad the string with spaces it displays fine. The number of spaces needed varies by string. This string needed 4 spaces to display correctly, whereas another string with one less character needed 5 spaces; there doesn't seem to be a correlation or pattern with the number of spaces needed. And also, I don't want to pad strings randomly throughout the code, especially when other languages don't need this at all.
我尝试过的(不起作用)
- 缩小字体大小
- 调整控件大小
- 更改字体名称
- 更改字体字符集
- 从应用程序中没有此问题的另一个控件复制控件属性
- 添加额外的空终止符
- 用零宽度字符填充
- 使用 SetWindowTextW
- 更改源和执行字符集
- 更改系统区域设置
我发现唯一有效的是填充任意数量的空格,这当然不是理想的解决方案.
The only thing I've found that works is padding with an arbitrary amount of spaces which is certainly not an ideal solution.
其他信息
- 我只注意到日语字符有这个问题,但只测试了英语、德语和日语.
- 日语字符使用 3 个字节的数据,我怀疑这与此有关,但我不知道是什么或为什么.英文字符使用 1 个字节,某些德文字符使用 2 个字节.
- 在一个地方的控件(按钮/标签/等)可能有问题,而在不同地方的包含相同文本的控件没有问题,即使它们都是按钮......等.
- 当文本被截断时,它通常会在末尾显示一个问号框(如第一张图片)或一个随机字符/字母.每次我运行应用程序时,这个字符都会改变,但问题框是最常见的.
- 对于我的填充修复",空格是在字符串的开头还是结尾都没有关系,只要空格的数量足够.它也不需要是空格,任何非零宽度字符都可以使用.
- 使用 MBCS(多字节字符集)编译并启用了 Windows 10 UTF-8 Unicode 支持设置.(与使用定义的 UNICODE 编译相反,这不是一个选项.大型旧代码库)
EDIT:这是一个关于如何设置文本的示例
EDIT: Here is an example on how the text is set
GetDlgItem(IDC_SOME_CTRL_ID)->SetWindowText(GetTranslation("Some String"));
其中 GetTranslation() 是我们自己的函数,用于查找Some String"的翻译.(基本上是一个查找表)并返回一个 CString.使用调试器,我可以看到返回的 CString 始终具有正确的字符串值.我可以用硬编码的日语字符串替换 GetTranslation,但问题仍然会发生.
Where GetTranslation() is our own function to look up the translation of "Some String" (basically a lookup table) and return a CString. Using a debugger I can see the returned CString always has the correct string value. I can replace GetTranslation with a hardcoded Japanese string and the issue will still happen.
EDIT 2:我收到抱怨说这段代码不够用.
EDIT 2: I got complaints that this code wasn't enough.
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
ViewMenu.cpp
ViewMenu.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;
}
ViewMenu.h
#include "resource.h"
class CViewMenu : public CFormView
{
protected:
CViewMenu();
public:
enum { IDD = IDD_VIEW_MENU };
CButton m_ctrlMenuButton0;
}
推荐答案
以下内容应该适用于 Windows 10 版本 1903 及更高版本,无论默认系统区域设置如何,并满足 OP 的要求(字符串文字、MBCS 构建、无 Unicode 窗口等等).经验证,它可以在设置为 En-US 语言环境的 2004 版中工作,没有Beta:使用 Unicode UTF-8 进行全球语言支持";检查,使用VS 2019 16.7.5构建.
The following should work in Windows 10 versions 1903 and later, regardless of the default system locale, and fulfills OP's requirements (string literals, MBCS build, no Unicode windows etc). It was verified to work in version 2004 set to En-US locale, without "Beta: Use Unicode UTF-8 for worldwide language support" checked, using VS 2019 16.7.5 to build.
以 UTF-8 编码保存包含活动代码页之外字符的源文件,有或没有 BOM.
Save source files containing characters outside the active codepage in UTF-8 encoding, with or without BOM.
编译时定义了 _MBCS
(在 IDE 中:属性/高级/字符集 = MBCS).
Compile with _MBCS
defined (in the IDE: Properties / Advanced / Character Set = MBCS).
使用 /utf-8
开关(C/C++/命令行/附加选项 =/utf-8).
Compile with the /utf-8
switch (C/C++ / Command Line / Additional Options = /utf-8).
创建一个清单文件,将 UTF-8 声明为进程的目标代码页(根据 activeCodePage
文档).
Create a manifest file declaring UTF-8 as the target codepage for the process (per the activeCodePage
documentation).
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">
<activeCodePage>UTF-8</activeCodePage>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>
将清单文件添加到项目中(在 IDE 中:清单工具/常规/输入和输出/附加清单文件 = 在上一步创建的清单文件).
Add the manifest file to the project (in the IDE: Manifest Tool / General / Input and Output / Additional Manifest Files = manifest file created at the previous step).
这篇关于MFC 控件上的文本 - Unicode 字符(如日语)被截断的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!