Qt 设置鼠标光标形状,这次用 TaoToken 让 Codex 走通 setCursor 1. 只读区域的光标还是输入光标先复现原文的问题在 Qt 5.14.2 里给只读的 QTextEdit 加箭头光标看似只差一行代码实际落地时经常被 viewport 拦下。这次我用 TaoToken 的 Key 把 Codex 接起来让它按原文场景生成 viewport()-setCursor(Qt::ArrowCursor) 这行代码TaoToken 官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 负责创建 KeyCodex 的 Base URL 指向 https://taotoken.net/api。随后在 Windows 上跑一遍 Qt 5.14.2 程序验证效果。1.1 原文的场景与版本原文的场景很具体Windows 系统Qt Creator 7.0.0Qt 5.14.2。界面上有一个类型为 QTextEdit 的控件对象名是Nutation_ReadonlyArea用来展示只读信息。程序运行后鼠标一旦移进那块文本区域默认光标仍然是文本输入用的 IBeam也就是一条竖线。这会给使用者一个错误暗示这里能打字。可控件本身是只读的点了也改不了内容。把鼠标光标改成 ArrowCursor等于告诉用户“这块地方只能看不能编辑”。从交互反馈上讲这个小改动比单纯加setReadOnly(true)更直观。原文给出的关键代码是这么写的ui-Nutation_ReadonlyArea-viewport() -setCursor(Qt::ArrowCursor);这行代码看起来很简单但它踩中了一个 Qt 新手容易忽略的点QTextEdit 本身不是一个扁平的普通控件。1.2 viewport 才是光标真正落地的画布你可以把 QTextEdit 理解成一面装了外框的画布。外框是QTextEdit自己真正显示文字、接收鼠标事件的是内部那个viewport()。鼠标悬停在文本区域时它落在的是 viewport 上而不是外层边框上。如果图省事直接写成ui-Nutation_ReadonlyArea-setCursor(Qt::ArrowCursor);这样设置的是整个 QTextEdit 外框的光标属性效果常常不稳定鼠标在文字区域上方时还是 IBeam移到滚动条或边框附近又变成箭头看起来就像光标在跳来跳去。正确做法就是原文里的那步拿到viewport()再对它调用setCursor(Qt::ArrowCursor)。这样鼠标在文本内容区域、空白区域、滚动内容上方时都会稳定保持箭头形状。2. 准备 TaoToken Key给 Codex 一条统一接入通道这次我不打算直接在 Qt Creator 里手敲代码来验证而是让 Codex 在命令行里帮我生成这段viewport()-setCursor代码。既然要让 Codex 走自定义模型通道就需要一个能统一接入模型服务的 API Key。TaoToken 提供的是一条统一接入通道注册拿到 Key 之后把 Base URL 填进 Codex 的配置文件Codex 就能通过 https://taotoken.net/api 访问模型。下面两个地址不要混用用途地址官网注册、创建 API Key、看模型广场、查用量https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end填进 Codex 的 Base URLhttps://taotoken.net/apiBase URL 末尾不要加/v1也不要顺手把官网地址填进去。2.1 去官网拿 YOUR_API_KEY打开 TaoToken 注册并登录在控制台进入 API Keys 页面创建一个新 Key。创建完成之后复制一次后面配置 Codex 时要用。这个 Key 就是你的身份凭证下文统一用YOUR_API_KEY占位。建议直接放进环境变量不要硬编码进项目代码或配置文件后提交到 Git 仓库。2.2 记下模型 ID 和 Base URL创建完 Key顺手打开模型广场看当前可用的模型列表。选一个擅长代码生成的模型把它的模型 ID 记下来。模型 ID 不需要背因为不同时期的模型广场列表会影响 ID 的具体值。你只需要记住配置 Codex 时填的是模型广场当前展示的那个 ID。如果后面报model not found大概率是你填了一个过时或不存在的模型名。3. setCursor 的完整 Qt 写法viewport 上钉住 ArrowCursor拿到 Key 之后先不急着配 Codex。先把 Qt 侧的技术点梳理清楚这样回头验证 Codex 生成的代码时才知道对不对。3.1 最小可运行代码假设你的MainWindow构造函数里已经执行了ui-setupUi(this)那么把这四行加进去即可ui-setupUi(this); ui-Nutation_ReadonlyArea-setReadOnly(true); ui-Nutation_ReadonlyArea-viewport() -setCursor(Qt::ArrowCursor); ui-Nutation_ReadonlyArea-setToolTip( tr(只读区域不可编辑));这段代码做的事情很明确setReadOnly(true)禁止编辑内容viewport()-setCursor(Qt::ArrowCursor)把文本显示区域的光标固定为箭头setToolTip(...)给用户一个额外的文字提示。如果你只想在鼠标悬停时改变光标形状setCursor本身就是这个语义光标进入viewport区域时变成箭头离开这个控件后自动恢复默认样式。想要恢复原来的光标形状可以调用ui-Nutation_ReadonlyArea-viewport()-unsetCursor();这样viewport会重新使用父级或全局默认光标。3.2 常见的错误写法第一种错误写法是把光标直接设置在QTextEdit外层ui-Nutation_ReadonlyArea-setCursor(Qt::ArrowCursor);这种写法的问题在 1.2 里已经解释过外层和viewport是两层东西鼠标落在文本区域上时viewport的光标会覆盖外层设置。第二种错误写法是使用QApplication::setOverrideCursorQApplication::setOverrideCursor(Qt::ArrowCursor);这在全局修改所有窗口控件的光标而且会覆盖其他控件的正常状态。它适合在耗时操作期间临时设置不适合用来表达某个只读区域的属性。用完还要restoreOverrideCursor()很容易忘记。第三种错误写法是把setCursor放在setupUi之前调用ui-Nutation_ReadonlyArea-viewport() -setCursor(Qt::ArrowCursor); ui-setupUi(this); // 设置生效前控件还没构建完成这种情况下代码可能不报错但光标不会变。因为setupUi会重建控件属性顺序反了等于白写。3.3 只读区域的光标反馈还能怎么配合除了光标形状还可以把只读区域的前景色稍微调灰一点让界面更统一QPalette pal ui-Nutation_ReadonlyArea-palette(); pal.setColor(QPalette::Text, pal.color(QPalette::Disabled, QPalette::Text)); ui-Nutation_ReadonlyArea-setPalette(pal);不过原文的主线是光标颜色这步属于额外优化。不要在项目里为了一个ArrowCursor写太多样板代码重点仍然是viewport那一层。4. Codex 接入 TaoToken让命令行帮你写 viewport 代码4.1 Codex 的 config.toml本地 Codex 的配置文件在~/.codex/config.toml。为了让 Codex 走 TaoToken 通道可以这样配置model_provider taotoken model 模型 ID 以模型广场为准 [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key TAOTOKEN_API_KEY注意base_url填的是接口地址不是官网落地页。如果你在别处看到有人写https://taotoken.net/v1或https://taotoken.net/models那不是给 Codex 用的接口地址。然后在当前 shell 里导出 Keyexport TAOTOKEN_API_KEYYOUR_API_KEY导出完成之后Codex 会从环境变量里读取 Key配置文件本身不出现明文密钥。4.2 提示词怎么给配置好之后打开终端把原文的场景丢给 Codexcodex exec 在 Qt 5.14.2 中界面有一个 QTextEdit对象名是 Nutation_ReadonlyArea已经设为只读。我想让鼠标移到这个控件的文本区域时光标显示为箭头而非文本输入光标。请给出 Qt 构造函数里应调用的代码并解释为什么必须使用 viewport()-setCursor。Codex 返回的代码会包含viewport()-setCursor(Qt::ArrowCursor)这行同时解释QTextEdit的 viewport 机制。这里要说清楚Codex 只是生成和解释代码不会替你编译运行 Qt 工程。拿到它给的代码片段后复制回自己的 Qt 项目里使用。如果编译或运行时报错再把报错信息贴回对话让 Codex 继续分析。5. 编译运行验证光标形状和这次调用用量5.1 在 Qt Creator 里编译并观察把上一步拿到的viewport()-setCursor代码放进构造函数重新编译运行。验证时重点看三处鼠标移到Nutation_ReadonlyArea的文本内容区域光标应该显示为箭头鼠标移到该控件的滚动条上光标也应该是箭头而不是出现在文本区的 IBeam鼠标移到旁边可编辑的输入框上光标仍然显示为正常的 IBeam说明这次设置没有全局污染其他控件。如果光标没变优先检查代码是否写在setupUi之后以及调用的对象是不是viewport()。不要急着怀疑 Codex先把 Qt 侧这几个固定坑排除掉。5.2 回 TaoToken 控制台核对用量Codex 刚才那次调用已经在 TaoToken 侧留下请求记录。回到 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 在控制台的用量页面查看这次请求的模型、时间和 token 数确认调用成功且已经记账。如果你还想在浏览器里快速验证同一个 Key 和模型能不能正常对话可以先打开 TaoToken 模型对话 发一条消息试试。之后长期让 Codex 写 Qt 代码的话可以看看 Coding Plan 是否更适合自己的用量需要再生成别的 Key去 API Keys 页面 创建即可。6. 排障setCursor 不生效与 Codex 调用失败6.1 Qt 侧光标没变化如果编译运行之后光标仍然是 IBeam按下面顺序排查先确认viewport()-setCursor这行代码在setupUi之后。再确认没有把代码写成ui-Nutation_ReadonlyArea-setCursor(...)。最后检查程序里是否还有别的地方调用了QApplication::setOverrideCursor如果有需要配对restoreOverrideCursor()调用。还有一个容易被忽略的点如果你在ui文件里修改过QTextEdit的对象名要保证ui-Nutation_ReadonlyArea这个名字在编译期没有飘红。名字不一致时Qt 的 moc 系统会在编译阶段直接报错根本走不到运行期。6.2 Codex 侧调用报错如果 Codex 返回401 Unauthorized说明TAOTOKEN_API_KEY环境变量没有正确导出或者 Key 本身无效。重新检查export TAOTOKEN_API_KEYYOUR_API_KEY如果返回model not found说明配置文件里的model值不是模型广场当前列表里的 ID。打开 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 重新确认模型 ID然后改回~/.codex/config.toml。如果连接超时或 connection refused先别怀疑 Codex 配置。用 curl 测一下接口通不通curl https://taotoken.net/api注意这里测的是接口地址不是官网落地页。官网地址是给人开 Key 和查用量用的填进 Codex 的base_url反而连不上。跑通一次之后这类“明明只设一个光标属性为什么就是不生效”的小问题直接丢给 Codex 就能快速拿到带解释的代码。Key 放在环境变量里随时可以吊销重发下次再遇到类似的 Qt 细节需求就不用反复编译试错了。