From 9424ddd0c2e0110a50d355fb9ecae72dc14e4e45 Mon Sep 17 00:00:00 2001 From: Rowland <975945824@qq.com> Date: Fri, 16 Jan 2026 09:36:35 +0800 Subject: [PATCH] =?UTF-8?q?ui=E6=9B=BF=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- check_docking.py | 21 ++++++++++++ core/imgui_style_manager.py | 27 +++++++--------- demo.py | 57 +++++++++++++++++---------------- imgui.ini | 64 +++++++++++++++++++++++++++++-------- test_docking.py | 52 ++++++++++++++++++++++++++++++ 5 files changed, 166 insertions(+), 55 deletions(-) create mode 100644 check_docking.py create mode 100644 test_docking.py diff --git a/check_docking.py b/check_docking.py new file mode 100644 index 00000000..3078b445 --- /dev/null +++ b/check_docking.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +""" +验证ImGui docking功能是否启用 +""" +from imgui_bundle import imgui + +# 创建一个虚拟的IO对象来检查标志 +import imgui_bundle +print("检查ImGui docking支持...") +print(f"ConfigFlags_.docking_enable 存在: {hasattr(imgui.ConfigFlags_, 'docking_enable')}") +print(f"dock_space_over_viewport 存在: {hasattr(imgui, 'dock_space_over_viewport')}") + +# 检查docking标志值 +docking_flag = imgui.ConfigFlags_.docking_enable +print(f"Docking标志值: {docking_flag}") + +# 检查窗口标志 +print(f"WindowFlags_.no_title_bar 存在: {hasattr(imgui.WindowFlags_, 'no_title_bar')}") +print(f"WindowFlags_.no_collapse 存在: {hasattr(imgui.WindowFlags_, 'no_collapse')}") + +print("\n✓ ImGui docking API 可用!") \ No newline at end of file diff --git a/core/imgui_style_manager.py b/core/imgui_style_manager.py index 42c10391..ed1b643e 100644 --- a/core/imgui_style_manager.py +++ b/core/imgui_style_manager.py @@ -3,8 +3,7 @@ ImGui样式管理器 用于统一管理ImGui UI样式,与主程序Qt UI保持一致 """ -import imgui -from imgui_bundle import imgui_ctx +from imgui_bundle import imgui, imgui_ctx import os import platform from pathlib import Path @@ -210,27 +209,25 @@ class ImGuiStyleManager: print("✓ ImGui样式已应用,与Qt UI保持一致") def get_window_flags(self, window_type="default"): - """获取不同类型窗口的标志""" + """获取不同类型窗口的标志(支持docking)""" base_flags = 0 if window_type == "main_menu": - return imgui.WINDOW_MENU_BAR + return imgui.WindowFlags_.menu_bar elif window_type == "dockable": + # 移除NO_MOVE和NO_RESIZE以支持docking return (base_flags | - imgui.WINDOW_NO_TITLE_BAR | - imgui.WINDOW_NO_RESIZE | - imgui.WINDOW_NO_MOVE | - imgui.WINDOW_NO_COLLAPSE) + imgui.WindowFlags_.no_title_bar | + imgui.WindowFlags_.no_collapse) elif window_type == "toolbar": + # 工具栏允许docking但保持无标题栏 return (base_flags | - imgui.WINDOW_NO_TITLE_BAR | - imgui.WINDOW_NO_RESIZE | - imgui.WINDOW_NO_MOVE | - imgui.WINDOW_NO_COLLAPSE | - imgui.WINDOW_NO_SCROLLBAR) + imgui.WindowFlags_.no_title_bar | + imgui.WindowFlags_.no_collapse | + imgui.WindowFlags_.no_scrollbar) elif window_type == "panel": - return (base_flags | - imgui.WINDOW_NO_COLLAPSE) + # 面板窗口完全支持docking + return base_flags # 移除NO_COLLAPSE限制 return base_flags diff --git a/demo.py b/demo.py index 15feb001..51d76f7b 100644 --- a/demo.py +++ b/demo.py @@ -115,6 +115,10 @@ class MyWorld(CoreWorld): # Install Dear ImGui p3dimgui.init() + # 启用ImGui Docking功能 + imgui.get_io().config_flags |= imgui.ConfigFlags_.docking_enable + print("✓ ImGui Docking功能已启用") + # 初始化样式管理器 from core.imgui_style_manager import ImGuiStyleManager self.style_manager = ImGuiStyleManager(self.imgui) @@ -311,6 +315,11 @@ class MyWorld(CoreWorld): def __newFrame(self): # Dear ImGui commands can be placed here. + # 创建全屏DockSpace(在第一帧之后创建) + if imgui.get_frame_count() > 0: + viewport = imgui.get_main_viewport() + imgui.dock_space_over_viewport(0, viewport, imgui.DockNodeFlags_.passthru_central_node) + # 在第一帧应用样式 if imgui.get_frame_count() == 0: self.style_manager.apply_style() @@ -379,46 +388,25 @@ class MyWorld(CoreWorld): imgui.show_demo_window() def _draw_docked_layout(self, window_width, window_height): - """绘制停靠布局(模拟)""" - # 布局参数 - left_panel_width = 250 - right_panel_width = 300 - top_toolbar_height = 40 - bottom_console_height = 150 - menu_bar_height = 20 - + """绘制可停靠的布局(支持拖拽)""" # 左侧场景树面板 if self.showSceneTree: - imgui.set_next_window_pos((0, menu_bar_height), imgui.Cond_.always.value) - imgui.set_next_window_size((left_panel_width, window_height - menu_bar_height - bottom_console_height), imgui.Cond_.always.value) self._draw_scene_tree() - # 右侧面板区域 - right_panel_y = menu_bar_height - right_panel_height = (window_height - menu_bar_height - bottom_console_height) // 2 - # 属性面板 if self.showPropertyPanel: - imgui.set_next_window_pos((window_width - right_panel_width, right_panel_y), imgui.Cond_.always.value) - imgui.set_next_window_size((right_panel_width, right_panel_height), imgui.Cond_.always.value) self._draw_property_panel() # 脚本面板 if self.showScriptPanel: - imgui.set_next_window_pos((window_width - right_panel_width, right_panel_y + right_panel_height), imgui.Cond_.always.value) - imgui.set_next_window_size((right_panel_width, right_panel_height), imgui.Cond_.always.value) self._draw_script_panel() # 底部控制台 if self.showConsole: - imgui.set_next_window_pos((0, window_height - bottom_console_height), imgui.Cond_.always.value) - imgui.set_next_window_size((window_width, bottom_console_height), imgui.Cond_.always.value) self._draw_console() # 顶部工具栏 if self.showToolbar: - imgui.set_next_window_pos((left_panel_width, menu_bar_height), imgui.Cond_.always.value) - imgui.set_next_window_size((window_width - left_panel_width - right_panel_width, top_toolbar_height), imgui.Cond_.always.value) self._draw_toolbar() @@ -486,7 +474,10 @@ class MyWorld(CoreWorld): def _draw_toolbar(self): """绘制工具栏""" - with self.style_manager.begin_styled_window("工具栏", self.showToolbar): + # 工具栏可以保持无标题栏,但允许移动和调整大小 + flags = self.style_manager.get_window_flags("toolbar") + + with self.style_manager.begin_styled_window("工具栏", self.showToolbar, flags): self.showToolbar = True # 确保窗口保持打开 # 工具按钮组 @@ -548,7 +539,10 @@ class MyWorld(CoreWorld): def _draw_scene_tree(self): """绘制场景树面板""" - with self.style_manager.begin_styled_window("场景树", self.showSceneTree): + # 使用更少的限制性标志,允许docking + flags = (imgui.WindowFlags_.no_collapse) + + with self.style_manager.begin_styled_window("场景树", self.showSceneTree, flags): self.showSceneTree = True # 确保窗口保持打开 imgui.text("场景层级") @@ -577,7 +571,10 @@ class MyWorld(CoreWorld): def _draw_property_panel(self): """绘制属性面板""" - with self.style_manager.begin_styled_window("属性面板", self.showPropertyPanel): + # 使用面板类型的窗口标志,支持docking + flags = self.style_manager.get_window_flags("panel") + + with self.style_manager.begin_styled_window("属性面板", self.showPropertyPanel, flags): self.showPropertyPanel = True # 确保窗口保持打开 imgui.text("对象属性") @@ -605,7 +602,10 @@ class MyWorld(CoreWorld): def _draw_console(self): """绘制控制台面板""" - with self.style_manager.begin_styled_window("控制台", self.showConsole): + # 使用面板类型的窗口标志,支持docking + flags = self.style_manager.get_window_flags("panel") + + with self.style_manager.begin_styled_window("控制台", self.showConsole, flags): self.showConsole = True # 确保窗口保持打开 imgui.text("控制台输出") @@ -645,7 +645,10 @@ class MyWorld(CoreWorld): def _draw_script_panel(self): """绘制脚本管理面板""" - with self.style_manager.begin_styled_window("脚本管理", self.showScriptPanel): + # 使用面板类型的窗口标志,支持docking + flags = self.style_manager.get_window_flags("panel") + + with self.style_manager.begin_styled_window("脚本管理", self.showScriptPanel, flags): self.showScriptPanel = True # 确保窗口保持打开 imgui.text("脚本列表") diff --git a/imgui.ini b/imgui.ini index f5ab8041..3fd04bf3 100644 --- a/imgui.ini +++ b/imgui.ini @@ -19,37 +19,75 @@ Size=745,76 Collapsed=0 [Window][Dear ImGui Demo] -Pos=948,19 -Size=550,680 -Collapsed=1 +Pos=241,149 +Size=832,127 +Collapsed=0 [Window][工具栏] -Pos=250,20 -Size=1300,40 +Pos=287,20 +Size=832,32 Collapsed=0 +DockId=0x00000007,0 [Window][场景树] Pos=0,20 -Size=250,846 +Size=285,578 Collapsed=0 +DockId=0x00000001,0 [Window][属性面板] -Pos=1550,20 -Size=300,423 -Collapsed=1 +Pos=1121,20 +Size=259,214 +Collapsed=0 +DockId=0x00000005,0 [Window][控制台] -Pos=0,866 -Size=1850,150 +Pos=0,600 +Size=1380,150 Collapsed=0 +DockId=0x0000000A,0 [Window][脚本管理] -Pos=1550,443 -Size=300,423 +Pos=1121,236 +Size=259,362 Collapsed=0 +DockId=0x00000006,0 [Window][中文显示测试] Pos=60,60 Size=135,263 Collapsed=0 +[Window][WindowOverViewport_11111111] +Pos=0,20 +Size=1380,730 +Collapsed=0 + +[Window][测试窗口1] +Pos=60,60 +Size=121,82 +Collapsed=0 + +[Window][测试窗口2] +Pos=60,60 +Size=121,82 +Collapsed=0 + +[Window][测试窗口3] +Pos=60,60 +Size=93,65 +Collapsed=0 + +[Docking][Data] +DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=0,20 Size=1380,730 Split=Y + DockNode ID=0x00000009 Parent=0x08BD597D SizeRef=1380,578 Split=X + DockNode ID=0x00000003 Parent=0x00000009 SizeRef=1119,730 Split=X + DockNode ID=0x00000001 Parent=0x00000003 SizeRef=285,730 HiddenTabBar=1 Selected=0xE0015051 + DockNode ID=0x00000002 Parent=0x00000003 SizeRef=832,730 Split=Y + DockNode ID=0x00000007 Parent=0x00000002 SizeRef=1380,32 HiddenTabBar=1 Selected=0x43A39006 + DockNode ID=0x00000008 Parent=0x00000002 SizeRef=1380,696 CentralNode=1 Selected=0x5E5F7166 + DockNode ID=0x00000004 Parent=0x00000009 SizeRef=259,730 Split=Y Selected=0x5DB6FF37 + DockNode ID=0x00000005 Parent=0x00000004 SizeRef=259,270 HiddenTabBar=1 Selected=0x5DB6FF37 + DockNode ID=0x00000006 Parent=0x00000004 SizeRef=259,458 HiddenTabBar=1 Selected=0x3188AB8D + DockNode ID=0x0000000A Parent=0x08BD597D SizeRef=1380,150 HiddenTabBar=1 Selected=0x5428E753 + diff --git a/test_docking.py b/test_docking.py new file mode 100644 index 00000000..3efc54ba --- /dev/null +++ b/test_docking.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 +""" +测试ImGui docking功能 +""" +from direct.showbase.ShowBase import ShowBase +import p3dimgui +from imgui_bundle import imgui, imgui_ctx + +class DockingTest(ShowBase): + def __init__(self): + ShowBase.__init__(self) + + # Install Dear ImGui + p3dimgui.init() + + # 启用ImGui Docking功能 + imgui.get_io().config_flags |= imgui.ConfigFlags_.docking_enable + print("✓ ImGui Docking功能已启用") + + # 添加任务 + self.taskMgr.add(self.__newFrame, "imgui-new-frame") + + def __newFrame(self, task): + # 创建全屏DockSpace(在第一帧之后创建) + if imgui.get_frame_count() > 0: + viewport = imgui.get_main_viewport() + imgui.dock_space_over_viewport(0, viewport, imgui.DockNodeFlags_.passthru_central_node) + + # 测试窗口 + if imgui.get_frame_count() > 10: # 等待几帧后显示 + # 窗口1 + with imgui_ctx.begin("测试窗口1", True): + imgui.text("这是第一个测试窗口") + imgui.text("你可以拖拽标题栏来移动窗口") + imgui.text("也可以拖拽到其他窗口边缘来停靠") + + # 窗口2 + with imgui_ctx.begin("测试窗口2", True): + imgui.text("这是第二个测试窗口") + imgui.text("尝试将这个窗口停靠到第一个窗口") + imgui.text("或者创建标签页") + + # 窗口3 + with imgui_ctx.begin("测试窗口3", True): + imgui.text("这是第三个测试窗口") + imgui.text("自由调整窗口大小和位置") + + return task.cont + +if __name__ == "__main__": + test = DockingTest() + test.run() \ No newline at end of file