DockBuilder로 레이아웃 구성

메쉬·어셈블리·뷰포트가 있는 도구를 ImGui로 만들면, 창을 손으로 하나씩 배치하는 순간 레이아웃이 흔들립니다. 이 글에서는 Docking 을 켠 뒤 DockBuilder 로 Viewport / Hierarchy / Properties / Log 네 영역을 초기 레이아웃으로 고정하는 패턴을 정리합니다.

완성할 예제

예제는 다음을 한 프레임 안에서 구성합니다.

  • ImGuiConfigFlags_DockingEnable로 도킹 활성화

  • 전체 뷰포트를 덮는 DockSpace 호스트

  • DockBuilderSplitNode로 좌·우·하단 분할

  • Viewport / Hierarchy / Properties / Log 창을 각 독에 고정

읽고 나면 “첫 실행 시 CAD형 셸”을 코드로 재현할 수 있습니다.

왜 DockBuilder가 필요한가

일반 사용자는 창을 드래그해 배치할 수 있지만, ​첫 실행 기본 배치 는 제품 경험이 됩니다. 수동 SetNextWindowPos만으로는 도킹 관계가 생기지 않고, 리사이즈·모니터 변경에도 약합니다.

관심사는 대략 다음과 같습니다.

  1. 도킹 플래그 — IO에 DockingEnable

  2. 호스트 — DockSpace / DockSpaceOverViewport

  3. 트리 분할 — DockBuilderSplitNode

  4. 창 고정 — DockBuilderDockWindow

  5. 완료 — DockBuilderFinish

레이아웃 스케치

목표 배치는 전형적인 CAD 셸입니다.

Text

+------------------+------------------+ | | Hierarchy | | Viewport +------------------+ | | Properties | +------------------+------------------+ | Log | +-------------------------------------+

중앙·좌측이 뷰포트, 우측 상단이 계층, 우측 하단이 속성, 하단이 로그입니다.

도킹 활성화와 DockSpace

초기화 시점에 플래그를 켭니다. 매 프레임이 아니라 컨텍스트 생성 직후가 일반적입니다.

Cpp

ImGuiIO& io = ImGui::GetIO(); io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // 필요 시: io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;

프레임마다 호스트 윈도우와 DockSpace를 제출합니다.

Cpp

void ShowEditorDockSpace(bool* p_open) { const ImGuiViewport* viewport = ImGui::GetMainViewport(); ImGui::SetNextWindowPos(viewport->WorkPos); ImGui::SetNextWindowSize(viewport->WorkSize); ImGui::SetNextWindowViewport(viewport->ID); ImGuiWindowFlags host_flags = ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus; ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); ImGui::Begin("EditorDockHost", p_open, host_flags); ImGui::PopStyleVar(2); const ImGuiID dockspace_id = ImGui::GetID("EditorDockSpace"); ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), ImGuiDockNodeFlags_PassthruCentralNode); ImGui::End(); // 최초 1회만 레이아웃 빌드 static bool layout_built = false; if (!layout_built) { BuildCadLayout(dockspace_id); layout_built = true; } }

DockBuilder로 분할하기

imgui_internal.h를 포함한 뒤, 노드를 만들고 비율로 자릅니다.

Cpp

#include "imgui_internal.h" void BuildCadLayout(ImGuiID dockspace_id) { ImGui::DockBuilderRemoveNode(dockspace_id); ImGui::DockBuilderAddNode(dockspace_id, ImGuiDockNodeFlags_DockSpace); ImGui::DockBuilderSetNodeSize(dockspace_id, ImGui::GetMainViewport()->Size); ImGuiID dock_main = dockspace_id; ImGuiID dock_right = ImGui::DockBuilderSplitNode( dock_main, ImGuiDir_Right, 0.28f, nullptr, &dock_main); ImGuiID dock_bottom = ImGui::DockBuilderSplitNode( dock_main, ImGuiDir_Down, 0.22f, nullptr, &dock_main); ImGuiID dock_right_bottom = ImGui::DockBuilderSplitNode( dock_right, ImGuiDir_Down, 0.45f, nullptr, &dock_right); // dock_main → Viewport // dock_right → Hierarchy // dock_right_bottom → Properties // dock_bottom → Log ImGui::DockBuilderDockWindow("Viewport", dock_main); ImGui::DockBuilderDockWindow("Hierarchy", dock_right); ImGui::DockBuilderDockWindow("Properties", dock_right_bottom); ImGui::DockBuilderDockWindow("Log", dock_bottom); ImGui::DockBuilderFinish(dockspace_id); }

창 이름은 이후에 ImGui::Begin("Viewport") 등과 ​문자열로 일치 해야 합니다. 공백·대소문자가 다르면 독에 붙지 않습니다.

네 창 본문

레이아웃만 잡고 내용은 최소로 둡니다.

Cpp

void DrawEditorWindows() { if (ImGui::Begin("Viewport")) { ImGui::TextUnformatted("3D view (texture / FBO goes here)"); } ImGui::End(); if (ImGui::Begin("Hierarchy")) { ImGui::TextUnformatted("Scene tree"); } ImGui::End(); if (ImGui::Begin("Properties")) { ImGui::TextUnformatted("Selected object fields"); } ImGui::End(); if (ImGui::Begin("Log")) { ImGui::TextUnformatted("Messages..."); } ImGui::End(); }

메인 루프에서는 NewFrame 이후 ShowEditorDockSpaceDrawEditorWindows 순서가 자연스럽습니다.

설계 체크리스트

  1. docking 브랜치(또는 docking이 포함된 빌드)를 링크했는지 확인합니다.

  2. DockingEnable을 컨텍스트 생성 직후 켭니다.

  3. DockSpace 호스트를 도킹 창보다 먼저 제출합니다.

  4. Begin 창 이름과 DockBuilderDockWindow 이름을 동일하게 둡니다.

  5. 레이아웃 빌드는 최초 1회 또는 명시적 Reset에서만 수행합니다.

  6. 중앙 노드에 뷰포트를 두고, 보조 패널은 가장자리로 보냅니다.

자주 발생하는 문제

창이 독에 붙지 않음

창 이름 불일치, 또는 DockSpace보다 먼저 Begin한 경우입니다. 제출 순서를 바꾸고 문자열을 대조합니다.

분할 비율이 기대와 다름

DockBuilderSplitNode의 비율은 ​잘려 나가는 쪽 기준입니다. 좌/우/상/하 방향을 바꾼 뒤 비율을 다시 맞춥니다.

매 실행마다 레이아웃이 초기화됨

layout_built 가드를 빼먹었거나, 매 프레임 RemoveNode를 호출하는 경우입니다. Reset 액션과 최초 빌드를 분리합니다.

중앙이 비어 보이거나 클릭이 통과함

PassthruCentralNode와 뷰포트 창의 배경/입력 처리를 함께 설계해야 합니다. 뷰포트에 실제 컨텐츠(Image 등)를 그리는 다음 글로 이어집니다.

공식 위키의 Docking 페이지와 imgui_demo.cpp의 Docking 섹션을 함께 보면 API 조합 예제를 빠르게 확인할 수 있습니다.

On this page