[转载]在Java中轻松实现界面跳转

在Java中轻松实现界面跳转
假设这样一种情况,我们的系统的界面使用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){
  ....
 }
 ...
}

  不经大量应用别的业务用例界面,这种编译依赖性真不是什么好事,更何况用了大量的低效的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  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方法中设立目标位置是否合适有待商榷)

  那么我们如何使用这样一个路径?

  我们设立一个辅助类来完成这个工作,我们命名为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 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   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();
}
}

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/374079/viewspace-131004/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/374079/viewspace-131004/

JavaWeb之Servlet精讲实战课程 本课程是javaee和大数据开发的基础课程,讲述了Servlet中Servlet创建过程,Request请求以及Response中各种响应头的介绍,以及乱码的各种处理方式,以及刷新重定向转发等。对servlet中的session和cookie做了着重讲解,同时,也介绍了servlet2.5与servlet3.0的区别。在整个课程当中,带学生做了一个简单的数码商城项目,将所学的servlet知识应用到了其中,让学生学以致用。数码商城项目保存的功能:登录、退出、记住密码、查看商品详情、加入商品到购物车、删除购物车中商品等。 阅读详情

相关推荐

java中怎么实现页面跳转页面跳转页面,java后端如何实现页面跳转

页面跳转分类有两种:重定向和转发,即redirect和forward。一:重定向redirect第一种方式:controller中返回值为String相关免费学习视频分享:java在线学习public String login(HttpServletRequest req, HttpServletResponse resp)return "redirect:http://localhost:808...

weixin_35455994的博客 2611

JavaSwing界面跳转技巧

在本文中,我们介绍了三种常见的JavaSwing界面跳转技巧:CardLayout布局管理器、TabbedPane、JOptionPane。在这个示例中,我们使用了三个面板,并使用CardLayout将它们组合到了一个容器中。通过CardLayout,你可以将多个面板组合到一个容器中,然后通过一系列的动作来控制它们的显隐。TabbedPane是Swing中的一个非常常用的组件,它允许用户在多个“标签页”之间进行切换。在这个示例中,我们使用了三个Tab(标签页),通过点击标签页来切换不同的面板。

我点评的博客 2297

JavaGUI界面实现跳转

页面跳转

weixin_51555736的博客 6989

Android Studio 代码页跳界面 /java和XML快速切换技巧

https://www.cnblogs.com/simadi/p/6698666.html?utm_source=itdadao&utm_medium=referral 今天又发现了一个Android Studio强大的功能,非常惊叹! 我们开发Android应用程序时,Activity或者Fragment会有一个相对应的布局。在Eclipse中或者一般的做法,我们...

weixin_30878361的博客 375

java如何获取跳转之后的网页的url-------一句话搞定

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_33774308的博客 1886

Android学习笔记2---多界面切换

用过VB 、 VC#的朋友都知道,在VB或VC#里要进行窗口(界面)切换很容易 例如在VB、C#里: 有 Fom1、 Form2、Form3,如果要切换。 Form1.show() Form2.show() 相当简单,当时在Android里, 要想这么做,很真实很“难”了。要得动动脑筋了。 按照我以往的编程经验,我这里提供一种简单的解决办法...

weixin_30894583的博客 187

Flex实现页面跳转的功能可用性分析 .

Flex关于页面跳转的方式,我是直接贴的,博客中很多很多,我只是贴过来然后结合实际应用中分析下那种方式最好。 Flex中实现页面跳转以下几种方式: 1、使用ViewStack组件,把要跳转的页新建成 MXML Component,然后通过 ViewStack 组件把这些页包含进来,然后再通过改变ViewStack的selectedItem或者electedChild来切换这...

weixin_34051201的博客 88

如何实现JavaScript延迟加载执行--Java自学网

我们经常会见页面中的功能在执行几秒后跳转为另外功能,用JS实现,简单又好用。 1、 JavaScript延迟加载方法:     setTimeout("document.getElementById('my').src='include/common.php'; ",3000);//延时3秒  页面中常用的方法是利用setTimeout来实现 2、 JS最后加载方法

300

AWS代理商选型与成本控制实战:从账单异常到架构避坑

企业上云的第一步往往不是选技术,而是弄懂云成本模型和代理商的真实能力边界。理解按需、预留、竞价等计费方式的搭配逻辑,掌握预算告警、资源标签和生命周期管理等成本控制手段,才能让云支出可视化、可优化。在实际运营中,即使将Auto Scaling Group设为0,EIP、EBS快照、负载均衡等附属资源仍可能持续扣费,排查隐藏账单是运维常态。结合AWS迁移、架构评审、账单异常排查等工程实践,从概念到原理再到场景化落地,最终收敛到如何评估一家值得长期信赖的AWS代理商,以及签约后如何通过有效治理持续降本增效。

weixin_34005042的博客 246

Playwright进阶技巧:掌握page.expect_popup(),轻松管理新页面跳转

声明:文章中引用的视频为微信群里面的山豆根大佬原创所录制哟~免费视频录制剪辑不易,请大家多多支持。学习笔记登录后复制 def test_pw_new_page(page: Page): page.goto("/demo/link", wait_until="networkidle") page.get_b...

weixin_40209481的博客 445

Android需求之点击跳转至市场评价

相信大家都看过APP上有一个选项”喜欢此APP?还希望您评价一下吧!”,然后点击弹出选择框让你选择一个市场如: 安智市场,百度应用,豌豆荚….然后选择其中一个后就跳转至此市场你的APP专栏中. 其实这里就是一个简单的意图而已: String mAddress ="market://details?id="+getPackageName(); ...

weixin_30952535的博客 169

获得浏览器语言版本、当前访问的域名,jsp实现301跳转

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_33797791的博客 124

转载:Jetpack Navigation

原作者:Arcns 原链接:https://www.jianshu.com/p/bea053264436 Jetpack是google近年来力推的一系列安卓开发组件框架,目前仍在不断的更新与完善,其主要目的是帮助开发者们构建高质量的现代化APP,减少模版代码。 本系列文章将会介绍Jetpack常用组件框架的使用方式,如Navigation、ViewModel、LiveData、Room、Paging、WorkManager等。 一、Navigation简介 Navigation主要用于实现Fra

BINGXIHEART的博客 354

轻松实现MVC模式

概要: 框架需求与目标 框架设计与编码实现 框架演示与功能实现 一、框架需求与目标 框架需求: 框架的需求包含功能性需求 和非功能性需求,功能性需求框架本身所提供的功能,而非功能性需求通常也指定体验性需求,即该框架对于开发者而言,是否易上手,是否需要较...

chuiyi3047的博客 287

【Android UI设计与开发】3.引导界面(三)实现应用程序只启动一次引导界面

大部分的引导界面基本上都是千篇一律的,只要熟练掌握了一个,基本上也就没什么好说的了,要想实现应用程序只启动一次引导界面这样的效果,只要使用SharedPreferences类,就会让程序变的非常简单,下面来详细介绍一下这个类的使用方法 1.SharedPreferences的详细介绍和用法 其实在20.游戏开发基础(游戏数据存储)中已经有过介绍了,为...

weixin_34122604的博客 118

转载JAVA三层架构,持久层,业务层,表现层的理解

JAVA三层架构,持久层,业务层,表现层的理解 转载:http://blog.csdn.net/ljf_study/article/details/64443653 SSH: Struts(表示层)+Spring(业务层)+Hibernate(持久层) Struts: Struts是一个表示层框架,主要作用是界面展示,接收请求,分发请求。 在MVC框架中,St...

weixin_30408675的博客 158

java怎么实现自动退出功能_SpringSecurity退出功能实现的正确方式

本文将介绍在Spring Security框架下如何实现用户的"退出"logout的功能。其实这是一个非常简单的功能,我见过很多的程序员在使用了Spring Security之后,仍然去自己写controller方法实现logout功能,这种做法就好像耕地,你有机械设备你不用,你非要用牛。一、logout最简及最佳实践其实使用Spring Security进行logout非常简单,只需要在spri...

weixin_39789499的博客 541

Android Studio 源码分析

android实现按钮跳转到指定网页 res/layout: <Button android:text="Button" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/button6"/>app/java/MainA...

dawanai5802的博客 484
上一篇: [转载]关于spring中的aop的解释
下一篇: [转载]Eclipse中用SWT和JFace开发入门(一)
congji3817
博客等级 码龄10年 15粉丝 588原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值