This commit is contained in:
Rowland 2026-01-08 16:30:59 +08:00
parent 1fc3e154d1
commit 1ad2086525
8 changed files with 2150 additions and 583 deletions

File diff suppressed because it is too large Load Diff

166
core/imgui_manager.py Normal file
View File

@ -0,0 +1,166 @@
"""
pyimgui管理器 - 在Panda3D引擎上集成ImGui界面
"""
import imgui
import OpenGL.GL as gl
from panda3d.core import RenderState, ShaderAttrib, Texture, CardMaker, NodePath
from panda3d.core import TransparencyAttrib, ColorBlendAttrib
from direct.task.Task import Task
import numpy as np
class ImGuiManager:
"""ImGui管理器负责在Panda3D引擎上渲染ImGui界面"""
def __init__(self, world):
self.world = world
self.io = None
self.font_texture = None
self._setup_imgui()
self._create_imgui_task()
# UI状态
self.show_demo_window = False
self.show_test_button = True
self.button_clicked = False
def _setup_imgui(self):
"""初始化ImGui设置"""
# 初始化ImGui上下文
imgui.create_context()
self.io = imgui.get_io()
# 设置显示大小
win_props = self.world.win.getProperties()
self.io.display_size = (win_props.get_x_size(), win_props.get_y_size())
# 设置渲染回调
self.io.render_callback = self._render_imgui
# 创建字体纹理
self._create_font_texture()
print("✓ ImGui初始化完成")
def _create_font_texture(self):
"""创建ImGui字体纹理"""
# 获取字体数据
font_pixels = self.io.fonts.get_tex_data_as_rgba32()
width, height = self.io.fonts.get_tex_data_as_rgba32()[1]
# 创建Panda3D纹理
self.font_texture = Texture()
self.font_texture.setup_2d_texture(width, height, Texture.T_unsigned_byte, Texture.F_rgba8)
self.font_texture.set_ram_image(font_pixels)
# 设置纹理ID
self.io.fonts.tex_id = self.font_texture
# 清除字体数据
self.io.fonts.clear_tex_data()
def _render_imgui(self, draw_data):
"""渲染ImGui绘制数据"""
if not draw_data:
return
# 设置OpenGL状态
gl.glEnable(gl.GL_BLEND)
gl.glBlendEquation(gl.GL_FUNC_ADD)
gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
gl.glDisable(gl.GL_CULL_FACE)
gl.glDisable(gl.GL_DEPTH_TEST)
gl.glEnable(gl.GL_SCISSOR_TEST)
# 设置视口和投影矩阵
display_w, display_h = self.io.display_size
gl.glViewport(0, 0, int(display_w), int(display_h))
# 获取投影矩阵
projection_matrix = self._get_projection_matrix()
gl.glMatrixMode(gl.GL_PROJECTION)
gl.glLoadMatrixf(projection_matrix)
# 渲染每个命令列表
for commands in draw_data.commands_lists:
# 渲染命令
self._render_commands(commands)
# 恢复OpenGL状态
gl.glDisable(gl.GL_SCISSOR_TEST)
gl.glEnable(gl.GL_DEPTH_TEST)
def _get_projection_matrix(self):
"""获取正交投影矩阵"""
L, R, T, B = 0, self.io.display_size[0], self.io.display_size[1], 0
projection_matrix = np.array([
[2.0/(R-L), 0.0, 0.0, 0.0],
[0.0, 2.0/(T-B), 0.0, 0.0],
[0.0, 0.0, -1.0, 0.0],
[(R+L)/(L-R), (T+B)/(B-T), 0.0, 1.0]
], dtype=np.float32)
return projection_matrix
def _render_commands(self, commands):
"""渲染ImGui命令列表"""
# 这里需要实现具体的渲染逻辑
# 由于Panda3D的渲染管线与ImGui不完全兼容我们需要创建一个自定义的渲染方法
pass
def _create_imgui_task(self):
"""创建ImGui更新任务"""
taskMgr.add(self._update_imgui, "update_imgui")
def _update_imgui(self, task):
"""更新ImGui界面"""
# 开始新帧
imgui.new_frame()
# 绘制UI
self._draw_ui()
# 渲染ImGui
imgui.render()
return Task.cont
def _draw_ui(self):
"""绘制UI元素"""
# 绘制测试按钮
if self.show_test_button:
imgui.begin("测试窗口", True)
if imgui.button("点击我!"):
self.button_clicked = True
print("按钮被点击了!")
if self.button_clicked:
imgui.text("按钮已被点击!")
imgui.end()
# 绘制演示窗口(可选)
if self.show_demo_window:
self.show_demo_window = imgui.show_demo_window(self.show_demo_window)
def toggle_demo_window(self):
"""切换演示窗口显示"""
self.show_demo_window = not self.show_demo_window
def toggle_test_button(self):
"""切换测试按钮显示"""
self.show_test_button = not self.show_test_button
def process_mouse_input(self, button_event):
"""处理鼠标输入"""
# 这里需要将Panda3D的鼠标事件转换为ImGui可以理解的事件
pass
def process_keyboard_input(self, key_event):
"""处理键盘输入"""
# 这里需要将Panda3D的键盘事件转换为ImGui可以理解的事件
pass
def cleanup(self):
"""清理资源"""
if self.font_texture:
self.font_texture = None
imgui.destroy_context()

286
core/imgui_style_manager.py Normal file
View File

@ -0,0 +1,286 @@
"""
ImGui样式管理器
用于统一管理ImGui UI样式与主程序Qt UI保持一致
"""
import imgui
from imgui_bundle import imgui_ctx
import os
import platform
from pathlib import Path
from panda3d.core import Filename
class ImGuiStyleManager:
"""ImGui样式管理器 - 负责UI样式的统一管理"""
def __init__(self, imgui_backend):
"""
初始化样式管理器
Args:
imgui_backend: ImGui后端对象
"""
self.imgui_backend = imgui_backend
self.io = imgui_backend.io
self.style = None # 延迟初始化在apply_style中设置
# 颜色定义 - 与Qt UI保持一致
self.colors = {
# 主要颜色
'primary': (0.188, 0.404, 0.753, 1.0), # #3067C0 - 主色调
'primary_dark': (0.149, 0.337, 0.627, 1.0), # #2556A0 - 按钮按下
'background': (0.0, 0.0, 0.0, 1.0), # #000000 - 主背景
'secondary_bg': (0.096, 0.096, 0.106, 1.0), # #19191B - 次背景
'panel_bg': (0.18, 0.188, 0.208, 1.0), # #2E3035 - 面板背景
'text': (0.922, 0.922, 0.922, 1.0), # #EBEBEB - 主文字
'text_secondary': (0.922, 0.922, 0.922, 0.6), # #EBEBEB - 次文字
'border': (0.243, 0.243, 0.259, 1.0), # #3E3E42 - 主要边框
'border_secondary': (0.173, 0.184, 0.212, 1.0), # #2C2F36 - 次要边框
'button_bg': (0.349, 0.384, 0.463, 0.5), # 半透明按钮背景
'input_bg': (0.349, 0.392, 0.443, 0.2), # 输入框背景
'input_border': (0.298, 0.361, 0.431, 0.6), # 输入框边框
'success': (0.176, 1.0, 0.769, 1.0), # #2dffc4 - 成功状态
'warning': (0.953, 0.616, 0.471, 1.0), # #f39d78 - 警告状态
'info': (0.157, 0.620, 1.0, 1.0), # #289eff - 信息状态
}
# 尺寸定义
self.sizes = {
'font_size': 12.0, # 与Qt一致的字体大小
'window_padding': (8.0, 8.0),
'window_rounding': 2.0,
'item_spacing': (6.0, 6.0),
'item_inner_spacing': (4.0, 4.0),
'frame_padding': (4.0, 3.0),
'frame_rounding': 2.0,
'indent_spacing': 20.0,
'scrollbar_size': 14.0,
}
# 字体设置在demo.py中直接处理这里不再初始化
def _setup_fonts(self):
"""设置字体,包括中文字体支持"""
try:
# 尝试加载中文字体
font_path = self._get_chinese_font_path()
if font_path:
# 使用p3dimgui的字体加载方法
self.imgui_backend.load_font(font_path, self.sizes['font_size'])
print(f"✓ ImGui中文字体加载成功: {font_path}")
else:
print("⚠ 无法加载中文字体,使用默认字体")
except Exception as e:
print(f"⚠ ImGui字体设置失败: {e}")
# 备用方案:尝试使用默认字体
try:
# 使用p3dimgui的默认字体
self.imgui_backend.load_font(None, self.sizes['font_size'])
except:
pass
def _get_chinese_font_path(self):
"""获取中文字体路径"""
system = platform.system().lower()
project_root = Path(__file__).resolve().parent.parent
# 候选字体路径
if system == "windows":
win_dir = os.environ.get("WINDIR") or r"C:\Windows"
font_candidates = [
project_root / "RenderPipelineFile" / "data" / "font" / "msyh.ttc",
Path(win_dir) / "Fonts" / "msyh.ttc",
Path(win_dir) / "Fonts" / "msyh.ttf",
Path(win_dir) / "Fonts" / "simhei.ttf",
]
elif system == "darwin":
font_candidates = [
Path("/System/Library/Fonts/PingFang.ttc"),
Path("/System/Library/Fonts/STHeiti.ttc"),
]
else: # Linux
font_candidates = [
Path("/usr/share/fonts/truetype/wqy/wqy-microhei.ttc"),
Path("/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc"),
]
# 尝试找到存在的字体文件
for font_path in font_candidates:
if font_path.exists():
return str(font_path)
return None
def apply_style(self):
"""应用与Qt UI一致的样式"""
# 先应用深色主题作为基础
imgui.style_colors_dark()
# 获取样式对象
self.style = imgui.get_style()
style = self.style
# 应用自定义颜色
style.colors[imgui.COLOR_WINDOW_BG] = self.colors['background']
style.colors[imgui.COLOR_CHILD_BG] = self.colors['secondary_bg']
style.colors[imgui.COLOR_POPUP_BG] = self.colors['panel_bg']
style.colors[imgui.COLOR_BORDER] = self.colors['border']
style.colors[imgui.COLOR_BORDER_SHADOW] = self.colors['border_secondary']
# 文本颜色
style.colors[imgui.COLOR_TEXT] = self.colors['text']
style.colors[imgui.COLOR_TEXT_DISABLED] = self.colors['text_secondary']
style.colors[imgui.COLOR_TEXT_SELECTED_BG] = self.colors['primary']
# 菜单栏颜色
style.colors[imgui.COLOR_MENU_BAR_BG] = self.colors['background']
# 按钮颜色
style.colors[imgui.COLOR_BUTTON] = self.colors['button_bg']
style.colors[imgui.COLOR_BUTTON_HOVERED] = self.colors['primary']
style.colors[imgui.COLOR_BUTTON_ACTIVE] = self.colors['primary_dark']
# 复选框和单选按钮
style.colors[imgui.COLOR_CHECK_MARK] = self.colors['primary']
style.colors[imgui.COLOR_RADIO_BUTTON_HOVERED] = self.colors['primary']
style.colors[imgui.COLOR_RADIO_BUTTON_ACTIVE] = self.colors['primary_dark']
# 滑块
style.colors[imgui.COLOR_SLIDER_GRAB] = self.colors['primary']
style.colors[imgui.COLOR_SLIDER_GRAB_ACTIVE] = self.colors['primary_dark']
# 进度条
style.colors[imgui.COLOR_PROGRESS_BAR_FG] = self.colors['primary']
# 标题栏
style.colors[imgui.COLOR_TITLE_BG] = self.colors['panel_bg']
style.colors[imgui.COLOR_TITLE_BG_ACTIVE] = self.colors['primary']
style.colors[imgui.COLOR_TITLE_BG_COLLAPSED] = self.colors['border_secondary']
# 输入框
style.colors[imgui.COLOR_FRAME_BG] = self.colors['input_bg']
style.colors[imgui.COLOR_FRAME_BG_HOVERED] = self.colors['input_border']
style.colors[imgui.COLOR_FRAME_BG_ACTIVE] = (
self.colors['primary'][0],
self.colors['primary'][1],
self.colors['primary'][2],
0.1 # 低透明度
)
# 标签页
style.colors[imgui.COLOR_TAB] = self.colors['button_bg']
style.colors[imgui.COLOR_TAB_HOVERED] = self.colors['primary']
style.colors[imgui.COLOR_TAB_ACTIVE] = self.colors['primary']
style.colors[imgui.COLOR_TAB_UNFOCUSED] = self.colors['button_bg']
style.colors[imgui.COLOR_TAB_UNFOCUSED_ACTIVE] = self.colors['primary_dark']
# 选择高亮
style.colors[imgui.COLOR_HEADER] = self.colors['primary']
style.colors[imgui.COLOR_HEADER_HOVERED] = self.colors['primary']
style.colors[imgui.COLOR_HEADER_ACTIVE] = self.colors['primary_dark']
# 分隔符
style.colors[imgui.COLOR_SEPARATOR] = self.colors['border_secondary']
style.colors[imgui.COLOR_SEPARATOR_HOVERED] = self.colors['border']
style.colors[imgui.COLOR_SEPARATOR_ACTIVE] = self.colors['primary']
# 调整尺寸和间距
style.window_padding = self.sizes['window_padding']
style.window_rounding = self.sizes['window_rounding']
style.window_min_size = (200, 100)
style.child_rounding = self.sizes['frame_rounding']
style.frame_padding = self.sizes['frame_padding']
style.frame_rounding = self.sizes['frame_rounding']
style.item_spacing = self.sizes['item_spacing']
style.item_inner_spacing = self.sizes['item_inner_spacing']
style.indent_spacing = self.sizes['indent_spacing']
style.scrollbar_size = self.sizes['scrollbar_size']
style.scrollbar_rounding = self.sizes['frame_rounding']
style.grab_min_size = 10.0
style.grab_rounding = self.sizes['frame_rounding']
# 禁用一些ImGui的默认效果使其更像Qt
style.window_border_size = 1.0
style.child_border_size = 1.0
style.popup_border_size = 1.0
style.frame_border_size = 1.0
print("✓ ImGui样式已应用与Qt UI保持一致")
def get_window_flags(self, window_type="default"):
"""获取不同类型窗口的标志"""
base_flags = 0
if window_type == "main_menu":
return imgui.WINDOW_MENU_BAR
elif window_type == "dockable":
return (base_flags |
imgui.WINDOW_NO_TITLE_BAR |
imgui.WINDOW_NO_RESIZE |
imgui.WINDOW_NO_MOVE |
imgui.WINDOW_NO_COLLAPSE)
elif window_type == "toolbar":
return (base_flags |
imgui.WINDOW_NO_TITLE_BAR |
imgui.WINDOW_NO_RESIZE |
imgui.WINDOW_NO_MOVE |
imgui.WINDOW_NO_COLLAPSE |
imgui.WINDOW_NO_SCROLLBAR)
elif window_type == "panel":
return (base_flags |
imgui.WINDOW_NO_COLLAPSE)
return base_flags
def begin_styled_window(self, name, open=True, flags=None, window_type="default"):
"""开始一个带样式的窗口"""
if flags is None:
flags = self.get_window_flags(window_type)
return imgui_ctx.begin(name, open, flags)
def styled_button(self, label, size=(0, 0)):
"""绘制带样式的按钮"""
return imgui.button(label, size)
def styled_input_text(self, label, value, buffer_size=256):
"""绘制带样式的文本输入框"""
changed, new_value = imgui.input_text(label, value, buffer_size)
return changed, new_value
def styled_slider_float(self, label, value, min_val, max_val, format="%.3f"):
"""绘制带样式的浮点滑块"""
changed, new_value = imgui.slider_float(label, value, min_val, max_val, format)
return changed, new_value
def load_icon(self, icon_name):
"""加载图标纹理"""
try:
# 构建图标路径
project_root = Path(__file__).resolve().parent.parent
icon_path = project_root / "icons" / f"{icon_name}.png"
if icon_path.exists():
return self.imgui_backend.loadTexture(str(icon_path))
else:
print(f"⚠ 图标文件不存在: {icon_path}")
return None
except Exception as e:
print(f"⚠ 加载图标失败: {e}")
return None
def image_button(self, texture_id, size=(32, 32), bg_col=(0, 0, 0, 0), tint_col=(1, 1, 1, 1)):
"""绘制图像按钮"""
return imgui.image_button(texture_id, size, bg_col, tint_col)
def get_icon_text_button(self, icon_texture, text, size=(0, 0)):
"""绘制带图标的文本按钮"""
if icon_texture:
# 先绘制图标
imgui.image(icon_texture, (16, 16))
imgui.same_line()
# 再绘制文本按钮
return imgui.button(text, size)

View File

@ -0,0 +1,204 @@
"""
pyimgui管理器 - 在Panda3D引擎上集成ImGui界面
使用更简单的方法通过创建覆盖层来实现
"""
import imgui
import numpy as np
from panda3d.core import RenderState, ShaderAttrib, Texture, CardMaker, NodePath
from panda3d.core import TransparencyAttrib, ColorBlendAttrib, PNMImage
from panda3d.core import GraphicsOutput, RenderBuffer, TextureStage, TexGenAttrib
from direct.task.Task import Task
from direct.gui.OnscreenImage import OnscreenImage
from direct.gui.OnscreenText import OnscreenText
import PIL.Image
import PIL.ImageDraw
import io
class SimpleImGuiManager:
"""简化的ImGui管理器使用2D覆盖层在Panda3D引擎上显示ImGui界面"""
def __init__(self, world):
self.world = world
self.io = None
self._setup_imgui()
self._create_imgui_task()
# UI状态
self.show_demo_window = False
self.show_test_button = True
self.button_clicked = False
self.counter = 0
# 渲染相关
self.imgui_texture = None
self.imgui_image = None
self.texture_buffer = None
# 创建渲染纹理
self._create_render_texture()
def _setup_imgui(self):
"""初始化ImGui设置"""
# 初始化ImGui上下文
imgui.create_context()
self.io = imgui.get_io()
# 设置显示大小
win_props = self.world.win.getProperties()
self.io.display_size = (win_props.get_x_size(), win_props.get_y_size())
# 设置字体大小
font_size = 16
self.io.font_global_scale = font_size / 13.0
print("✓ ImGui初始化完成")
def _create_render_texture(self):
"""创建用于渲染ImGui的纹理"""
win_props = self.world.win.getProperties()
width = win_props.get_x_size()
height = win_props.get_y_size()
# 创建纹理
self.imgui_texture = Texture()
self.imgui_texture.setup_2d_texture(width, height, Texture.T_unsigned_byte, Texture.F_rgba8)
# 创建屏幕图像
self.imgui_image = OnscreenImage(
image=self.imgui_texture,
pos=(0, 0, 0),
scale=(1, 1, 1)
)
self.imgui_image.setTransparency(TransparencyAttrib.MAlpha)
def _create_imgui_task(self):
"""创建ImGui更新任务"""
taskMgr.add(self._update_imgui, "update_imgui")
def _update_imgui(self, task):
"""更新ImGui界面"""
# 开始新帧
imgui.new_frame()
# 绘制UI
self._draw_ui()
# 渲染ImGui到纹理
self._render_to_texture()
return Task.cont
def _draw_ui(self):
"""绘制UI元素"""
# 绘制测试窗口
if self.show_test_button:
imgui.begin("测试窗口", True)
if imgui.button("点击我!"):
self.button_clicked = True
self.counter += 1
print(f"按钮被点击了! 计数: {self.counter}")
if self.button_clicked:
imgui.text(f"按钮已被点击 {self.counter} 次!")
imgui.text("这是一个在Panda3D引擎上显示的ImGui按钮")
imgui.text(f"帧率: {globalClock.getAverageFrameRate():.1f} FPS")
imgui.end()
# 绘制演示窗口(可选)
if self.show_demo_window:
self.show_demo_window = imgui.show_demo_window(self.show_demo_window)
def _render_to_texture(self):
"""将ImGui渲染到纹理"""
# 渲染ImGui
imgui.render()
# 获取绘制数据
draw_data = imgui.get_draw_data()
if draw_data:
# 创建PIL图像
width, height = int(self.io.display_size[0]), int(self.io.display_size[1])
image = PIL.Image.new('RGBA', (width, height), (0, 0, 0, 0))
draw = PIL.ImageDraw.Draw(image)
# 简单的文本渲染这里只是示例实际需要完整的ImGui渲染
if self.show_test_button:
# 绘制简单的按钮模拟
button_x, button_y = 50, 50
button_width, button_height = 100, 30
draw.rectangle([button_x, button_y, button_x + button_width, button_y + button_height],
fill=(100, 100, 200, 255), outline=(255, 255, 255, 255))
draw.text((button_x + 10, button_y + 5), "点击我!", fill=(255, 255, 255, 255))
# 显示点击计数
if self.counter > 0:
draw.text((button_x, button_y + button_height + 10),
f"点击次数: {self.counter}", fill=(255, 255, 255, 255))
# 将PIL图像转换为Panda3D纹理
img_buffer = io.BytesIO()
image.save(img_buffer, format='RGBA')
img_buffer.seek(0)
pnm_image = PNMImage()
pnm_image.read(StringStream(img_buffer.read()))
self.imgui_texture.load(pnm_image)
def toggle_demo_window(self):
"""切换演示窗口显示"""
self.show_demo_window = not self.show_demo_window
def toggle_test_button(self):
"""切换测试按钮显示"""
self.show_test_button = not self.show_test_button
def process_mouse_click(self, x, y):
"""处理鼠标点击"""
# 检查是否点击了按钮区域
if self.show_test_button:
button_x, button_y = 50, 50
button_width, button_height = 100, 30
# 转换坐标系Panda3D坐标系原点在屏幕中心
screen_x = (x + self.io.display_size[0] / 2)
screen_y = (self.io.display_size[1] / 2 - y)
if (button_x <= screen_x <= button_x + button_width and
button_y <= screen_y <= button_y + button_height):
self.button_clicked = True
self.counter += 1
print(f"按钮被点击了! 计数: {self.counter}")
def cleanup(self):
"""清理资源"""
if self.imgui_image:
self.imgui_image.removeNode()
if self.imgui_texture:
self.imgui_texture = None
imgui.destroy_context()
# 辅助类用于内存中的字符串流
class StringStream:
"""简单的内存字符串流用于PNMImage读取"""
def __init__(self, data):
self.data = data
self.position = 0
def read(self, size=-1):
if size == -1:
result = self.data[self.position:]
self.position = len(self.data)
else:
result = self.data[self.position:self.position + size]
self.position += size
return result
def seek(self, position):
self.position = position
def tell(self):
return self.position

679
demo.py Normal file
View File

@ -0,0 +1,679 @@
from panda3d.core import loadPrcFileData, WindowProperties, Point3
from math import pi, sin, cos
from direct.showbase.ShowBase import ShowBase
from direct.task import Task
from direct.actor.Actor import Actor
from direct.interval.IntervalGlobal import Sequence
import p3dimgui
from imgui_bundle import imgui, imgui_ctx
import sys
import warnings
# 导入MyWorld类和必要的模块
from core.world import CoreWorld
from core.selection import SelectionSystem
from core.event_handler import EventHandler
from core.tool_manager import ToolManager
from core.script_system import ScriptManager
from core.patrol_system import PatrolSystem
from core.Command_System import CommandManager
from gui.gui_manager import GUIManager
from core.terrain_manager import TerrainManager
from scene.scene_manager import SceneManager
from project.project_manager import ProjectManager
from core.InfoPanelManager import InfoPanelManager
from core.collision_manager import CollisionManager
try:
# 尝试导入视频管理器,避免循环导入
import importlib.util
spec = importlib.util.spec_from_file_location("video_integration", "demo/video_integration.py")
video_module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(video_module)
VideoManager = video_module.VideoManager
except:
# 如果video_integration模块不存在则跳过
VideoManager = None
print("⚠ 视频管理器模块未找到,视频功能将不可用")
warnings.filterwarnings("ignore", category=DeprecationWarning)
class MyWorld(CoreWorld):
def __init__(self):
super().__init__()
# 初始化选择和变换系统
self.selection = SelectionSystem(self)
# 绑定F键用于聚焦选中节点
self.accept("f", self.onFocusKeyPressed)
self.accept("F", self.onFocusKeyPressed) # 大写F
#初始化巡检系统
self.patrol_system = PatrolSystem(self)
self.accept("p",self.onPatrolKeyPressed)
self.accept("P",self.onPatrolKeyPressed)
# 初始化事件处理系统
self.event_handler = EventHandler(self)
# 初始化工具管理系统
self.tool_manager = ToolManager(self)
# 初始化脚本管理系统
self.script_manager = ScriptManager(self)
# 初始化GUI管理系统
self.gui_manager = GUIManager(self)
# 初始化视频管理
if VideoManager is not None:
self.video_manager = VideoManager(self)
else:
self.video_manager = None
# 初始化场景管理系统
self.scene_manager = SceneManager(self)
# 初始化项目管理系统
self.project_manager = ProjectManager(self)
self.info_panel_manager = InfoPanelManager(self)
self.command_manager = CommandManager()
# 初始化碰撞管理器
self.collision_manager = CollisionManager(self)
# 初始化VR管理器
try:
from core.vr import VRManager
self.vr_manager = VRManager(self)
print("✓ VR管理器初始化完成")
except Exception as e:
print(f"⚠ VR管理器初始化失败: {e}")
self.vr_manager = None
# 调试选项
self.debug_collision = True # 是否显示碰撞体
# 默认启用模型间碰撞检测(可选)
self.enableModelCollisionDetection(enable=True, frequency=0.1, threshold=0.5)
# 启动脚本系统
self.script_manager.start_system()
self.terrain_manager = TerrainManager(self)
self.terrain_edit_radius = 3.0
self.terrain_edit_strength=0.3
self.terrain_edit_operation = "add"
# Install Dear ImGui
p3dimgui.init()
# 初始化样式管理器
from core.imgui_style_manager import ImGuiStyleManager
self.style_manager = ImGuiStyleManager(self.imgui)
# 尝试直接设置中文字体
try:
import platform
from pathlib import Path
# 获取中文字体路径
system = platform.system().lower()
if system == "linux":
font_path = "/usr/share/fonts/truetype/wqy/wqy-microhei.ttc"
elif system == "windows":
font_path = "C:/Windows/Fonts/msyh.ttc"
elif system == "darwin":
font_path = "/System/Library/Fonts/PingFang.ttc"
else:
font_path = None
if font_path and Path(font_path).exists():
# 先清除默认字体
self.imgui.io.fonts.clear()
# 创建中文字符范围(基本中文字符)
# 这个范围包含了常用中文字符的Unicode范围
chinese_ranges = []
# 基本拉丁字母
for i in range(0x0020, 0x00FF):
chinese_ranges.append(i)
# 中文字符范围
for i in range(0x4E00, 0x9FFF): # CJK统一汉字
chinese_ranges.append(i)
for i in range(0x3400, 0x4DBF): # CJK扩展A
chinese_ranges.append(i)
for i in range(0x20000, 0x2A6DF): # CJK扩展B
chinese_ranges.append(i)
for i in range(0x2A700, 0x2B73F): # CJK扩展C
chinese_ranges.append(i)
for i in range(0x2B740, 0x2B81F): # CJK扩展D
chinese_ranges.append(i)
for i in range(0x2B820, 0x2CEAF): # CJK扩展E
chinese_ranges.append(i)
for i in range(0x2CEB0, 0x2EBEF): # CJK扩展F
chinese_ranges.append(i)
for i in range(0x3000, 0x303F): # CJK符号和标点
chinese_ranges.append(i)
for i in range(0xFF00, 0xFFEF): # 全角字符
chinese_ranges.append(i)
# 添加中文字体不指定字符范围让ImGui自动处理
font = self.imgui.io.fonts.add_font_from_file_ttf(font_path, 14.0)
print(f"✓ 直接设置中文字体成功: {font_path}")
print(f" 使用自动字符范围")
else:
print("⚠ 中文字体文件不存在")
except Exception as e:
print(f"⚠ 直接设置中文字体失败: {e}")
# 备用方案:使用默认字体
try:
self.imgui.io.fonts.add_font_default()
print("✓ 使用默认字体")
except:
pass
# Disable the camera trackball controls.
self.disableMouse()
self.showDemoWindow = True
# UI状态管理
self.showSceneTree = True
self.showPropertyPanel = True
self.showConsole = True
self.showScriptPanel = True
self.showToolbar = True
self.accept('imgui-new-frame', self.__newFrame)
self.accept('`', self.__toggleImgui)
self.testTexture = None
self.icons = {} # 初始化图标字典
print("✓ MyWorld 初始化完成")
# ==================== 兼容性属性 ====================
# 保留models属性以兼容现有代码
@property
def models(self):
"""模型列表的兼容性属性"""
return self.scene_manager.models
@models.setter
def models(self, value):
"""模型列表的兼容性设置器"""
self.scene_manager.models = value
# 保留gui_elements属性以兼容现有代码
@property
def gui_elements(self):
"""GUI元素列表的兼容性属性"""
return self.gui_manager.gui_elements
@gui_elements.setter
def gui_elements(self, value):
"""GUI元素列表的兼容性设置器"""
self.gui_manager.gui_elements = value
# 保留guiEditMode属性以兼容现有代码
@property
def guiEditMode(self):
"""GUI编辑模式的兼容性属性"""
return self.gui_manager.guiEditMode
@guiEditMode.setter
def guiEditMode(self, value):
"""GUI编辑模式的兼容性设置器"""
self.gui_manager.guiEditMode = value
# 保留currentTool属性以兼容现有代码
@property
def currentTool(self):
"""当前工具的兼容性属性"""
return self.tool_manager.currentTool
@currentTool.setter
def currentTool(self, value):
"""当前工具的兼容性设置器"""
self.tool_manager.currentTool = value
# 保留terrains属性以兼容现有代码
@property
def terrains(self):
"""地形列表的兼容性属性"""
return self.terrain_manager.terrains
@terrains.setter
def terrains(self,value):
"""地形列表的兼容性设置器"""
self.terrain_manager.terrains = value
def onFocusKeyPressed(self):
"""处理 F 键按下事件"""
try:
if hasattr(self, 'selection') and self.selection.selectedNode:
self.selection.focusCameraOnSelectedNodeAdvanced()
else:
print("当前没有选中任何节点")
except Exception as e:
print(f"处理 F 键事件失败: {e}")
def onPatrolKeyPressed(self):
"""处理 P 键按下事件 - 控制巡检系统"""
try:
print("检测到 P 键按下")
if not self.patrol_system.is_patrolling:
if not self.patrol_system.patrol_points:
self.createDefaultPatrolRoute()
if self.patrol_system.start_patrol():
print("✓ 巡检已开始")
else:
print("✗ 巡检启动失败")
else:
if self.patrol_system.stop_patrol():
print("✓ 巡检已停止")
else:
print("✗ 巡检停止失败")
except Exception as e:
print(f"处理 P 键事件失败: {e}")
def createDefaultPatrolRoute(self):
"""创建默认巡检路线"""
try:
self.patrol_system.clear_patrol_points()
self.patrol_system.add_patrol_point((0, -10, 2), (0,0,0), 1.5)
self.patrol_system.add_patrol_point((10, -10, 2), (0,0,0), 1.5)
self.patrol_system.add_patrol_point((10, 5, 2), (0,0,0), 1.5)
self.patrol_system.add_patrol_point((10, 0, 5), (0,0,0), 1.5)
self.patrol_system.add_patrol_point((0, -10, 2), None, 2.5)
print("✓ 默认自动朝向巡检路线已创建")
self.patrol_system.list_patrol_points()
except Exception as e:
print(f"创建默认自动朝向巡检路线失败: {e}")
def enableModelCollisionDetection(self, enable=True, frequency=0.1, threshold=0.5):
"""启用模型间碰撞检测"""
return self.collision_manager.enableModelCollisionDetection(enable, frequency, threshold)
def __toggleImgui(self):
if not self.imgui.isKeyboardCaptured():
self.imgui.toggle()
def __newFrame(self):
# Dear ImGui commands can be placed here.
# 在第一帧应用样式
if imgui.get_frame_count() == 0:
self.style_manager.apply_style()
# 加载图标
self.icons = {
'select': self.style_manager.load_icon('select_tool'),
'move': self.style_manager.load_icon('move_tool'),
'rotate': self.style_manager.load_icon('rotate_tool'),
'scale': self.style_manager.load_icon('scale_tool'),
'success': self.style_manager.load_icon('success_icon'),
'warning': self.style_manager.load_icon('warning_icon'),
}
# 确保中文字体被正确应用
try:
# 强制刷新字体
self.imgui.io.fonts.clear()
# 重新添加中文字体
import platform
from pathlib import Path
system = platform.system().lower()
if system == "linux":
font_path = "/usr/share/fonts/truetype/wqy/wqy-microhei.ttc"
elif system == "windows":
font_path = "C:/Windows/Fonts/msyh.ttc"
elif system == "darwin":
font_path = "/System/Library/Fonts/PingFang.ttc"
if font_path and Path(font_path).exists():
# 添加中文字体,明确指定中文字符集
try:
# 获取中文字符集
chinese_ranges = imgui.get_io().fonts.get_glyph_ranges_chinese_full()
self.imgui.io.fonts.add_font_from_file_ttf(font_path, 14.0, None, chinese_ranges)
print("✓ 第一帧重新设置中文字体(包含中文字符集)")
except:
# 如果获取字符集失败,使用简单方式
self.imgui.io.fonts.add_font_from_file_ttf(font_path, 14.0)
print("✓ 第一帧重新设置中文字体(简单方式)")
except Exception as e:
print(f"⚠ 第一帧设置中文字体失败: {e}")
# 绘制菜单栏
self._draw_menu_bar()
# 绘制工具栏
if self.showToolbar:
self._draw_toolbar()
# 绘制场景树面板
if self.showSceneTree:
self._draw_scene_tree()
# 绘制属性面板
if self.showPropertyPanel:
self._draw_property_panel()
# 绘制控制台面板
if self.showConsole:
self._draw_console()
# 绘制脚本面板
if self.showScriptPanel:
self._draw_script_panel()
# 绘制纹理测试窗口
if self.testTexture:
with self.style_manager.begin_styled_window("Texture Test", True,
imgui.WINDOW_ALWAYS_AUTO_RESIZE) as (_, windowOpen):
if not windowOpen:
self.imgui.removeTexture(self.testTexture)
self.testTexture = None
return
imgui.image(self.testTexture, (256, 256))
# 绘制ImGui演示窗口
if self.showDemoWindow:
imgui.show_demo_window()
def _draw_menu_bar(self):
"""绘制菜单栏"""
with imgui_ctx.begin_main_menu_bar() as main_menu:
if main_menu:
# 文件菜单
with imgui_ctx.begin_menu("文件") as file_menu:
if file_menu:
imgui.menu_item("新建项目", "Ctrl+N", False, True)
imgui.menu_item("打开项目", "Ctrl+O", False, True)
imgui.separator()
imgui.menu_item("保存", "Ctrl+S", False, True)
imgui.menu_item("另存为", "", False, True)
imgui.separator()
imgui.menu_item("退出", "Alt+F4", False, True)
# 编辑菜单
with imgui_ctx.begin_menu("编辑") as edit_menu:
if edit_menu:
imgui.menu_item("撤销", "Ctrl+Z", False, True)
imgui.menu_item("重做", "Ctrl+Y", False, True)
imgui.separator()
imgui.menu_item("复制", "Ctrl+C", False, True)
imgui.menu_item("粘贴", "Ctrl+V", False, True)
imgui.menu_item("删除", "Del", False, True)
# 视图菜单
with imgui_ctx.begin_menu("视图") as view_menu:
if view_menu:
_, self.showToolbar = imgui.menu_item("工具栏", "", self.showToolbar, True)
_, self.showSceneTree = imgui.menu_item("场景树", "", self.showSceneTree, True)
_, self.showPropertyPanel = imgui.menu_item("属性面板", "", self.showPropertyPanel, True)
_, self.showConsole = imgui.menu_item("控制台", "", self.showConsole, True)
_, self.showScriptPanel = imgui.menu_item("脚本管理", "", self.showScriptPanel, True)
# 工具菜单
with imgui_ctx.begin_menu("工具") as tools_menu:
if tools_menu:
imgui.menu_item("导入模型", "", False, True)
imgui.menu_item("地形编辑器", "", False, True)
imgui.menu_item("材质编辑器", "", False, True)
imgui.menu_item("脚本编辑器", "", False, True)
# 窗口菜单
with imgui_ctx.begin_menu("窗口") as window_menu:
if window_menu:
_, self.showDemoWindow = imgui.menu_item("ImGui演示", "", self.showDemoWindow, True)
if self.testTexture:
imgui.menu_item("关闭纹理测试", "", False, True)
else:
imgui.menu_item("显示纹理测试", "", False, True)
# 帮助菜单
with imgui_ctx.begin_menu("帮助") as help_menu:
if help_menu:
imgui.menu_item("关于", "", False, True)
imgui.menu_item("文档", "", False, True)
# 右侧显示FPS
imgui.set_cursor_pos_x(imgui.get_window_size().x - 140)
imgui.text("%.2f FPS (%.2f ms)" % (imgui.get_io().framerate, 1000.0 / imgui.get_io().framerate))
def _draw_toolbar(self):
"""绘制工具栏"""
# 设置工具栏位置
imgui.set_next_window_pos((10, 30), imgui.Cond_.first_use_ever.value)
imgui.set_next_window_size((300, 40), imgui.Cond_.first_use_ever.value)
with self.style_manager.begin_styled_window("工具栏", self.showToolbar,
self.style_manager.get_window_flags("toolbar")):
self.showToolbar = True # 确保窗口保持打开
# 工具按钮组
if self.icons.get('select'):
if self.style_manager.image_button(self.icons['select'], (24, 24)):
print("选择工具")
if imgui.is_item_hovered():
imgui.set_tooltip("选择工具 (Q)")
imgui.same_line()
else:
if imgui.button("选择"):
print("选择工具")
imgui.same_line()
if self.icons.get('move'):
if self.style_manager.image_button(self.icons['move'], (24, 24)):
print("移动工具")
if imgui.is_item_hovered():
imgui.set_tooltip("移动工具 (W)")
imgui.same_line()
else:
if imgui.button("移动"):
print("移动工具")
imgui.same_line()
if self.icons.get('rotate'):
if self.style_manager.image_button(self.icons['rotate'], (24, 24)):
print("旋转工具")
if imgui.is_item_hovered():
imgui.set_tooltip("旋转工具 (E)")
imgui.same_line()
else:
if imgui.button("旋转"):
print("旋转工具")
imgui.same_line()
if self.icons.get('scale'):
if self.style_manager.image_button(self.icons['scale'], (24, 24)):
print("缩放工具")
if imgui.is_item_hovered():
imgui.set_tooltip("缩放工具 (R)")
else:
if imgui.button("缩放"):
print("缩放工具")
imgui.same_line()
imgui.separator()
imgui.same_line()
# 其他工具按钮
if imgui.button("导入"):
print("导入模型")
imgui.same_line()
if imgui.button("保存"):
print("保存场景")
imgui.same_line()
if imgui.button("播放"):
print("播放动画")
def _draw_scene_tree(self):
"""绘制场景树面板"""
# 设置场景树位置
imgui.set_next_window_pos((10, 80), imgui.Cond_.first_use_ever.value)
imgui.set_next_window_size((250, 300), imgui.Cond_.first_use_ever.value)
with self.style_manager.begin_styled_window("场景树", self.showSceneTree,
self.style_manager.get_window_flags("panel")):
self.showSceneTree = True # 确保窗口保持打开
imgui.text("场景层级")
imgui.separator()
# 模拟场景树结构
if imgui.tree_node("渲染"):
if imgui.tree_node("环境光"):
imgui.text("环境光 #1")
imgui.tree_pop()
if imgui.tree_node("定向光"):
imgui.text("定向光 #1")
imgui.tree_pop()
if imgui.tree_node("地板"):
imgui.text("地板节点")
imgui.tree_pop()
imgui.tree_pop()
if imgui.tree_node("相机"):
imgui.text("主相机")
imgui.tree_pop()
if imgui.tree_node("模型"):
imgui.text("(空)")
imgui.tree_pop()
def _draw_property_panel(self):
"""绘制属性面板"""
# 设置属性面板位置
imgui.set_next_window_pos((270, 80), imgui.Cond_.first_use_ever.value)
imgui.set_next_window_size((250, 300), imgui.Cond_.first_use_ever.value)
with self.style_manager.begin_styled_window("属性面板", self.showPropertyPanel,
self.style_manager.get_window_flags("panel")):
self.showPropertyPanel = True # 确保窗口保持打开
imgui.text("对象属性")
imgui.separator()
# 模拟属性设置
changed, pos_x = imgui.drag_float("位置 X", 0.0, 0.1)
changed, pos_y = imgui.drag_float("位置 Y", 0.0, 0.1)
changed, pos_z = imgui.drag_float("位置 Z", 0.0, 0.1)
imgui.separator()
changed, rot_x = imgui.drag_float("旋转 X", 0.0, 1.0)
changed, rot_y = imgui.drag_float("旋转 Y", 0.0, 1.0)
changed, rot_z = imgui.drag_float("旋转 Z", 0.0, 1.0)
imgui.separator()
changed, scale = imgui.drag_float("缩放", 1.0, 0.1)
imgui.separator()
if imgui.button("重置变换"):
print("重置变换")
def _draw_console(self):
"""绘制控制台面板"""
# 设置控制台位置
imgui.set_next_window_pos((10, 390), imgui.Cond_.first_use_ever.value)
imgui.set_next_window_size((770, 150), imgui.Cond_.first_use_ever.value)
with self.style_manager.begin_styled_window("控制台", self.showConsole,
self.style_manager.get_window_flags("panel")):
self.showConsole = True # 确保窗口保持打开
imgui.text("控制台输出")
imgui.separator()
# 模拟控制台输出
if self.icons.get('success'):
imgui.image(self.icons['success'], (12, 12))
imgui.same_line()
imgui.text_colored((0.176, 1.0, 0.769, 1.0), "[INFO]") # 成功颜色
imgui.same_line()
imgui.text("引擎初始化完成")
imgui.text_colored((0.157, 0.620, 1.0, 1.0), "[INFO]") # 信息颜色
imgui.same_line()
imgui.text("渲染管线已加载")
if self.icons.get('warning'):
imgui.image(self.icons['warning'], (12, 12))
imgui.same_line()
imgui.text_colored((0.953, 0.616, 0.471, 1.0), "[WARN]") # 警告颜色
imgui.same_line()
imgui.text("视频管理器模块未找到")
if self.icons.get('success'):
imgui.image(self.icons['success'], (12, 12))
imgui.same_line()
imgui.text_colored((0.176, 1.0, 0.769, 1.0), "[INFO]") # 成功颜色
imgui.same_line()
imgui.text("VR管理器初始化完成")
# 输入框
imgui.separator()
changed, command = imgui.input_text(">", "", 256)
if changed and command:
print(f"执行命令: {command}")
def _draw_script_panel(self):
"""绘制脚本管理面板"""
# 设置脚本面板位置
imgui.set_next_window_pos((530, 80), imgui.Cond_.first_use_ever.value)
imgui.set_next_window_size((250, 300), imgui.Cond_.first_use_ever.value)
with self.style_manager.begin_styled_window("脚本管理", self.showScriptPanel,
self.style_manager.get_window_flags("panel")):
self.showScriptPanel = True # 确保窗口保持打开
imgui.text("脚本列表")
imgui.separator()
# 模拟脚本列表
selected, _ = imgui.selectable("main.py", False)
if selected:
print("选择脚本: main.py")
selected, _ = imgui.selectable("player_controller.py", False)
if selected:
print("选择脚本: player_controller.py")
selected, _ = imgui.selectable("ui_manager.py", False)
if selected:
print("选择脚本: ui_manager.py")
imgui.separator()
# 脚本操作按钮
if imgui.button("新建脚本"):
print("新建脚本")
imgui.same_line()
if imgui.button("编辑"):
print("编辑脚本")
imgui.same_line()
if imgui.button("重载"):
print("重载脚本")
imgui.separator()
imgui.text("脚本输出:")
imgui.text("脚本引擎已启动")
imgui.text("热重载监控已启动")
demo = MyWorld()
demo.run()

55
imgui.ini Normal file
View File

@ -0,0 +1,55 @@
[Window][Debug##Default]
Pos=60,60
Size=400,400
Collapsed=0
[Window][Explore: render]
Pos=60,60
Size=410,761
Collapsed=0
[Window][Node Placer "camera"]
Pos=486,83
Size=472,216
Collapsed=0
[Window][Time Slider "pandaPace"]
Pos=-69,89
Size=745,76
Collapsed=0
[Window][Dear ImGui Demo]
Pos=989,19
Size=550,680
Collapsed=1
[Window][工具栏]
Pos=10,30
Size=300,40
Collapsed=0
[Window][场景树]
Pos=-3,66
Size=270,497
Collapsed=0
[Window][属性面板]
Pos=1132,337
Size=252,416
Collapsed=0
[Window][控制台]
Pos=0,562
Size=1132,191
Collapsed=0
[Window][脚本管理]
Pos=1132,39
Size=250,300
Collapsed=0
[Window][中文显示测试]
Pos=60,60
Size=135,263
Collapsed=0

149
test_chinese_font.py Normal file
View File

@ -0,0 +1,149 @@
#!/usr/bin/env python3
"""
测试中文字体显示的调试脚本
"""
import sys
import os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '.'))
from panda3d.core import loadPrcFileData
from direct.showbase.ShowBase import ShowBase
import p3dimgui
from imgui_bundle import imgui
import platform
from pathlib import Path
class ChineseFontTest(ShowBase):
def __init__(self):
# 设置窗口
loadPrcFileData('', 'win-size 800 600')
ShowBase.__init__(self)
# 初始化ImGui
p3dimgui.init()
# 测试字体加载
self.test_font_loading()
# 接受ImGui新帧事件
self.accept('imgui-new-frame', self._new_frame)
self.accept('`', self._toggle_imgui)
self.show_test_window = True
def test_font_loading(self):
"""测试字体加载"""
print("=== 开始字体测试 ===")
# 检查系统
system = platform.system().lower()
print(f"系统: {system}")
# 获取字体路径
font_paths = []
if system == "linux":
font_paths = [
"/usr/share/fonts/truetype/wqy/wqy-microhei.ttc",
"/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc",
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
]
elif system == "windows":
font_paths = [
"C:/Windows/Fonts/msyh.ttc",
"C:/Windows/Fonts/simhei.ttf",
]
elif system == "darwin":
font_paths = [
"/System/Library/Fonts/PingFang.ttc",
"/System/Library/Fonts/STHeiti.ttc",
]
# 测试每个字体
for font_path in font_paths:
if Path(font_path).exists():
print(f"✓ 字体文件存在: {font_path}")
try:
# 尝试加载字体
font = self.imgui.io.fonts.add_font_from_file_ttf(font_path, 16.0)
print(f" ✓ 字体加载成功")
# 检查字体信息
font_info = self.imgui.io.fonts.fonts
print(f" 字体数量: {len(font_info)}")
# 尝试获取字符集
try:
# 方法1尝试获取中文字符集
chinese_ranges = imgui.get_io().fonts.get_glyph_ranges_chinese_full()
print(f" ✓ 中文字符集获取成功,范围: {len(chinese_ranges)} 个字符")
except:
try:
# 方法2尝试获取中文字符集简化版
chinese_ranges = imgui.get_io().fonts.get_glyph_ranges_chinese()
print(f" ✓ 中文字符集获取成功(简化版),范围: {len(chinese_ranges)} 个字符")
except:
try:
# 方法3尝试获取默认字符集
default_ranges = imgui.get_io().fonts.get_glyph_ranges_default()
print(f" ✓ 默认字符集获取成功,范围: {len(default_ranges)} 个字符")
print(f" ⚠ 使用默认字符集,可能不支持中文")
except Exception as e:
print(f" ⚠ 字符集获取失败: {e}")
print(f" ⚠ 将使用默认字符集")
break
except Exception as e:
print(f" ✗ 字体加载失败: {e}")
else:
print(f"✗ 字体文件不存在: {font_path}")
print("=== 字体测试完成 ===")
def _toggle_imgui(self):
if not self.imgui.isKeyboardCaptured():
self.imgui.toggle()
def _new_frame(self):
# 绘制测试窗口
if self.show_test_window:
imgui.show_demo_window()
# 中文测试窗口
expanded, opened = imgui.begin("中文显示测试", True)
if expanded:
imgui.text("基础中文测试:")
imgui.text("你好,世界!")
imgui.text("这是一个中文测试")
imgui.text("引擎初始化完成")
imgui.text("选择和变换系统")
imgui.text("脚本管理系统")
imgui.separator()
imgui.text("特殊字符测试:")
imgui.text("标点符号:,。!?;:""''()【】")
imgui.separator()
imgui.text("数字测试:")
imgui.text("一二三四五六七八九十")
imgui.separator()
if imgui.button("测试按钮"):
print("中文按钮被点击")
imgui.same_line()
if imgui.button("另一个按钮"):
print("另一个中文按钮")
imgui.separator()
changed, text = imgui.input_text("输入中文", "在这里输入中文")
if changed:
print(f"输入的中文: {text}")
imgui.end()
if __name__ == "__main__":
test = ChineseFontTest()
test.run()

21
testgui.py Normal file
View File

@ -0,0 +1,21 @@
from direct.showbase.ShowBase import ShowBase
from imgui_bundle import imgui
import p3dimgui
class MyApp(ShowBase):
def __init__(self):
ShowBase.__init__(self)
# Install Dear ImGui
p3dimgui.init()
self.accept('imgui-new-frame', self.draw)
def draw(self):
# Show the demo window.
imgui.show_demo_window()
app = MyApp()
app.run()