我正在开发一个应用程序,该应用程序接收以UTF-8编码的文本,并且需要在某些MFC控件上显示它。该应用程序是使用MultiByte字符集(MBCS)构建的,并且假定这不能更改。
我希望,如果我将从UTF-8接收到的文本转换为宽字符字符串,则可以使用SetWindowTextW
方法正确显示它。为此,我使用了一个玩具应用程序,该应用程序从文件中读取输入并设置控件的文本。
std::wstring utf8_decode(const std::string &str)
{
if (str.empty()) return std::wstring();
int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
std::wstring wstrTo(size_needed, 0);
MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);
return wstrTo;
}
BOOL CAboutDlg::OnInitDialog()
{
std::vector<std::string> texts;
texts.resize(6);
std::fstream f("D:\\code\\sample-utf8.txt", std::ios::in);
for (size_t i=0;i<6;++i)
std::getline(f, texts[i]);
::SetWindowTextW(GetDlgItem(IDC_BUTTON1)->m_hWnd, utf8_decode(texts[0]).c_str());
::SetWindowTextW(GetDlgItem(IDC_BUTTON2)->m_hWnd, utf8_decode(texts[1]).c_str());
::SetWindowTextW(GetDlgItem(IDC_BUTTON3)->m_hWnd, utf8_decode(texts[2]).c_str());
::SetWindowTextW(GetDlgItem(IDC_BUTTON4)->m_hWnd, utf8_decode(texts[3]).c_str());
::SetWindowTextW(GetDlgItem(IDC_BUTTON5)->m_hWnd, utf8_decode(texts[4]).c_str());
::SetWindowTextW(GetDlgItem(IDC_BUTTON6)->m_hWnd, utf8_decode(texts[5]).c_str());
return TRUE;
}
这是否意味着在使用MBCS进行构建时就没有希望对单个控件使用unicode文本?如果可能的话,您能给我指点吗?谢谢。
答案 0 :(得分:4)
MBCS应用程序会创建MBCS窗口,通常来说,即使使用宽字符串界面,MBCS窗口也只能显示单个代码页中的文本。
对于MBCS应用程序,SetWindowTextW的宽字符串版本实质上是使用用户的当前语言环境(具有默认代码页)将宽字符串转换为MBCS,然后将其传递给函数的-A版本。
正如您在“ Unicode”实验中看到的那样,通常您做的都是正确的事情,但由于该应用程序是MBCS,因此受到限制。
答案 1 :(得分:1)
由于Adrian McCarthy和Joseph Willcoxson的建议,我得以完成这项工作。我使用CreateWindowExW
方法创建控件,然后使用SetWindowTextW
设置文本。以下是提供帮助的示例代码:
std::wstring utf8_decode(const std::string &str)
{
if (str.empty()) return std::wstring();
int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
std::wstring wstrTo(size_needed, 0);
MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);
return wstrTo;
}
HWND CreateButtonW(int x, int y, int width, int height, HWND parent)
{
HWND hwndButton = ::CreateWindowExW(
WS_EX_CLIENTEDGE,
L"BUTTON", // Predefined class; Unicode assumed
L"", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
x, y, width, height, parent,
NULL, // No menu.
(HINSTANCE)GetWindowLong(parent, GWL_HINSTANCE),
NULL); // Pointer not needed.
return hwndButton;
}
BOOL CAboutDlg::OnInitDialog()
{
std::vector<std::string> texts;
texts.resize(6);
std::fstream f("D:\\code\\sample-utf8.txt", std::ios::in);
for (size_t i=0;i<6;++i)
std::getline(f, texts[i]);
::SetWindowTextW(GetDlgItem(IDC_BUTTON1)->m_hWnd, utf8_decode(texts[0]).c_str());
::SetWindowTextW(GetDlgItem(IDC_BUTTON2)->m_hWnd, utf8_decode(texts[1]).c_str());
::SetWindowTextW(GetDlgItem(IDC_BUTTON3)->m_hWnd, utf8_decode(texts[2]).c_str());
::SetWindowTextW(GetDlgItem(IDC_BUTTON4)->m_hWnd, utf8_decode(texts[3]).c_str());
::SetWindowTextW(GetDlgItem(IDC_BUTTON5)->m_hWnd, utf8_decode(texts[4]).c_str());
::SetWindowTextW(GetDlgItem(IDC_BUTTON6)->m_hWnd, utf8_decode(texts[5]).c_str());
auto width = [](RECT& r) { return r.right - r.left; };
auto height = [](RECT& r) { return r.bottom - r.right; };
RECT r;
GetDlgItem(IDC_BUTTON1)->GetWindowRect(&r); ScreenToClient(&r);
HWND hBtnWnd = CreateButtonW(r.right+20, r.top, width(r), height(r), m_hWnd);
::SetWindowTextW(hBtnWnd, utf8_decode(texts[0]).c_str());
GetDlgItem(IDC_BUTTON2)->GetWindowRect(&r); ScreenToClient(&r);
hBtnWnd = CreateButtonW(r.right+20, r.top, width(r), height(r), m_hWnd);
::SetWindowTextW(hBtnWnd, utf8_decode(texts[1]).c_str());
GetDlgItem(IDC_BUTTON3)->GetWindowRect(&r); ScreenToClient(&r);
hBtnWnd = CreateButtonW(r.right+20, r.top, width(r), height(r), m_hWnd);
::SetWindowTextW(hBtnWnd, utf8_decode(texts[2]).c_str());
GetDlgItem(IDC_BUTTON4)->GetWindowRect(&r); ScreenToClient(&r);
hBtnWnd = CreateButtonW(r.right+20, r.top, width(r), height(r), m_hWnd);
::SetWindowTextW(hBtnWnd, utf8_decode(texts[3]).c_str());
GetDlgItem(IDC_BUTTON5)->GetWindowRect(&r); ScreenToClient(&r);
hBtnWnd = CreateButtonW(r.right+20, r.top, width(r), height(r), m_hWnd);
::SetWindowTextW(hBtnWnd, utf8_decode(texts[4]).c_str());
GetDlgItem(IDC_BUTTON6)->GetWindowRect(&r); ScreenToClient(&r);
hBtnWnd = CreateButtonW(r.right+20, r.top, width(r), height(r), m_hWnd);
::SetWindowTextW(hBtnWnd, utf8_decode(texts[5]).c_str());
return TRUE;
}
结果-在左侧使用默认设置创建的按钮,在使用CreateWindowExW
创建时在右侧: