吉林大学经济信息学院本科毕业论文
4.1Swing组件概念
Swing的优点:
1、Swing有一套丰富的、更方便的用户界面元素。
2、Swing几乎不依赖于平台,因而不容易出现与平台有关的错误。 3、Swing给用户的感觉是:在各平台上的运行都是一致的。
4.2选择Swing还是AWT
Swing是由100%纯Java实现的,Swing组件是用Java实现的轻量级( light-weight)组件,没有本地代码,不依赖操作系统的支持,这是它与AWT组件的最大区别。由于AWT组件通过与具体平台相关的对等类(Peer)实现,因此Swing比AWT组件具有更强的实用性。Swing在不同的平台上表现一致,并且有能力提供本地窗口系统不支持的其它特性。 在Swing中,可以指定程序中GUI的look and feel,真正做到GUI与平台无关,但在AWT中则不行。
4.3从Swing看工程的MVC设计模式
MVC设计模式把一个软件组件区分为三个不同的部分,model,view,controller。 Model是代表组件状态和低级行为的部分,它管理着自己的状态并且处理所有对状态的操作,model自己本身并不知道使用自己的view和controller是谁,系统维护着它和view之间的关系,当model发生了改变系统还负责通知相应的view。
View代表了管理model所含有的数据的一个视觉上的呈现。一个Model可以有一个以上的
6
吉林大学经济信息学院本科毕业论文
View,但是Swing中却很少有这样的情况。
Controller管理着model和用户之间的交互的控制。它提供了一些方法去处理当model的状态发生了变化时的情况。
4.4图形界面编码与分析
从整个窗体界面的布局可以看出来中间部分是java3D可绘制区,右面是控制版面,下面是提示版面。
整体上使用了BoxLayout的布局。 public void setupGUI(){ . .
.//由于代码过多,此处省略. //add status bar }
4.5界面反馈与控制
在swing中,有两种基本的响应组件消息的方式。第一个方式,也就是我用的方式,就是给组件添加监听器:
item.addActionListener(this); 被添加的类需要继承Listener接口。 第二个方式,是使用回调函数。
其余的方式并不常用,在这里不说了。
public void actionPerformed(ActionEvent e) { // TODO Auto-generated method stub // //if is playing animation,nothing done if(player.isPlaying())return;//这里判断是否在播放动画。设定播放动画的
7
吉林大学经济信息学院本科毕业论文
时候不能编辑动画 Update();//更新信息,保持动画信息为最新的 String name = ((Component)e.getSource()).getName();//这个追踪事件的源,并取得源的名字
String value = e.getActionCommand();//这里取得源的动作命令,这个命令是在创建组件的时候手工加上去的。
System.out.println(\调试信息
//panel View
if(name==\
panelView.add(\ panelView.repaint() ; return; }
.//代码过多,此处省略. . }
currentTrans[0].setTransform(FrameAccesser.readFrame(frames[tgIndex]));//将更新完的动作让模型显示出来
showFrameData(frames[tgIndex]);//将更新完的信息传入信息版面 }
5、辅助模块的设计和功用
5.1高亮显示被选模型部分
这个类的作用是让用户知道当前选择的模型最小细分是哪个。在这里,我最终选用了线框模式作为被选指示。 其原理是:
8
吉林大学经济信息学院本科毕业论文
首先要使被选模型允许动态改变外表渲染。这样才能在被编译以后的3d模型上动态的改变外观。这个在ModelCutter里面有一个辅助功能,可以设置指定序号的部分的动态改变能力。
其次,要有一个碰撞检测的过程,就是在三维空间中,由鼠标点,垂直于屏幕的一条直线和模型的碰撞。 碰撞检测算法 a、实体包围盒法
b、 静态干涉和动态干涉结合法(单步检测法)
JAVA3D提供的碰撞检测功能的实现。JAVA3D提供了两个类WakeupOnCollisionEntry及WakeupOnColisionExit,这两个类在构造的时候要求提供被检测的范围(类Bounds的子类)或三维对象(类Node的子类)。当场景图中的任何对象与被检测的对象(范围)发生碰撞时WakeupOnCollisionEntry就会被唤醒(Wakeup),当碰撞解除时WakeupOnColisionExit就会被唤醒。Java3D检测碰撞的方法有两个:USE_BOUNDS和USE_GEOMETRY,也就是使用包围盒或几何体进行碰撞检测,经过实验发现,前者的检测效果非常粗略,几乎是错误的结果,所以选择用几何体进行检测。实际编程中,可以把唤醒条件加入Behavior类中,就可以在Behavior类的processStinulus过程中处理碰撞发生后或解除后要作的控制。 public class PickHighlightBehavior extends PickMouseBehavior { Appearance savedAppearance = null; //选择前的外观 Shape3D oldShape = null; //选择前的图形
Appearance highlightAppearance; //选择后的外观 TransformGroup[] tg; //传递的对象组 .//代码过多,此处省略. . // Set up the polygon attributes PolygonAttributes pa = new PolygonAttributes(); pa.setPolygonMode(PolygonAttributes.POLYGON_LINE); pa.setCullFace(PolygonAttributes.CULL_NONE); highlightAppearance.setPolygonAttributes(pa);
//pickCanvas.setMode(PickTool.BOUNDS); //设定碰撞边界
pickCanvas.setMode(PickTool.GEOMETRY); //设定为几何碰撞,这样比较精确,但是运算量大 }
public void updateScene(int xpos, int ypos) { // 省略 //System.out.println(shape) ; savedAppearance = shape.getAppearance();//保存原有外观 //TransformGroup tg=(TransformGroup)shape.getParent() ; oldShape = shape; shape.setAppearance(highlightAppearance);//改变外观为选择状态 } } }
5.2三维地面和三维坐标系的建立
a、三维坐标系
9
吉林大学经济信息学院本科毕业论文
三维坐标系事实上就一个3D模型,当然,我们也可以用*.3ds导入。但是作为一个编辑器基本组件,速度是很重要的。用纯的代码写模型,需要首先在纸上计算好。这样才能准确的画出来。
我们的类只需要继承Shape3D就具有了基本的模型特征。 public class Axis extends Shape3D{ }
b、三维地面
三位地面就是一个充满交叉直线的图形。画的方法很简单,不用一个一个坐标的写,我们可以设置地增量,用循环来实现。
需要注意的是,坐标不要超出整体的3D空间的范围。 Shape3D createLand()
5.3帧播放器
帧播放器仅仅放在辅助模块里面是由原因的。因为动画的播放需要驱动循环的驱动,所以这个FramePlayer其实并不能播放帧,其作用仅仅是在调用的时候自动将当前帧更新到下一个帧,并判断是否还有下一个帧。也就是说,这个类仅仅是一个驱动帧的工具。 public class FramePlayer {
private boolean playing=false;//这个变量用于判断是否正在播放动画 private AFrame[] frames;//动画
private TransformGroup[] trans;//模型指针 private int[] framePos;//模型动画位置 // 省略
public void start(){//开始播放,并自动退回到第一个帧 rollbackFrame(); playing=true; } .
.//代码过多,此处省略. . } }
5.4视角控制
视角控制是必需的。因为动画编辑者可以需要改变观察点的角度,或者靠近,远离模型以更好的观察模型动画的设计情况。这里我们保持视角始终是与水平面呈45度角,也就是常用的3D视角。用几个矩阵相乘实现。 另一方面,视角转了360度,回到原点。
6、驱动模块/主模块与模块集成
public class AnimationEditor implements ActionListener
主模块是整个工程的核心模块,也是其他模块的交叉点。这个模块几乎是集成了其他所有模块的功能。
由于代码过多,功能也是面面俱到。让我们从入口函数来看。
6.1程序入口
程序入口非常简单。先设置了世界的比例,这里定为0.005F,然后初始化主模块。 public static void main( String[] args )
10