EG/demo/gui_test.py
2025-07-02 09:49:59 +08:00

358 lines
11 KiB
Python

#!/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)