150 lines
4.8 KiB
Markdown
150 lines
4.8 KiB
Markdown
# GUI 显示问题修复总结
|
||
|
||
## 问题描述
|
||
|
||
在 `test.py` 主程序中,3D文本和虚拟屏幕能够正常显示,但是2D GUI组件(按钮、标签、输入框)看不见。
|
||
|
||
## 问题原因分析
|
||
|
||
### 1. 坐标系统不匹配
|
||
- **3D GUI组件**(3D文本、虚拟屏幕)使用**世界坐标系统**,坐标范围可以是任意值
|
||
- **2D GUI组件**(按钮、标签、输入框)使用**屏幕坐标系统**,坐标范围通常是 -1 到 1
|
||
|
||
### 2. 具体问题
|
||
原代码中,所有GUI组件都使用相同的位置参数 `pos=(0, 0, 0)`:
|
||
```python
|
||
# 原来的错误代码
|
||
button = DirectButton(
|
||
text=text,
|
||
pos=pos, # 直接使用3D坐标,错误!
|
||
scale=size,
|
||
# ...
|
||
)
|
||
```
|
||
|
||
当传入像 `(5, 0, 0)` 这样的3D坐标时:
|
||
- 3D组件正常显示在世界坐标 (5, 0, 0)
|
||
- 2D组件会被显示在屏幕坐标 (5, 0, 0),这超出了屏幕范围 [-1, 1],因此不可见
|
||
|
||
## 解决方案
|
||
|
||
### 1. 坐标转换
|
||
为2D GUI组件添加坐标转换逻辑:
|
||
|
||
```python
|
||
def createGUIButton(self, pos=(0, 0, 0), text="按钮", size=0.1):
|
||
from direct.gui.DirectGui import DirectButton
|
||
|
||
# 将3D坐标转换为2D屏幕坐标
|
||
# DirectGUI使用屏幕坐标系,范围是-1到1
|
||
gui_pos = (pos[0] * 0.1, 0, pos[2] * 0.1) # 缩放到合适的屏幕范围
|
||
|
||
button = DirectButton(
|
||
text=text,
|
||
pos=gui_pos, # 使用转换后的屏幕坐标
|
||
scale=size,
|
||
# ...
|
||
)
|
||
```
|
||
|
||
### 2. 转换规则
|
||
- **输入坐标**: 3D逻辑坐标,范围 -50 到 50(用户友好)
|
||
- **输出坐标**: 2D屏幕坐标,范围 -1 到 1(DirectGUI要求)
|
||
- **转换公式**: `屏幕坐标 = 逻辑坐标 × 0.1`
|
||
|
||
### 3. 属性面板优化
|
||
为了更好地编辑2D GUI组件,属性面板中添加了特殊处理:
|
||
|
||
```python
|
||
def updateGUIPropertyPanel(self, gui_element):
|
||
gui_type = gui_element.getTag("gui_type")
|
||
|
||
if gui_type in ["button", "label", "entry"]:
|
||
# 2D GUI组件使用逻辑坐标编辑
|
||
logical_x = pos.getX() / 0.1 # 反向转换为逻辑坐标
|
||
logical_z = pos.getZ() / 0.1
|
||
|
||
# 提供逻辑坐标编辑界面
|
||
xPos.setValue(logical_x)
|
||
xPos.valueChanged.connect(lambda v: self.editGUI2DPosition(gui_element, "x", v))
|
||
|
||
# 同时显示实际屏幕坐标(只读)
|
||
actualXLabel = QLabel(f"{pos.getX():.3f}")
|
||
else:
|
||
# 3D GUI组件使用世界坐标编辑
|
||
# 正常的3D坐标编辑逻辑
|
||
```
|
||
|
||
## 修复效果验证
|
||
|
||
### 1. 测试脚本
|
||
创建了两个测试脚本验证修复效果:
|
||
- `test_2d_gui_fix.py`: 简单的2D GUI显示测试
|
||
- `test_gui_complete.py`: 完整的GUI功能测试
|
||
|
||
### 2. 测试结果
|
||
修复后的测试显示:
|
||
- ✅ 所有位置的2D按钮都可见且可点击
|
||
- ✅ 所有位置的2D标签都正常显示
|
||
- ✅ 所有位置的2D输入框都可见且可输入
|
||
- ✅ 3D文本和虚拟屏幕继续正常工作
|
||
- ✅ 坐标转换计算正确
|
||
|
||
### 3. 控制台输出示例
|
||
```
|
||
创建了 中心 位置的GUI元素:
|
||
- 按钮位置: (0.0, 0, 0.0)
|
||
- 标签位置: (0.0, 0, -0.2)
|
||
- 输入框位置: (0.0, 0, -0.4)
|
||
创建了 左侧 位置的GUI元素:
|
||
- 按钮位置: (-0.5, 0, 0.0)
|
||
- 标签位置: (-0.5, 0, -0.2)
|
||
- 输入框位置: (-0.5, 0, -0.4)
|
||
```
|
||
|
||
## 关键改进点
|
||
|
||
### 1. 用户体验
|
||
- 用户仍然可以使用直观的"逻辑坐标"(如 -5, 0, 5)来指定GUI位置
|
||
- 系统自动处理坐标转换,对用户透明
|
||
|
||
### 2. 一致性
|
||
- 3D GUI组件继续使用世界坐标系统
|
||
- 2D GUI组件使用合适的屏幕坐标系统
|
||
- 属性面板根据组件类型提供相应的编辑界面
|
||
|
||
### 3. 可维护性
|
||
- 坐标转换逻辑集中在创建方法中
|
||
- 添加了专门的2D GUI位置编辑方法 `editGUI2DPosition()`
|
||
- 保持了代码结构的清晰性
|
||
|
||
## 使用建议
|
||
|
||
### 1. 创建2D GUI组件
|
||
```python
|
||
# 使用逻辑坐标创建(推荐)
|
||
button = world.createGUIButton((-5, 0, 0), "左侧按钮") # 显示在屏幕左侧
|
||
button = world.createGUIButton((5, 0, 0), "右侧按钮") # 显示在屏幕右侧
|
||
button = world.createGUIButton((0, 0, 5), "上方按钮") # 显示在屏幕上方
|
||
```
|
||
|
||
### 2. 创建3D GUI组件
|
||
```python
|
||
# 使用世界坐标创建(不变)
|
||
text3d = world.createGUI3DText((0, 5, 2), "3D文本")
|
||
screen = world.createGUIVirtualScreen((3, 8, 0), (2, 1), "虚拟屏幕")
|
||
```
|
||
|
||
### 3. 坐标范围建议
|
||
- **2D GUI逻辑坐标**: -10 到 10(对应屏幕范围 -1 到 1)
|
||
- **3D GUI世界坐标**: 任意合理范围
|
||
|
||
## 总结
|
||
|
||
这次修复解决了2D GUI组件不可见的核心问题,通过正确的坐标系统转换,确保了:
|
||
1. 所有GUI组件都能正常显示
|
||
2. 用户界面保持直观和一致
|
||
3. 编辑功能完全可用
|
||
4. 代码结构保持清晰
|
||
|
||
修复验证显示所有功能都正常工作,用户现在可以在主程序中成功创建和使用所有类型的GUI元素。 |