菜单

文本输入和编辑

相关源文件

本页面介绍了 Dear ImGui 的文本输入和编辑系统,该系统提供了用于文本输入和操作的小部件。该系统包括单行和多行文本输入、带提示文本的输入,以及对自定义回调以控制文本输入行为的支持。有关通用文本显示和渲染的信息,请参阅 文本

概述

Dear ImGui 在其即时模式 UI 范式之上提供了一个全面的文本输入系统。该系统支持标准的文本编辑功能,包括:

  • 单行和多行文本输入
  • 文本选择和光标移动
  • 复制/粘贴功能
  • 撤销/重做操作
  • 输入时过滤字符
  • 占位符/提示文本
  • 基于回调的定制

来源: imgui.h238-271 imgui_widgets.cpp136-139 imstb_textedit.h83-98

文本输入小部件

Dear ImGui 提供了三个主要文本输入小部件:

小部件描述关键参数
InputText()单行文本输入标签、缓冲区、大小、标志、回调
InputTextMultiline()多行文本输入标签、缓冲区、大小、框大小、标志、回调
InputTextWithHint()单行文本输入,空时显示灰色提示文本标签、提示、缓冲区、大小、标志、回调

基本用法

来源: imgui.h670-677 imgui_widgets.cpp48-82

文本输入标志

文本输入行为可以通过在调用输入函数时使用 ImGuiInputTextFlags 进行自定义。

标志描述
ImGuiInputTextFlags_CharsDecimal允许 0-9, ., -
ImGuiInputTextFlags_CharsHexadecimal允许 0-9, a-f, A-F
ImGuiInputTextFlags_CharsUppercase将小写字母转换为大写
ImGuiInputTextFlags_CharsNoBlank过滤掉空格/制表符
ImGuiInputTextFlags_AutoSelectAll第一次获得焦点时选择全部文本
ImGuiInputTextFlags_EnterReturnsTrue按下 Enter 时返回“true”
ImGuiInputTextFlags_CallbackCompletion按 Tab 键调用回调(用于补全)
ImGuiInputTextFlags_CallbackHistory按向上/向下箭头调用回调(用于历史记录)
ImGuiInputTextFlags_CallbackAlways每一帧都调用回调
ImGuiInputTextFlags_CallbackCharFilter调用回调以过滤字符
ImGuiInputTextFlags_AllowTabInput允许输入制表符
ImGuiInputTextFlags_CtrlEnterForNewLine在多行模式下,按 Enter 失去焦点,按 Ctrl+Enter 添加新行
ImGuiInputTextFlags_NoHorizontalScroll禁用单行输入的滚动
ImGuiInputTextFlags_AlwaysOverwrite覆盖模式
ImGuiInputTextFlags_ReadOnly只读模式
ImGuiInputTextFlags_Password密码模式,将所有字符显示为“*”
ImGuiInputTextFlags_NoUndoRedo禁用撤销/重做
ImGuiInputTextFlags_ResizeBuffer允许通过回调调整缓冲区容量

来源: imgui.h238-271

文本输入生命周期

来源: imgui_widgets.cpp5904-6766 imgui.h238-271

键盘控制和导航

Dear ImGui 的文本编辑器实现了标准的键盘控制:

操作键盘快捷键
选择文本按住 SHIFT 或拖动鼠标
单词跳转CTRL+左/右
选择单词CTRL+Shift+左/右
全选CTRL+A 或双击
复制CTRL+C
剪切CTRL+X
粘贴CTRL+V
撤销CTRL+Z
重做CTRL+Y 或 CTRL+Shift+Z
恢复文本ESCAPE
换行Enter(多行模式)
单行模式换行在具有 ImGuiInputTextFlags_CtrlEnterForNewLine 时按 Ctrl+Enter

注意:在 macOS 上,控件会自动调整以匹配标准的 macOS 文本编辑快捷方式和行为。

来源: imgui.cpp140-148 imgui_widgets.cpp5941-6010

回调系统

回调系统允许通过应用程序定义的函数对文本输入行为进行深度定制。

来源: imgui_widgets.cpp136-139 imgui.h270-271

回调函数签名

回调函数会根据事件的不同,接收不同的 EventFlag 值。

  • ImGuiInputTextFlags_CallbackCompletion:按下 Tab 键
  • ImGuiInputTextFlags_CallbackHistory:按下向上/向下箭头
  • ImGuiInputTextFlags_CallbackAlways:每一帧都调用
  • ImGuiInputTextFlags_CallbackCharFilter:输入字符时调用
  • ImGuiInputTextFlags_CallbackResize:缓冲区需要调整大小(由 std::string 包装器内部使用)

来源: imgui.h270-271 imgui_widgets.cpp30-46

ImGuiInputTextCallbackData 结构

ImGuiInputTextCallbackData 结构通过自定义函数向回调函数提供上下文,并允许其操作文本输入状态。

成员类型描述
EventFlagImGuiInputTextFlags其中一个回调标志,指示事件类型
标志ImGuiInputTextFlags传递给 InputText() 的输入标志的副本
UserDatavoid*传递给 InputText() 的自定义用户数据
EventCharImWchar字符输入(用于 CharFilter 事件)
EventKeyImGuiKey按下的键(用于 Completion/History 事件)
Bufchar*文本缓冲区 - 可在回调中修改
BufTextLenint缓冲区中的当前文本长度
BufSizeint缓冲区大小
BufDirtybool如果修改了 Buf/BufTextLen,则设置为 true
CursorPosint当前光标位置
SelectionStartint选择开始索引
SelectionEndint选择结束索引

还有一些辅助方法:

  • DeleteChars(pos, bytes_count)
  • InsertChars(pos, text, text_end = NULL)
  • SelectAll()
  • ClearSelection()
  • HasSelection() -> bool

来源: imgui.h183-182 imgui_widgets.cpp136-139

C++ STL 与 imgui_stdlib 的集成

Dear ImGui 通过 imgui_stdlib.himgui_stdlib.cpp 文件提供 STL 集成,这些文件提供了直接与 std::string 配合使用的包装函数。

这些函数会自动处理缓冲区大小调整,并且比 C 风格的 char 数组函数更易于使用。

使用示例

来源: misc/cpp/imgui_stdlib.h20-22 misc/cpp/imgui_stdlib.cpp48-82

内部实现

文本缓冲区管理

Dear ImGui 的文本输入系统通过以下几个关键组件管理文本:

  1. ImGuiInputTextState:维护文本输入的活动状态,包括:

    • 缓冲区指针
    • 光标位置和选择
    • 滚动位置
    • 用于撤销/重做的编辑历史
  2. STB TextEdit:Dear ImGui 使用修改版的 stb_textedit.h 来实现核心文本编辑功能。

    • 光标移动
    • 文本选择
    • 删除和插入
    • 撤销/重做堆栈
  3. InputTextFilterCharacter:根据标志和回调过滤输入字符。

文本输入的渲染和样式

文本输入的渲染包括:

  • 光标渲染(覆盖模式下的垂直线或块)
  • 文本选择高亮
  • 占位符文本支持
  • 密码掩码
  • 长内容的水平滚动
  • 多行文本带垂直滚动

文本输入的视觉外观可以使用 ImGui 样式进行自定义:

  • ImGuiCol_Text:文本颜色
  • ImGuiCol_TextDisabled:禁用文本颜色(用于提示/占位符)
  • ImGuiCol_FrameBg:背景颜色
  • ImGuiCol_FrameBgHovered:鼠标悬停时的背景
  • ImGuiCol_FrameBgActive:激活时的背景
  • ImGuiCol_InputTextCursor:光标颜色

来源: imgui_widgets.cpp5904-6766 imstb_textedit.h1-160 imgui_draw.cpp220

常见用例和模式

过滤输入字符

实现自动补全

命令历史导航

来源:imgui_widgets.cpp136-139 imgui_demo.cpp4284-4389

最佳实践

  1. 缓冲区管理:

    • 始终确保缓冲区足够大(包括 null 终止符)
    • 考虑使用 std::string 结合 imgui_stdlib 包装器以实现自动缓冲区管理
  2. 事件处理:

    • 使用 ImGui::IsItemDeactivatedAfterEdit() 来检测用户何时完成编辑且值已更改
    • 使用 ImGui::IsItemActive() 来检查输入当前是否正在被编辑
  3. 性能:

    • 避免每帧重新创建大型缓冲区
    • 对于非常大的文本,请考虑使用 ImGuiTextBuffer 来高效追加
  4. 可用性:

    • 使用适当的标志,例如 ImGuiInputTextFlags_EnterReturnsTrue 用于表单
    • 使用 InputTextWithHint 添加描述性提示
    • 提供适当的验证反馈

来源:imgui_widgets.cpp5904-6766 imgui.h238-271 imgui_demo.cpp4284-4389