#!/usr/bin/env python # -*- coding: utf-8 -*- """ PANDA3D GUI功能测试示例 展示DirectGUI系统的各种组件使用方法 """ import sys from direct.showbase.ShowBase import ShowBase from direct.gui.DirectGui import * from direct.gui.OnscreenText import OnscreenText from direct.gui.OnscreenImage import OnscreenImage from panda3d.core import * class GUITestApp(ShowBase): def __init__(self): ShowBase.__init__(self) # 设置窗口标题 wp = WindowProperties() wp.setTitle("PANDA3D GUI功能测试") self.win.requestProperties(wp) # 设置背景颜色 self.setBackgroundColor(0.2, 0.3, 0.5) # 尝试加载中文字体 self.chinese_font = self.loadChineseFont() # 创建标题文本 self.title = OnscreenText( text="PANDA3D DirectGUI 组件示例", pos=(0, 0.9), scale=0.08, fg=(1, 1, 1, 1), align=TextNode.ACenter, font=self.chinese_font if self.chinese_font else None ) # 创建各种GUI组件 self.createButtons() self.createLabels() self.createEntries() self.createSliders() self.createCheckboxes() self.createRadioButtons() self.createScrolledFrame() self.createOptionMenu() # 状态显示文本 self.statusText = OnscreenText( text="状态: 准备就绪", pos=(-1.2, -0.9), scale=0.05, fg=(0, 1, 0, 1), align=TextNode.ALeft ) print("GUI测试应用启动成功!") print(f"中文字体加载状态: {'成功' if self.chinese_font else '失败,使用默认字体'}") print("尝试点击各种GUI组件来测试功能") def loadChineseFont(self): """尝试加载中文字体""" import os font_paths = [ '/usr/share/fonts/truetype/wqy/wqy-microhei.ttc', '/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc', '/usr/share/fonts/truetype/arphic/ukai.ttc', '/usr/share/fonts/truetype/arphic/uming.ttc', ] for font_path in font_paths: if os.path.exists(font_path): try: font = self.loader.loadFont(font_path) if font: return font except: continue return None def createButtons(self): """创建按钮组件""" # 普通按钮 self.button1 = DirectButton( text="普通按钮", pos=(-0.8, 0, 0.6), scale=0.06, command=self.onButton1Click, rolloverSound=None, clickSound=None, text_font=self.chinese_font if self.chinese_font else None ) # 带图像的按钮 self.button2 = DirectButton( text="彩色按钮", pos=(-0.4, 0, 0.6), scale=0.06, command=self.onButton2Click, frameColor=(0.2, 0.8, 0.2, 1), rolloverSound=None, clickSound=None, text_font=self.chinese_font if self.chinese_font else None ) # 退出按钮 self.exitButton = DirectButton( text="退出程序", pos=(0.8, 0, 0.6), scale=0.06, command=self.exitApp, frameColor=(0.8, 0.2, 0.2, 1), rolloverSound=None, clickSound=None, text_font=self.chinese_font if self.chinese_font else None ) def createLabels(self): """创建标签组件""" self.label1 = DirectLabel( text="这是一个标签", pos=(-0.8, 0, 0.4), scale=0.05, frameColor=(0, 0, 0, 0), # 透明背景 text_fg=(1, 1, 0, 1), text_font=self.chinese_font if self.chinese_font else None ) self.label2 = DirectLabel( text="带背景的标签", pos=(-0.4, 0, 0.4), scale=0.05, frameColor=(0.3, 0.3, 0.7, 0.8), text_fg=(1, 1, 1, 1), text_font=self.chinese_font if self.chinese_font else None ) def createEntries(self): """创建文本输入框""" # 普通输入框 self.entry1 = DirectEntry( text="", pos=(-0.8, 0, 0.2), scale=0.05, command=self.onEntry1Submit, initialText="在这里输入文本...", numLines=1, focus=0, width=12 ) # 密码输入框 self.entry2 = DirectEntry( text="", pos=(-0.4, 0, 0.2), scale=0.05, command=self.onEntry2Submit, initialText="密码输入框", numLines=1, focus=0, width=12, obscured=1 # 密码模式 ) def createSliders(self): """创建滑块组件""" # 水平滑块 self.slider1 = DirectSlider( range=(0, 100), value=50, pos=(0.2, 0, 0.4), scale=0.4, command=self.onSlider1Change, orientation=DGG.HORIZONTAL ) # 垂直滑块 self.slider2 = DirectSlider( range=(0, 100), value=25, pos=(0.6, 0, 0.2), scale=0.3, command=self.onSlider2Change, orientation=DGG.VERTICAL ) # 滑块值显示 self.sliderValueText = OnscreenText( text="滑块值: H=50, V=25", pos=(0.4, 0.1), scale=0.04, fg=(1, 1, 1, 1), font=self.chinese_font if self.chinese_font else None ) def createCheckboxes(self): """创建复选框""" self.checkbox1 = DirectCheckButton( text="选项 1", pos=(-0.8, 0, 0), scale=0.05, command=self.onCheckbox1Toggle, rolloverSound=None, clickSound=None, text_font=self.chinese_font if self.chinese_font else None ) self.checkbox2 = DirectCheckButton( text="选项 2", pos=(-0.4, 0, 0), scale=0.05, command=self.onCheckbox2Toggle, rolloverSound=None, clickSound=None, text_font=self.chinese_font if self.chinese_font else None ) def createRadioButtons(self): """创建单选按钮组""" self.radioButtons = [] self.radioVar = [0] # 用列表来存储选中的索引 for i in range(3): radio = DirectRadioButton( text=f"单选 {i+1}", pos=(-0.8 + i*0.2, 0, -0.2), scale=0.05, variable=self.radioVar, value=[i], command=self.onRadioButtonSelect, extraArgs=[i], # 添加额外参数 rolloverSound=None, clickSound=None, text_font=self.chinese_font if self.chinese_font else None ) self.radioButtons.append(radio) def createScrolledFrame(self): """创建滚动框架""" # 创建滚动框架 self.scrollFrame = DirectScrolledFrame( frameSize=(-0.5, 0.5, -0.3, 0.3), canvasSize=(-0.5, 0.5, -1, 1), pos=(0.2, 0, -0.2), frameColor=(0.2, 0.2, 0.2, 0.8), scrollBarWidth=0.04, verticalScroll_relief=DGG.SUNKEN, horizontalScroll_relief=DGG.SUNKEN ) # 在滚动框架中添加内容 for i in range(10): label = DirectLabel( text=f"滚动项目 {i+1}", pos=(0, 0, 0.8 - i*0.15), scale=0.04, parent=self.scrollFrame.getCanvas(), frameColor=(0, 0, 0, 0), text_fg=(1, 1, 1, 1), text_font=self.chinese_font if self.chinese_font else None ) def createOptionMenu(self): """创建选项菜单""" items = ["选项A", "选项B", "选项C", "选项D"] self.optionMenu = DirectOptionMenu( text="选择选项", pos=(0.6, 0, 0), scale=0.05, items=items, initialitem=0, command=self.onOptionMenuSelect, rolloverSound=None, clickSound=None, text_font=self.chinese_font if self.chinese_font else None ) # 事件处理函数 def onButton1Click(self): """按钮1点击事件""" self.updateStatus("普通按钮被点击!") print("普通按钮被点击") def onButton2Click(self): """按钮2点击事件""" self.updateStatus("彩色按钮被点击!") print("彩色按钮被点击") def onEntry1Submit(self, text): """文本输入框提交事件""" self.updateStatus(f"输入的文本: {text}") print(f"输入的文本: {text}") def onEntry2Submit(self, text): """密码输入框提交事件""" self.updateStatus(f"输入的密码长度: {len(text)}") print(f"输入的密码: {text}") def onSlider1Change(self): """水平滑块变化事件""" value = self.slider1['value'] self.updateSliderValues() print(f"水平滑块值: {value}") def onSlider2Change(self): """垂直滑块变化事件""" value = self.slider2['value'] self.updateSliderValues() print(f"垂直滑块值: {value}") def updateSliderValues(self): """更新滑块值显示""" h_val = int(self.slider1['value']) v_val = int(self.slider2['value']) self.sliderValueText.setText(f"滑块值: H={h_val}, V={v_val}") def onCheckbox1Toggle(self, status): """复选框1切换事件""" state = "选中" if status else "未选中" self.updateStatus(f"复选框1: {state}") print(f"复选框1: {state}") def onCheckbox2Toggle(self, status): """复选框2切换事件""" state = "选中" if status else "未选中" self.updateStatus(f"复选框2: {state}") print(f"复选框2: {state}") def onRadioButtonSelect(self, index, status): """单选按钮选择事件""" if status: self.updateStatus(f"选中单选按钮: {index + 1}") print(f"选中单选按钮: {index + 1}") def onOptionMenuSelect(self, arg): """选项菜单选择事件""" self.updateStatus(f"选择了: {arg}") print(f"选择了选项: {arg}") def updateStatus(self, message): """更新状态显示""" self.statusText.setText(f"状态: {message}") def exitApp(self): """退出应用程序""" print("正在退出程序...") self.userExit() if __name__ == "__main__": try: app = GUITestApp() app.run() except Exception as e: print(f"程序运行出错: {e}") sys.exit(1)