在Java中轻松实现界面跳转
副标题#e#
假设这样一种环境,我们的系统的界面利用javax.swing包构建,界面的基本是BaseView,他是一个容器,虽然他该当提供获取控件元素的成果,好比获得按钮,下拉框,表格等,虽然仅仅是一个容器罢了,而我们的界面的元素全部陈设在JPanel上。
描写为:
一个界面就是一个BaseView,他只包括一个JPanel,这个包括JPanel包括所有我们的Swing控件,譬喻JButton,JLable等等。
问题呈现了:我们凡是因为业务的需要完成一个界面的操纵要自动跳转到下一个界面,完成下一个界面又能跳返来(题外话:由于我们的操纵是基于GUI的,所以往往能生存Session信息,而Web却做不到),而这往往成为系统实现进程中效率低下的一个因素,我就见到我此刻的系统中有人用600行代码判定上一个界面应该是哪一个来跳转过来,因为许多界面都可以跳到当前界面。
虽然有一种做法是,在下一个界面类中包括指向上一个界面的变量,我们说,这不利便,也增加了依赖性,这对软件是倒霉的。
接下来,我给出我的办理要领,但愿对回收这种界面布局的伴侣有所裨益。
(以下全部用简化模子来报告.)
1.简朴点,我们假设BaseView担任JWindow,虽然可以是此外容器(依据你的实现),或许象这样:
public abstract class BaseView extends JWindow{
...
(实现一些取得界面控件,和界面信息的要领).
}
2.每个界面类都象这样界说:
public class MyView extends BaseView{
JPanel myPanel;
public void playoutPanel(){
JButton myButton = new JButton("OK");
myPanel.add(myButton);
......
(添加你需要的控件和机关到myPanel上)
}
}
3.假设有其他的界面OneView,TwoView,ThreeView处理惩罚完操纵后都需要跳转到myView,在myView中的ok按钮按下的时候需要回到原始界面。
本来臃肿的代码需要在myView中添加一个变量BaseView anyView;用来存放转来的谁人界面anyView,赋值在三者中的跳转代码中引用myView来设定.跳转代码象这样:
public void jump(){
MyView myView = new MyView();
myView.anyView = this;
this.remove(this.xxPanel);
this.add(myView.getPanel());
this.repaint();
}
看起来还不错,固然需要引用MyView类,并挪用他的变量和要领.可是跳转返来却不那么容易,不然怎么会用600行!
或许象这样:(这已经是被我简化的)
public void goBack(){
if(anyView instanceof OneView){
anyView.remove(this.myView);
OneView ov = (OneView)anyView;
anyView.add(ov.getPanel());
anyView.repaint();
}
if(anyView instanceof TwoView){
....
}
...
}
#p#副标题#e#
不经大量应用此外业务用例界面,这种编译依赖性真不是什么功德,更况且用了大量的低效的instanceof判定和转型操纵.
为了优化这种景象,彻底办理这个问题,我想应该设计一个第三方类来消除这种依赖性,而且让界面跳转不要这么费劲。这个第三方的类是这样设计的:
在这个类中,必需有一个变量来生存某一个界面跳转的路径,如A->B->C.路径一旦被生存,你就拥有了节制显示任何一个界面的权利了。在这个链中,第一个位置的界面应该是这次跳转的第一站,最后一个位置是当前站。这里存在一个因果干系:只有跳转了才可以跳归去。这样使得我们可以用数组来生存这个路径。现实中,跳转的景象应该不会高出10次,所以我们把路径长度设为10(虽然你可以按照需要变动)。这个类的样子或许象这样:
class ViewPath{
JPanel[] pnlPath = null; //跳转的界面路径,界面跳转最大10个条理吧!!!
int index = 0; //路径中的当前下标
BaseView bsView = null; //当前路径地址的同一个View
//在路径中寻找方针的要领
public int find(JPanel pnl){ //该路径下是否有某个Panel,有的话返回下标,没有的话返回-1
if(bsView==null) return -1; //没有初始化,该路径下没有任何Panel
for(int i=0;i<pnlPath.length;i++){ //在这个路径中寻找方针
if(pnl==pnlPath[i]){
index = i;
return i; //假如找到了则返回位置,而且把当前位置设为方针位置
}
}
return -1; //没有找到,返回-1
}
//结构函数
ViewPath(JPanel myPanel,BaseView myView){
pnlPath = new JPanel[10]; //配置路径最大长度为10
bsView = myView; //配置该路径所属的谁人View
pnlPath[0] = myPanel; //设立起始站
index = 0; //设立起始站索引
}
}
这样一个类就完成了生存一次跳转路径的浸染.(虽然,是否应该在find要领中设立方针位置是否符合有待商榷)
那么我们如何利用这样一个路径?
#p#分页标题#e#
我们设立一个帮助类来完成这个事情,我们定名为ViewJump,我们知道作为帮助的类最好是不要有实例,出格是象这样的起接口浸染的类,只提供静态要领.它的框架象这样:
public class ViewJump{
private static ViewPath[] viewPath = null; //路径池,系统多处利用,静态但私有,因为供内部用
private ViewJump(){} //私有结构要领,帮助类只提供静态要领
private static int find(JPanel pnl); //寻找给定的Panel是否在已有路径中,私有
private static int newPath(JPanel myPanel,BaseView myView); //成立一个新路径,私有
/**
* 每个类需要利用该帮助类时都需要第一步注册本身,然后才气做其他操纵
* 返回一个注册码id,帮助类需要利用这个注册码举办其他操纵
*/
public static int registerPath(JPanel myPanel,BaseView myView);
/**
* 设立下一个界面.
*/
public static void setNext(int id,JPanel aim);
/**
* 回到上一个界面
*/
public static void back(int id);
/**
* 回到第一个界面
*/
public static void backHome(int id);
/**
* 跳转到下一个界面
*/
public static void jump(int id);
}
完成这样一个类的代码量并不多,一百多行,可是却使得用户完全离开了处理惩罚差异界面的烦恼.稍后会把该类的源码附上,值得一提的是,这个类的实现当然可以用到雷同的实现傍边,可是假如用户的界面布局并不是如此搭建,你就需要变动参数范例了.假如能把这些抽象出来,获得一个抽象类或接口,参数用Object范例.用户按照本身的需要去实现这些要领,岂不妙哉!
利用这个类,你可以轻便的多的完成诸如上面的任务:
OneView中:
public void jump(){
MyView myView = new MyView();
int id = ViewJump.registerPath(this.xxPanel,this);
ViewJump.setNext(id,myView.getPanel());
ViewJump.jump(id);
}
MyView中退回的部门:
protected void goBack(){
int id = ViewJump.registerPath(this.myPanel,this);
ViewJump.back(id);
}
天哪,这并不神奇,600行代码仅仅用了两行就实现了!
好了,我就说这么多了,一切都把握在你手中,用你的伶俐来优化我们的冗余代码吧,因为这样它看起来相当不错.
附:完整代码:(我把ViewPath类放在同一个文件ViewJump.java里,代码上面已经给出)
public class ViewJump{
private static ViewPath[] viewPath = null;
//私有结构函数
private ViewJump(){}
//寻找该Panel是不是在路径中
/**
* 找到了返回在实例数组中的下标
* 没有找到返回-1
* @param pnl
* @return
*/
private static int find(JPanel pnl){
// System.out.println("执行find() in ViewJump");
if(viewPath == null || viewPath.length==0) return -1;
for(int i = 0;i<viewPath.length;i++){ //查抄每一个路径
ViewPath vp = viewPath[i]; //对该路径查抄
if(vp.find(pnl) != -1){
return i;
}
}
return -1;
}
//成立一个新的路径
/**
*
* @param myPanel
* @param myView
*/
private static int newPath(JPanel myPanel,BaseView myView){
System.out.println("执行newPath() in ViewJump");
//检讨一下看有没有无效的路径,有则排除
if(viewPath == null || viewPath.length==0) {
viewPath = new ViewPath[]{new ViewPath(myPanel,myView)};
return 0;
}
ViewPath[] vjArr = new ViewPath[viewPath.length];
int count = 0;
for(int i = 0;i<viewPath.length;i++){
if(viewPath[i].bsView!=null){ //把不为空的值取出来
vjArr[count++] = viewPath[i];
}
}
viewPath = new ViewPath[count+1];
System.arraycopy(viewPath,0,vjArr,0,count); //复制到本来的数组变量中
//最后一个位置留给新插手的元素
viewPath[count] = new ViewPath(myPanel,myView);
return count;
}
//得到实例的要领
/**
* 必需查抄该Panel是不是已经在路径中了,假如在路径中,
* 则返回注册的编号,用此编号扁可以会见到正确的范例了
* 假如不在路径中,则以此为开始新建一个新的路径
* 原来查抄路径的时候没有须要查抄路径的第一个元素,
* 因为一个元素不行能是初步,可是为了防备用户持续两次registerPath的错误
* 请把第一个元素也给查抄一下
* myView 参数只有当该界面为跳转的起始点时才需要,不然保持原始的View
* @param me
* @param other
* 返回实例数组的下标,
*/
public static int registerPath(JPanel myPanel,BaseView myView){
System.out.println("执行registerPath() in ViewJump");
int idx = find(myPanel);
System.out.println("idx="+idx);
if(idx==-1){ //返回-1暗示没有找到,成立一个新的路径
System.out.println("新建一个路径");
idx = newPath(myPanel,myView);
}
System.out.println("执行完注册路径..");
return idx; //返回实例下标
}
//设定要跳转的下一个方针
public static void setNext(int id,JPanel aim){
if(id<0||id>=viewPath.length){
return;
}
ViewPath vp = viewPath[id];
//设定方针,从这里看,这是存在安详裂痕的,假如利用者乱通报id进来的话
JPanel[] path = vp.pnlPath;
path[vp.index+1] = aim;
}
//回到上一个
public static void back(int id){
if(id<0||id>=viewPath.length){
return;
}
ViewPath vp = viewPath[id];
//回到上一个界面
if(vp.index>0){ //只有当前面有路径时才作
vp.bsView.remove(vp.pnlPath[vp.index]); //移去当前的
vp.index--; //游标往前走一步
vp.bsView.add(vp.pnlPath[vp.index],BorderLayout.CENTER); //增加当前的到界面
vp.bsView.validate();
vp.bsView.repaint();
}
}
//回到发源处
public static void backHome(int id){
if(id<0||id>=viewPath.length){
return;
}
ViewPath vp = viewPath[id];
//直接回到第一步,需要排除该路径吗?半途断裂怎么办?步伐是查抄View是否已为空
//选择不排除,每次在成立新的路径时,查抄路径是不是已经无效了
vp.bsView.remove(vp.pnlPath[vp.index]); //移去当前的
vp.index = 0; //游标往前走一步
vp.bsView.add(vp.pnlPath[vp.index],BorderLayout.CENTER); //增加当前的到界面
vp.bsView.validate();
vp.bsView.repaint();
}
//跳转到下一处
public static void jump(int id){
if(id<0||id>=viewPath.length){
return;
}
ViewPath vp = viewPath[id];
if(vp.pnlPath[vp.index+1]==null){
return; //下一步基础没有配置
}
vp.bsView.remove(vp.pnlPath[vp.index]); //移去当前的
vp.index++;
vp.bsView.add(vp.pnlPath[vp.index],BorderLayout.CENTER);
vp.bsView.validate();
vp.bsView.repaint();
}
}