我想弄出 EasyX 的中文输入框

1

https://tieba.baidu.com/p/2099210288 链接教程里的,我复制过来了然后的错误我不知道怎么改

#include<windowsx.h>
#include<Windows.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<cstring>
#include<string>
#include<time.h>
#include<conio.h>
#include<easyx.h>
#include<EasyUI.h>
#include<graphics.h>
#include<locale.h>
#include<wchar.h>
#include<imm.h>
using namespace std;
string str;						//输入数据
void scanf_book_ht(HWND hwnd, string& str)
{
	while (1) {
		HIMC himc = ImmGetContext(hwnd);
		static bool flag = false;
		DWORD dwsize = ImmGetCompositionStringW(himc, GCS_COMPSTR, NULL, 0);
		if (himc) {
			if (dwsize > 0) {
				if (flag == false) flag = true;
			}
		}
		else if (dwsize == 0 && flag) {
			int iSize; //IME结果字符串的大小
			LPSTR pszMultiByte = NULL;//IME结果字符串指针
			int ChineseSimpleAcp = 936;//宽字节转换时中文的编码
			WCHAR* lpWideStr = NULL;//宽字节字符数组
			dwsize = ImmGetCompositionStringW(himc, GCS_RESULTSTR, NULL, 0);//获取IME结果字符串的大小
			if (dwsize > 0) //如果IME结果字符串不为空,且没有错误
			{
				dwsize += sizeof(WCHAR);//大小要加上NULL结束符
				//为获取IME结果字符串分配空间
				if (lpWideStr)
				{
					delete[]lpWideStr;
					lpWideStr = NULL;
				}
				lpWideStr = new WCHAR[dwsize];
				memset(lpWideStr, 0, dwsize); //清空结果空间
				ImmGetCompositionStringW(himc, GCS_RESULTSTR, lpWideStr, dwsize);//获取IME结果字符串,这里获取的是宽字节
				iSize = WideCharToMultiByte(ChineseSimpleAcp, 0, lpWideStr, -1, NULL, 0, NULL, NULL);//计算将IME结果字符串转换为ASCII标准字节后的大小
				//为转换分配空间
				if (pszMultiByte)
				{
					delete[] pszMultiByte;
					pszMultiByte = NULL;
				}
				pszMultiByte = new char[iSize + 1];
				WideCharToMultiByte(ChineseSimpleAcp, 0, lpWideStr, -1, pszMultiByte, iSize, NULL, NULL);//宽字节转换
				pszMultiByte[iSize] = '\0';
				str += pszMultiByte;//添加到string中
				//释放空间
				if (lpWideStr)
				{
					delete[]lpWideStr;
					lpWideStr = NULL;
				}
				if (pszMultiByte)
				{
					delete[] pszMultiByte;
					pszMultiByte = NULL;
				}
			}
			flag = false;
		}
		ImmReleaseContext(hwnd, himc);//释放HIMC
	}
}
//输入框
/*void scanf_book*/int main(void)
{
	HWND hwnd = GetHWnd();
	memset(hwnd, 0, sizeof(hwnd));
	while (true)
	{
		if (_kbhit()) //如果是ASCII输入
		{
			char c = _getch();
			if (c == '\b')
			{
				if (str.length() > 0)
				{
					if (str.at(str.length() - 1) & 0x8000)
						str.erase(str.end() - 1);
					str.erase(str.end() - 1);
				}
			}
			else if (c == 27) {}
			else {
				str += c;
			}
		}
		else //除此之外,检测是否有IME输入,如果有,则将输入结果添加到string中
		{
			scanf_book_ht(hwnd, str);
		}
		if (str.length() > 100) str = "";
		outtextxy(360, 570, str.c_str());
	}
}

严重性 代码 说明 项目 文件 行 禁止显示状态
错误 LNK1120 3 个无法解析的外部命令 单词本 VS程序\单词本\Debug\单词本.exe 1

错误 LNK2019 无法解析的外部符号 ImmGetCompositionStringW@16,该符号在函数 "void cdecl scanf_book_ht(struct HWND *,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > &)" (?scanf_book_ht@@YAXPAUHWND_@@AAV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) 中被引用 单词本 VS程序\单词本\单词本.obj 1

错误 LNK2019 无法解析的外部符号 ImmGetContext@4,该符号在函数 "void cdecl scanf_book_ht(struct HWND *,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > &)" (?scanf_book_ht@@YAXPAUHWND_@@AAV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) 中被引用 单词本 VS程序\单词本\单词本.obj 1

错误 LNK2019 无法解析的外部符号 ImmReleaseContext@8,该符号在函数 "void cdecl scanf_book_ht(struct HWND *,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > &)" (?scanf_book_ht@@YAXPAUHWND_@@AAV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) 中被引用 单词本 VS程序\单词本\单词本.obj 1

ava
X能力者

2020-10-30

0

首先,EasyX 2021 版已经支持了通过 getmessage 获取中文输入的功能,不需要再使用输入法相关的 API 了。相关代码请参考:https://qa.codebus.cn/question/127

=====(以下是针对你的代码的修改,不建议使用)=====

你的编译错误应该是没有引入输入法的库文件,加上这句试试:

#pragma comment(lib,"Imm32.lib")

我没有见过你代码里面的某些头文件,没办法帮你调试。我根据原文中的代码,重新帮你整理了一份,在 VS2019 + EasyX_20200902 下编译通过:

// 在 EasyX 绘图窗口中实现文本框效果(支持中文输入)
// 参考:https://tieba.baidu.com/p/2099210288
// 作为范例,未考虑字符串超范围的问题。如有需要,请进一步封装
// 原文存在中文状态下无法输入标点符号的问题,未修正
// 编译环境:VS2019 + EasyX_20200902
//
#include <easyx.h>
#include <conio.h>
#include <string>
#pragma comment(lib,"Imm32.lib")

using namespace std;

wstring GetIMEString()
{
	// 术语说明:以输入“中国”为例
	// 切换到中文输入法后,输入“zhongguo”,这个字符串称作“IME 组成字符串”
	// 而在输入法列表中选择的字符串“中国”则称作“IME 结果字符串”

	wstring str;	// 返回的字符串

	HWND hWnd = GetHWnd();
	HIMC hIMC = ImmGetContext(hWnd);	// 获取 IMC 句柄
	if (hIMC == NULL)
		return str;

	static bool flag = false;		// 输入完成标记
									// 在输入中时,IME 组成字符串不为空,置 true
									// 输入完成后,IME 组成字符串为空,置 false

	DWORD dwSize = ImmGetCompositionStringW(hIMC, GCS_COMPSTR, NULL, 0);		// 获取“IME 组成字符串”的长度

	if (dwSize > 0)		// 如果 IME 组成字符串不为空,且没有错误(此时 dwSize 为负值),则置输入完成标记为 true
	{
		if (flag == false)
			flag = true;
	}
	else if (dwSize == 0 && flag)	// 如果 IME 组成字符串为空,并且标记为 true,则获取 IME 结果字符串
	{
		dwSize = ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, NULL, 0);		// 获取 IME 结果字符串的大小
		if (dwSize > 0)				// 如果 IME 结果字符串不为空,且没有错误
		{
			// 为获取 IME 结果字符串分配空间
			wchar_t* lpWideStr = new WCHAR[dwSize / sizeof(wchar_t) + 1];
			ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, lpWideStr, dwSize);	// 获取 IME 结果字符串
			lpWideStr[dwSize / sizeof(wchar_t)] = '\0';		// 补充字符串结尾 0 字符
			str = lpWideStr;		// 添加到 string 中
			delete[]lpWideStr;		// 释放空间
		}
		flag = false;
	}
	ImmReleaseContext(hWnd, hIMC);	// 释放 HIMC

	return str;
}

int main()
{
	initgraph(640, 480, EW_SHOWCONSOLE);	// 创建绘图窗口
	
	// 画文本框
	rectangle(10, 18, 630, 42);
	int x = 12;				// 文字输出的位置。每输出一个,坐标相应增加
	int ncursor = 0;		// 实现光标闪烁的计数器

	while (true)
	{
		// 输出文字
		if (_kbhit())		// ASCII 字符输入
		{
			wchar_t c = _getwch();
			outtextxy(x, 22, c);
			x += textwidth(c);
		}
		else // 除此之外,检测是否有 IME 输入,如果有,输出
		{
			wstring s = GetIMEString();
			if (s.size() > 0)
			{
				outtextxy(x, 22, s.c_str());
				x += textwidth(s.c_str());
			}
		}

		// 绘制光标
		setlinecolor((ncursor++ / 10 % 2 == 0) ? WHITE : BLACK);
		line(x + 2, 23, x + 2, 37);

		// 延时
		Sleep(20);
	}

	closegraph();
	return 0;
}
ava
慢羊羊

2020-10-30

技术讨论社区