QT文本编辑器第四弹:字体、颜色、加粗、倾斜、下划线、背景色全实现(TaoToken 统一 Key 通道) 1. QT 文本编辑器富文本格式模块到底难在哪如果你正在用 QT 写一个文本编辑器做到第四弹这个阶段大概率已经能打开文件、保存文件、做基本的复制粘贴了。但一旦要往「像 Word 那样选中一段字就能加粗、改颜色、换字体」的方向走很多人会卡住。核心检索词就是 QT 文本编辑器富文本格式设置它要解决的问题是让字体族、字号、字体颜色、加粗、倾斜、下划线、背景色这七种样式都能作用在光标选区上并且点击一次生效、再点一次取消互不干扰。我见过太多半成品编辑器加粗按钮点下去没反应或者点了加粗之后整篇文档都变粗了又或者倾斜和加粗互相覆盖。根子在于没搞清楚 QTextCursor 和 QTextCharFormat 的配合方式。QTextCursor 代表你当前选中的那块区域QTextCharFormat 代表你要往这块区域上「盖」的格式属性。关键函数是mergeCharFormat它只合并你设置的属性不动其他属性这样加粗和倾斜才能叠加而不是互相冲掉。这一篇要交付的是可以直接复制进项目的工具栏动作绑定代码、格式合并逻辑、光标选区处理以及一份逐项点击验证清单。适合已经有一个能跑的 QT 文本编辑器骨架、想补齐富文本格式菜单的开发者。下面所有代码基于 QT 5/6 的 QMainWindow QTextEdit 结构头文件和槽函数命名沿用你项目里已有的风格即可。在动手之前先把整体思路理清楚。工具栏上每个按钮对应一个槽函数槽函数里构造一个 QTextCharFormat设置对应的属性然后交给 mergeFormat 去合并到选区。加粗、倾斜、下划线这三个是「开关型」的需要一个全局变量记录上一次的状态点一次翻转一次。字体、字号、颜色、背景色是「取值型」的弹对话框让用户选选完直接应用。背景色这里有个坑很多人以为改的是文字背景其实 QTextEdit 的调色板 Base 改的是整个编辑区背景真正给文字加背景要用setBackground。这个区别后面会专门讲。2. TaoToken 统一 Key 通道给编辑器接入 AI 能力的前置准备写到这里你可能会问一个 QT 文本编辑器教程为什么要提 TaoToken。原因是这样当你的编辑器富文本格式模块跑通之后下一步很自然的需求就是加一个「AI 润色」「AI 改写选中段落」的功能。这时候你需要一个稳定的模型调用通道而不是每个模型都去单独申请 Key、单独配环境。TaoToken 就是干这个的它把多个模型的调用统一到一个 Key 上你只需要在代码里改 Base URL 和 Model ID 就能切换模型。TaoToken 是什么一个统一的大模型 API 接入通道兼容 OpenAI 风格的接口格式。能做什么你用同一个 API Key就能调用不同厂商的对话模型适合在编辑器里做文本润色、续写、翻译这类功能。适合谁正在做桌面端工具、想把 AI 能力嵌进 QT 应用的开发者尤其是懒得维护多套鉴权逻辑的人。接入前你需要准备三样东西我把它叫做「三件套」Base URL、API Key、Model ID。Base URL 填https://taotoken.net/api注意这里不加任何多余路径。API Key 去控制台生成地址是 https://taotoken.net/api-keys 。Model ID 根据你要用的模型填比如做文本润色可以选一个擅长中文的对话模型。这三样在 QT 里怎么用你可以用 QNetworkAccessManager 发 POST 请求请求头带上Authorization: Bearer 你的Key请求体里写 model 和 messages。如果你打算长期在编辑器里做编码辅助或者 Agent 类的功能可以看一下 Coding Plan地址是 https://taotoken.net/coding-plan 。它适合那种需要持续调用、按量使用的场景。想先验证模型效果可以直接在模型对话页面试地址 https://taotoken.net/chat 。接入文档在 https://taotoken.net/doc 里面有完整的请求示例和参数说明。这里要强调一点TaoToken 是正规的 API 接入服务不是让你去搞什么网络绕行。你只需要在代码里配置好 Base URL 和 Key走标准的 HTTPS 请求就行。QT 的 QNetworkAccessManager 原生支持 HTTPS不需要额外装什么东西。把 Key 拿到手之后建议先别急着写进 QT 代码而是用 curl 或者 Postman 发一个最简单的请求确认通道是通的。命令大概长这样curl -X POST https://taotoken.net/api/chat/completions \ -H Authorization: Bearer 你的APIKey \ -H Content-Type: application/json \ -d { model: 你的ModelID, messages: [{role: user, content: 把这句话润色一下今天天气不错}] }如果返回里有choices字段和正常的文本内容说明通道没问题。这一步验证过了再往 QT 里集成能省掉很多排查时间。很多人一上来就在 QT 里调结果报错分不清是网络问题还是代码问题先用命令行确认通道是最省事的做法。3. 可复制配置工具栏动作绑定与格式合并完整代码这一节是全文的核心直接给可复制的代码。先看头文件里需要声明什么。全局变量 boldcheck、Italiccheck、UnderLinecheck 用来记录加粗、倾斜、下划线的上一个状态初始值设为 0。mergeFormat 函数负责把格式合并到光标选区。槽函数按你的动作命名对应即可。// mainwindow.h public: explicit MainWindow(QWidget *parent 0); ~MainWindow(); int boldcheck, Italiccheck, UnderLinecheck; // 记录加粗、倾斜、下划线的上一个状态 private slots: void mergeFormat(QTextCharFormat fmt); // 将格式合并到光标选区 void on_action_font_triggered(); // 字体 void on_action_fontSize_triggered(); // 字号 void on_action_fontColor_triggered(); // 字体颜色 void on_action_bold_triggered(); // 加粗 void on_action_italic_triggered(); // 倾斜 void on_action_underline_triggered(); // 下划线 void on_action_bgColor_triggered(); // 文字背景色构造函数里把三个状态变量初始化同时把工具栏按钮和槽函数连起来。如果你用的是 Qt Designer 的 action 自动连接命名对上就行如果是手写 connect参考下面。// mainwindow.cpp 构造函数片段 MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui-setupUi(this); boldcheck 0; Italiccheck 0; UnderLinecheck 0; connect(ui-action_bold, QAction::triggered, this, MainWindow::on_action_bold_triggered); connect(ui-action_italic, QAction::triggered, this, MainWindow::on_action_italic_triggered); connect(ui-action_underline, QAction::triggered, this, MainWindow::on_action_underline_triggered); }mergeFormat 是整个模块的地基。它的逻辑是拿到当前光标如果没有选区就自动选中光标所在的单词然后把格式合并进去。这样即使用户没选文字只把光标放在某个词上点加粗也能生效。void MainWindow::mergeFormat(QTextCharFormat fmt) { QTextCursor cursor ui-textEdit-textCursor(); if (!cursor.hasSelection()) { cursor.select(QTextCursor::WordUnderCursor); } cursor.mergeCharFormat(fmt); ui-textEdit-mergeCurrentCharFormat(fmt); }注意最后那行mergeCurrentCharFormat它的作用是让编辑器记住当前格式这样你接着输入的新文字也会沿用这个格式。少了这行你会发现选中加粗后继续打字又变回普通体了。字体和字号用 QFontDialog 和 QFont 来处理。字体对话框返回一个 QFont 对象直接 setCurrentFont 即可。字号可以单独弹一个输入框或者用 QFontDialog 里带的字号选择。void MainWindow::on_action_font_triggered() { bool ok; QFont font QFontDialog::getFont(ok, QFont(Microsoft YaHei, 12), this, 选择字体); if (ok) { ui-textEdit-setCurrentFont(font); } } void MainWindow::on_action_fontSize_triggered() { bool ok; int size QInputDialog::getInt(this, 设置字号, 字号, 12, 1, 200, 1, ok); if (ok) { QTextCharFormat fmt; fmt.setFontPointSize(size); mergeFormat(fmt); } }字体颜色用 QColorDialog拿到颜色后调 setTextColor。这里注意setTextColor 作用于当前选区和 mergeFormat 效果类似但它是 QTextEdit 的便捷方法。void MainWindow::on_action_fontColor_triggered() { QColor color QColorDialog::getColor(Qt::black, this, 选择字体颜色); if (color.isValid()) { ui-textEdit-setTextColor(color); } }加粗、倾斜、下划线这三个开关型按钮逻辑是根据全局变量的当前值决定设置成什么设置完把变量翻转。这样第一次点变粗第二次点变正常。void MainWindow::on_action_bold_triggered() { QTextCharFormat fmt; fmt.setFontWeight(boldcheck ? QFont::Normal : QFont::Bold); mergeFormat(fmt); boldcheck !boldcheck; } void MainWindow::on_action_italic_triggered() { QTextCharFormat fmt; fmt.setFontItalic(Italiccheck ? false : true); mergeFormat(fmt); Italiccheck !Italiccheck; } void MainWindow::on_action_underline_triggered() { QTextCharFormat fmt; fmt.setFontUnderline(UnderLinecheck ? false : true); mergeFormat(fmt); UnderLinecheck !UnderLinecheck; }文字背景色是这一弹新增的重点。很多人会误用 QPalette 去改 textEdit 的背景那样改的是整个编辑区不是选中文字的背景。正确做法是用 QTextCharFormat 的 setBackground。void MainWindow::on_action_bgColor_triggered() { QColor color QColorDialog::getColor(Qt::yellow, this, 选择文字背景色); if (color.isValid()) { QTextCharFormat fmt; fmt.setBackground(color); mergeFormat(fmt); } }如果你确实想改整个编辑器的背景色那才用 QPalette代码是这样QPalette palette ui-textEdit-palette(); palette.setColor(QPalette::Base, color); ui-textEdit-setPalette(palette);这两者的区别一定要分清setBackground 是给文字加底色QPalette::Base 是给编辑区换底色。做富文本格式菜单你要的是前者。4. 验证请求与成功结果逐项点击验证清单代码写完了怎么确认每一项都生效且互不干扰我整理了一份逐项点击验证清单你照着点一遍基本能覆盖所有边界情况。第一步验证字体族。在编辑器里输入「测试字体样式」六个字全选点字体按钮选一个和默认明显不同的字体比如从微软雅黑换成楷体。点确定后选中文字应该立刻变字体。把光标移到这段文字后面继续打字新打的字应该也是楷体这说明 mergeCurrentCharFormat 生效了。第二步验证字号。选中同一段文字点字号输入一个明显大的值比如 28。文字应该变大。这里注意观察字号变化不应该影响字体族也不应该影响颜色。第三步验证字体颜色。选中文字点字体颜色选红色。文字变红。此时加粗、倾斜状态应该保持不变。第四步验证加粗。选中文字点加粗文字变粗。再点一次变回正常。连续点三次应该是粗、正常、粗。如果第三次没变粗说明 boldcheck 翻转逻辑有问题。第五步验证倾斜。选中文字点倾斜文字倾斜。再点加粗此时应该是又粗又斜。再点倾斜取消应该只剩加粗。这一步专门验证加粗和倾斜的叠加与分离。第六步验证下划线。选中文字点下划线出现下划线。再叠加倾斜应该是斜体带下划线。逐项取消确认互不影响。第七步验证文字背景色。选中文字点背景色选黄色。文字应该有黄色底色而不是整个编辑区变黄。这是最容易出错的一项重点确认。第八步验证无选区情况。把光标放在某个词中间不选中任何文字直接点加粗。按照 mergeFormat 的逻辑应该自动选中光标所在单词并加粗。如果你不想要这个行为可以把cursor.select(QTextCursor::WordUnderCursor)那行去掉改成直接返回。第九步验证混合格式。输入一段话前半段加粗后半段倾斜中间一段加下划线加背景色。全选后点字体颜色变蓝。理想结果是所有文字变蓝但各自的加粗、倾斜、下划线、背景色都保留。这验证的是 mergeCharFormat 只合并颜色属性、不动其他属性的特性。第十步验证保存后重新打开。把带格式的文本保存成 HTML 或 RTF重新打开格式应该还在。如果你保存成纯 txt格式会丢这是正常的纯文本不存格式信息。这份清单走完你的富文本格式模块基本就稳了。如果哪一项没过对照下一节的排查表找原因。5. 本篇常见错误排查401、local proxy failed、reading choices 与 OAuth虽然这一篇主体是 QT 富文本格式但既然提到了 TaoToken 统一 Key 通道就把接入 AI 能力时最容易撞上的几个报错一起讲了。这些报错在你把编辑器接上模型接口之后大概率会遇到。第一个401 Unauthorized。这个最直接就是 Key 不对或者没带。检查你的请求头是不是Authorization: Bearer Key注意 Bearer 和 Key 之间有一个空格。另外确认 Key 没有多余的空格或换行从控制台复制的时候容易带上。如果你把 Key 写在了配置文件里检查读取的时候有没有把引号也读进去。第二个local proxy failed。这个报错通常出现在你本地配了什么网络转发工具的情况下。QT 的 QNetworkAccessManager 默认会读取系统代理设置如果你系统里配了一个不可用的转发请求就会失败。解决办法是在代码里显式设置不使用代理或者检查系统网络设置里有没有残留的转发配置。注意这里说的是排查本地网络配置问题不是让你去搞什么特殊通道标准 HTTPS 请求直连即可。第三个reading choices 相关报错比如Cannot read property choices of undefined或者解析响应时拿不到 choices 字段。这通常说明请求发出去了但返回的不是预期的 JSON 结构。可能原因有三个一是 Model ID 填错了服务端返回了错误信息而不是正常响应二是请求体格式不对比如 messages 数组写错了三是响应还没解析完就去读字段了。排查方法是在 QT 里把原始响应打印出来看用qDebug() reply-readAll()先看返回的到底是什么。第四个OAuth 相关报错。如果你用的是某些需要 OAuth 流程的模型服务可能会遇到 token 过期或者 scope 不对的问题。TaoToken 用的是 API Key 方式不涉及 OAuth 跳转所以如果你看到 OAuth 报错先确认自己是不是把 Base URL 填成了别的服务的地址。Base URL 应该是https://taotoken.net/api不要多加路径。第五个Codex 的 auth.json 配置问题。如果你在用 Codex 类的编码工具它的鉴权信息存在 auth.json 里。这个文件里需要填 Base URL、Key 和 Model ID 三件套。常见错误是 Base URL 末尾多加了斜杠或者 Model ID 写成了显示名称而不是实际 ID。检查的时候把这三项逐一核对。第六个CC Switch 或 Cline MCP 配置问题。这两个工具在配置模型通道时同样需要 Base URL、Key、Model ID 三件套。CC Switch 的配置文件通常是 JSON 格式Cline 的 MCP 配置在 settings 里。如果你在这两个工具里遇到连接失败先确认三件套是否齐全再确认 JSON 格式有没有语法错误比如多余的逗号或者少了引号。把上面这些报错对照一遍基本能覆盖接入阶段 90% 的问题。剩下的 10% 大概率是网络环境或者服务端临时波动隔几分钟重试即可。6. 从格式模块到 AI 润色下一步怎么走富文本格式模块跑通之后你的 QT 文本编辑器已经具备了「所见即所得」的编辑能力。接下来最自然的延伸就是在工具栏上加一个「AI 润色」按钮。点击后把当前选中的文字取出来通过 TaoToken 的接口发给模型把返回的润色结果替换回选区。取选中文字用ui-textEdit-textCursor().selectedText()替换回去用cursor.insertText(结果)。发送请求的部分用 QNetworkAccessManagerPOST 到https://taotoken.net/api/chat/completions请求头带 Key请求体里 model 填你的 Model IDmessages 里放一段系统提示词加用户选中的文字。如果你想让编辑器支持多种模型切换可以在设置里做一个下拉框把不同的 Model ID 列进去用户选哪个就用哪个。因为 TaoToken 是统一 Key 通道你不需要为每个模型单独配 Key换 Model ID 就行。想先试试模型效果可以去 https://taotoken.net/chat 直接对话验证。接入文档在 https://taotoken.net/doc 里面有完整的参数说明。需要生成 Key 就去 https://taotoken.net/api-keys 。长期做编码辅助的话Coding Plan 在 https://taotoken.net/coding-plan 。最后说一个我踩过的坑在 QT 里发 HTTPS 请求如果遇到 SSL 握手失败先检查你的 QT 版本有没有带 OpenSSL 库。Windows 下 QT 默认可能不带需要手动把 libssl 和 libcrypto 的动态库放到可执行文件目录。这个和 TaoToken 无关是 QT 本身的依赖问题但很多人会误以为是接口不通白白排查半天。确认方法很简单写一个最小的 QNetworkAccessManager 请求任意 HTTPS 地址如果也失败那就是 SSL 库的问题。