目录
- 什么是 Rich Edit 控件?
- 准备工作:加载 Rich Edit 库
- 创建 Rich Edit 控件
- 发送消息:与 Rich Edit 交互
- 常用功能与代码示例
- 设置文本内容
- 获取文本内容
- 设置字体、颜色
- 换行与段落格式
- 处理富文本格式 (RTF)
- 完整示例:一个简单的富文本编辑器
- 高级主题与注意事项
什么是 Rich Edit 控件?
Rich Edit 控件是一个标准的 Windows 窗口类,它比普通的 EDIT 控件功能强大得多。

-
普通 Edit 控件 (
EDIT):- 只能处理纯文本。
- 功能有限:单行/多行、基本编辑。
-
Rich Edit 控件 (
RICHEDIT):- 支持富文本格式,包括:
- 多种字体 和字号
- 字体样式 (粗体、斜体、下划线)
- 字体颜色 和背景色
- 段落对齐 (左对齐、居中、右对齐)
- 项目符号和编号列表
- 插入图片 (需要额外处理)
- 可以加载和保存 RTF (Rich Text Format) 文件,这是一种通用的富文本格式。
- 支持富文本格式,包括:
在 Windows 中,有多个版本的 Rich Edit 控件,如 RichEdit20A, RichEdit20W, RichEdit50W 等,为了获得最佳兼容性和功能,我们通常使用 RichEdit50W。
准备工作:加载 RichEdit 库
在创建 Rich Edit 控件之前,必须显式加载其对应的动态链接库 (DLL),对于 RichEdit50W,这个库是 riched32.dll。

通常在程序初始化时(例如在 WinMain 函数中)调用 LoadLibrary。
#include <windows.h>
#include <richedit.h> // 包含 Rich Edit 相关的消息和结构体定义
// 在 WinMain 函数开始处
HINSTANCE hRichEditDll = LoadLibrary(TEXT("RICHED32.DLL"));
if (hRichEditDll == NULL) {
// 处理加载失败的情况
MessageBox(NULL, TEXT("无法加载 RichEdit32.dll"), TEXT("错误"), MB_OK | MB_ICONERROR);
return 1;
}
在程序结束时,记得使用 FreeLibrary 释放它。
创建 Rich Edit 控件
创建 Rich Edit 控件与创建其他标准控件(如按钮、文本框)类似,使用 CreateWindowEx 函数。
关键点:
- 窗口类名: 必须使用
RICHEDIT_CLASS,注意,这通常需要调用LoadLibrary后才能使用。 - 扩展样式: 可以使用
ES_MULTILINE(多行),WS_VSCROLL(垂直滚动条),WS_HSCROLL(水平滚动条) 等。
// 在 WM_CREATE 消息处理中
HWND hRichEdit = CreateWindowEx(
0, // 扩展窗口样式
RICHEDIT_CLASS, // 窗口类名
TEXT("请输入文本..."), // 窗口标题
WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | ES_MULTILINE | ES_AUTOVSCROLL,
10, 10, 400, 300, // 位置和大小
hWnd, // 父窗口句柄
(HMENU)IDC_RICHEDIT, // 控件ID
hInstance, // 应用程序实例句柄
NULL // 创建参数
);
if (hRichEdit == NULL) {
MessageBox(hWnd, TEXT("创建 Rich Edit 控件失败"), TEXT("错误"), MB_OK);
}
发送消息:与 Rich Edit 交互
与 Rich Edit 控件交互的主要方式是使用 SendMessage 函数发送特定的消息,每个消息通常对应一个特定的功能。
SendMessage 的原型:
LRESULT SendMessage( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam );
hWnd: Rich Edit 控件的句柄。Msg: 要发送的消息(EM_SETCHARFORMAT)。wParam/lParam: 消息的附加参数。
常用功能与代码示例
使用 WM_SETTEXT 消息。
SendMessage(hRichEdit, WM_SETTEXT, 0, (LPARAM)L"这是设置的新文本。");
使用 WM_GETTEXT 消息,你需要一个足够大的缓冲区来存储文本。
wchar_t buffer[1024]; SendMessage(hRichEdit, WM_GETTEXT, (WPARAM)1024, (LPARAM)buffer);
设置字体、颜色
这是 Rich Edit 的核心功能,你需要使用 CHARFORMAT 结构体和 EM_SETCHARFORMAT 消息。
CHARFORMAT cf = {0};
cf.cbSize = sizeof(CHARFORMAT); // 结构体大小,必须设置
cf.dwMask = CFM_COLOR | CFM_FACE | CFM_SIZE; // 我们将要设置哪些属性
cf.crTextColor = RGB(255, 0, 0); // 设置字体颜色为红色
cf.dwEffects = 0; // 清除所有效果
wcscpy_s(cf.szFaceName, L"微软雅黑"); // 设置字体名称
cf.yHeight = 20 * 12; // 字号,单位是 1/20 个点,20 * 12 表示 12 号字体
// 发送消息
// SCF_SELECTION: 只对当前选中文本有效
// SCF_WORD: 如果没有选中文本,则对光标所在单词有效
SendMessage(hRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
换行与段落格式
使用 PARAFORMAT 结构体和 EM_SETPARAFORMAT 消息。
PARAFORMAT pf = {0};
pf.cbSize = sizeof(PARAFORMAT);
pf.dwMask = PFM_ALIGNMENT; // 我们将要设置对齐方式
pf.wAlignment = PFA_CENTER; // 设置为居中对齐
SendMessage(hRichEdit, EM_SETPARAFORMAT, SCF_SELECTION, (LPARAM)&pf);
处理富文本格式
Rich Edit 控件可以处理 RTF 格式的文本。
- 设置 RTF 内容: 使用
EM_STREAMIN消息,这比较复杂,通常需要提供一个回调函数。 - 获取 RTF 内容: 使用
EM_STREAMOUT消息,同样复杂。 - 更简单的方法: 将 RTF 文件读入内存,然后通过
WM_SETTEXT设置,但这会丢失格式信息,更标准的方法是使用EditStreamIn结构。
一个更简单的方法是利用剪贴板:
// 假设你有一个包含 RTF 的字符串
const char* rtf_data = "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1033{\\fonttbl{\\f0\\fnil\\fcharset0 Calibri;}}\n{\\colortbl;\\red0\\green0\\blue0;}\n\\viewkind4\\uc1\\pard\\f0\\fs20 这是 RTF 格式的文本,\\par\n}";
HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, strlen(rtf_data) + 1);
LPVOID pGlobal = GlobalLock(hGlobal);
memcpy(pGlobal, rtf_data, strlen(rtf_data) + 1);
GlobalUnlock(hGlobal);
// 将数据放入剪贴板
OpenClipboard(hWnd);
EmptyClipboard();
SetClipboardData(CF_RTF, hGlobal);
CloseClipboard();
// 从剪贴板粘贴到 Rich Edit
SendMessage(hRichEdit, WM_PASTE, 0, 0);
// 释放内存
GlobalFree(hGlobal);
完整示例:一个简单的富文本编辑器
这个例子创建一个窗口,包含一个 Rich Edit 控件和几个按钮,用于改变字体颜色。
#include <windows.h>
#include <richedit.h>
#include <commctrl.h> // 为 Common Controls 库
#pragma comment(lib, "comctl32.lib") // 链接 Common Controls 库
#define IDC_RICHEDIT 101
#define IDC_BTN_RED 102
#define IDC_BTN_BLUE 103
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void InitCommonControls();
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow) {
InitCommonControls(); // 初始化 Common Controls (为了 Rich Edit)
// 加载 RichEdit DLL
HINSTANCE hRichEditDll = LoadLibrary(TEXT("RICHED32.DLL"));
if (!hRichEditDll) {
MessageBox(NULL, L"无法加载 RichEdit32.dll", L"错误", MB_OK | MB_ICONERROR);
return 1;
}
WNDCLASSW wc = {0};
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.lpszClassName = L"MyRichEditWindow";
RegisterClassW(&wc);
HWND hWnd = CreateWindowW(L"MyRichEditWindow", L"简单 Rich Edit 示例",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 600, 400,
NULL, NULL, hInstance, NULL);
if (hWnd) ShowWindow(hWnd, nCmdShow);
MSG msg = {0};
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
FreeLibrary(hRichEditDll); // 卸载 DLL
return (int)msg.wParam;
}
void InitCommonControls() {
INITCOMMONCONTROLSEX icex;
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_WIN95_CLASSES;
InitCommonControlsEx(&icex);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_CREATE: {
// 创建 Rich Edit 控件
HWND hRichEdit = CreateWindowExW(0, RICHEDIT_CLASS, L"",
WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | ES_MULTILINE | ES_AUTOVSCROLL,
10, 10, 560, 300,
hWnd, (HMENU)IDC_RICHEDIT, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
if (!hRichEdit) {
MessageBox(hWnd, L"创建 Rich Edit 失败", L"错误", MB_OK);
return -1;
}
// 创建按钮
CreateWindowW(L"BUTTON", L"红色", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
10, 320, 100, 30, hWnd, (HMENU)IDC_BTN_RED, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
CreateWindowW(L"BUTTON", L"蓝色", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
120, 320, 100, 30, hWnd, (HMENU)IDC_BTN_BLUE, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
break;
}
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDC_BTN_RED: {
CHARFORMAT cf = {0};
cf.cbSize = sizeof(CHARFORMAT);
cf.dwMask = CFM_COLOR;
cf.crTextColor = RGB(255, 0, 0);
SendMessage(GetDlgItem(hWnd, IDC_RICHEDIT), EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
break;
}
case IDC_BTN_BLUE: {
CHARFORMAT cf = {0};
cf.cbSize = sizeof(CHARFORMAT);
cf.dwMask = CFM_COLOR;
cf.crTextColor = RGB(0, 0, 255);
SendMessage(GetDlgItem(hWnd, IDC_RICHEDIT), EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
break;
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
高级主题与注意事项
-
版本兼容性: 不同的 Windows 版本默认支持不同版本的 Rich Edit。
RichEdit20是 Win98/NT4 时代的主流,RichEdit50(来自riched50.dll) 功能更强大,被 XP 及更高版本支持,为了确保你的程序在任何 Windows 系统上都能工作,最好的做法是使用LoadLibrary动态加载riched32.dll,并检查加载是否成功,如果失败,可以尝试加载riched50.dll或msftedit.dll(这是RichEdit50的另一个来源)。 -
Unicode 支持: 在现代 Windows 编程中,强烈推荐使用宽字符版本 (
W版本) 的 API,如CreateWindowExW和CHARFORMATW,这样可以更好地支持国际化字符。 -
通知消息: Rich Edit 控件会向父窗口发送
EN_CHANGE(内容改变)、EN_SELCHANGE(选择改变) 等通知消息,你可以在WM_NOTIFY消息中处理它们,以实现更复杂的交互逻辑。 -
性能: 对于包含大量文本或复杂格式的文档,频繁地发送
EM_SETCHARFORMAT等消息可能会影响性能,在需要批量修改格式时,可以考虑先锁定文本内容进行修改,然后再一次性应用格式。 -
替代方案: 如果你觉得直接使用 Win32 API 的 Rich Edit 控件过于繁琐,可以考虑使用更高层的 GUI 框架,
- MFC (Microsoft Foundation Classes): 封装了 Win32,提供了
CRichEditCtrl类,使用起来更方便。 - Qt: 跨平台框架,其
QTextEdit控件功能强大且易用。 - wxWidgets: 另一个优秀的跨平台 C++ GUI 框架。
- MFC (Microsoft Foundation Classes): 封装了 Win32,提供了
希望这份详细的指南能帮助你在 C 语言项目中成功使用 Rich Edit 控件!
