如何在ImGui中创建表格并实现整体绕中心旋转?
在ImGui中实现旋转表格的方案
核心思路
ImGui本身没有直接支持UI元素旋转的API,但可以通过修改ImDrawList的渲染变换矩阵实现表格整体旋转。关键是围绕表格中心构建旋转变换,绘制表格时应用该变换,绘制完成后恢复原变换。
具体实现步骤
1. 提前计算表格的尺寸与中心位置
首先需要确定表格的整体尺寸,才能找到旋转中心。如果表格高度是动态计算的,可预计算总高度:
// 计算表格总高度 float totalTableHeight = 0.0f; for (int row = 0; row < globalRowCount; row++) { totalTableHeight += row_heights[row] * dpi; } // 获取表格左上角的屏幕坐标 ImVec2 tablePos = ImGui::GetCursorScreenPos(); // 计算表格中心坐标 ImVec2 tableCenter = ImVec2( tablePos.x + tableWidth / 2.0f, tablePos.y + totalTableHeight / 2.0f );
2. 应用旋转变换矩阵
在绘制表格前,向ImGui的绘图列表中推入旋转变换,构建围绕中心旋转的矩阵:
ImGuiWindow* window = ImGui::GetCurrentWindow(); ImDrawList* drawList = window->DrawList; // 旋转角度(弧度制,示例为30度,可替换为自定义角度) float rotationAngle = ImGui::DegToRad(30.0f); // 构建变换矩阵:平移到原点→旋转→平移回中心 ImMatrix4x4 transform = ImMatrix4x4::Identity(); transform.Translate(-tableCenter.x, -tableCenter.y, 0.0f); transform.RotateZ(rotationAngle); transform.Translate(tableCenter.x, tableCenter.y, 0.0f); // 推入变换 drawList->PushTransform(transform);
3. 处理鼠标交互匹配问题
旋转后的表格会出现鼠标点击位置与UI元素不匹配的情况,需要临时转换鼠标坐标:
// 保存原始鼠标位置 ImVec2 originalMousePos = ImGui::GetMousePos(); // 反向转换鼠标位置到旋转后的坐标系 ImVec2 transformedMousePos = transform.Inverted().TransformPoint(originalMousePos); // 临时替换鼠标位置 ImGui::SetMousePos(transformedMousePos);
4. 绘制表格(保留原有代码)
将你已有的表格绘制代码放在变换生效期间:
ImGui::BeginTable(tableId.c_str(), globalColumnCount, tableFlags, ImVec2(tableWidth, totalTableHeight)); // 你的原有列设置代码 for (int col = 0; col < globalColumnCount; col++) { ImGui::TableSetupColumn(headers[col].c_str(), ImGuiTableColumnFlags_WidthStretch, 0.0f, col / static_cast<float>(globalColumnCount)); } // 你的原有行绘制代码 for (int row = 0; row < globalRowCount; row++) { ImGui::TableNextRow(); float cellRowHeight = row_heights[row] * dpi; ImGui::SetCursorPosY(ImGui::GetCursorPosY() + cellRowHeight); if (row < globalheadercount) { for (int col = 0; col < globalColumnCount; col++) { ImGui::TableNextColumn(); ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ImGui::GetColorU32(ImVec4(0.0f, 0.0f, 0.0f, 0.0f))); ImGui::Text(""); } } else if (row >= globalheadercount + globalBodyCount) { for (int col = 0; col < globalColumnCount; col++) { ImGui::TableNextColumn(); ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ImGui::GetColorU32(ImVec4(0.0f, 0.0f, 0.0f, 0.0f))); ImGui::Text(""); } } else { ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0, 0, 0, 0)); ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0, 0, 0, 1)); for (int col = 0; col < globalColumnCount; col++) { ImGui::TableNextColumn(); std::string inputID = "###Input_" + elem_id + "_" + std::to_string(row) + "_" + std::to_string(col); ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0, 0, 0, 1)); ImGui::InputText(inputID.c_str(), &cellTexts[tableIndex][row * globalColumnCount + col]); ImGui::PopStyleColor(); } ImGui::PopStyleColor(2); } } ImGui::EndTable();
5. 恢复原状态
表格绘制完成后,恢复鼠标位置与渲染变换:
// 恢复原始鼠标位置 ImGui::SetMousePos(originalMousePos); // 弹出变换,避免影响后续UI drawList->PopTransform();
注意事项
- 确保使用的ImGui版本支持
ImDrawList::PushTransform和ImMatrix4x4(ImGui 1.89及以上版本已支持)。 - 如果表格尺寸随内容动态变化,需每次绘制时重新计算尺寸与中心。
- 旋转角度需使用弧度制,可通过
ImGui::DegToRad()将角度转换为弧度。
内容的提问来源于stack exchange,提问作者Kazi Ruvef
相关产品推荐
相关产品推荐

