Java中簡(jiǎn)單完成界面跳轉(zhuǎn)
發(fā)表時(shí)間:2024-01-15 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]假設(shè)這樣一種情況,我們的系統(tǒng)的界面使用javax.swing包構(gòu)建,界面的基礎(chǔ)是BaseView,他是一個(gè)容器,當(dāng)然他應(yīng)當(dāng)提供獲取控件元素的功能,比如得到按鈕,下拉框,表格等,當(dāng)然僅僅是一個(gè)容器而已,而我們的界面的元素全部部署在JPanel上。 描述為: 一個(gè)界面就是一個(gè)BaseView,...
假設(shè)這樣一種情況,我們的系統(tǒng)的界面使用javax.swing包構(gòu)建,界面的基礎(chǔ)是BaseView,他是一個(gè)容器,當(dāng)然他應(yīng)當(dāng)提供獲取控件元素的功能,比如得到按鈕,下拉框,表格等,當(dāng)然僅僅是一個(gè)容器而已,而我們的界面的元素全部部署在JPanel上。
描述為:
一個(gè)界面就是一個(gè)BaseView,他只包含一個(gè)JPanel,這個(gè)包含JPanel包含所有我們的Swing控件,例如JButton,JLable等等。
問題出現(xiàn)了:我們通常因?yàn)闃I(yè)務(wù)的需要完成一個(gè)界面的操作要自動(dòng)跳轉(zhuǎn)到下一個(gè)界面,完成下一個(gè)界面又能跳回來(題外話:由于我們的操作是基于GUI的,所以往往能保存Session信息,而Web卻做不到),而這往往成為系統(tǒng)實(shí)現(xiàn)過程中效率低下的一個(gè)因素,我就見到我現(xiàn)在的系統(tǒng)中有人用600行代碼判斷上一個(gè)界面應(yīng)該是哪一個(gè)來跳轉(zhuǎn)過來,因?yàn)楹芏嘟缑娑伎梢蕴疆?dāng)前界面。
當(dāng)然有一種做法是,在下一個(gè)界面類中包含指向上一個(gè)界面的變量,我們說,這不方便,也增加了依賴性,這對(duì)軟件是不利的。
接下來,我給出我的解決方法,希望對(duì)采用這種界面結(jié)構(gòu)的朋友有所裨益。
(以下全部用簡(jiǎn)化模型來講述.)
1.簡(jiǎn)單點(diǎn),我們假設(shè)BaseView繼承JWindow,當(dāng)然可以是別的容器(依據(jù)你的實(shí)現(xiàn)),大概象這樣:
public abstract class BaseView extends JWindow{
...
(實(shí)現(xiàn)一些取得界面控件,和界面信息的方法).
}
2.每個(gè)界面類都象這樣定義:
public class MyView extends BaseView{
JPanel myPanel;
public void playoutPanel(){
JButton myButton = new JButton("OK");
myPanel.add(myButton);
......
(添加你需要的控件和布局到myPanel上)
}
}
3.假設(shè)有其他的界面OneView,TwoView,ThreeView處理完操作后都需要跳轉(zhuǎn)到myView,在myView中的ok按鈕按下的時(shí)候需要回到原始界面。
原來臃腫的代碼需要在myView中添加一個(gè)變量BaseView anyView;用來存放轉(zhuǎn)來的那個(gè)界面anyView,賦值在三者中的跳轉(zhuǎn)代碼中引用myView來設(shè)定.跳轉(zhuǎn)代碼象這樣:
public void jump(){
MyView myView = new MyView();
myView.anyView = this;
this.remove(this.xxPanel);
this.add(myView.getPanel());
this.repaint();
}
看起來還不錯(cuò),雖然需要引用MyView類,并調(diào)用他的變量和方法.但是跳轉(zhuǎn)回來卻不那么容易,否則怎么會(huì)用600行!
大概象這樣:(這已經(jīng)是被我簡(jiǎn)化的)
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){
....
}
...
}
不經(jīng)大量應(yīng)用別的業(yè)務(wù)用例界面,這種編譯依賴性真不是什么好事,更何況用了大量的低效的instanceof判斷和轉(zhuǎn)型操作.
為了優(yōu)化這種情形,徹底解決這個(gè)問題,我想應(yīng)該設(shè)計(jì)一個(gè)第三方類來消除這種依賴性,并且讓界面跳轉(zhuǎn)不要這么費(fèi)勁。這個(gè)第三方的類是這樣設(shè)計(jì)的:
在這個(gè)類中,必須有一個(gè)變量來保存某一個(gè)界面跳轉(zhuǎn)的路徑,如A->B->C.路徑一旦被保存,你就擁有了控制顯示任何一個(gè)界面的權(quán)利了。在這個(gè)鏈中,第一個(gè)位置的界面應(yīng)該是這次跳轉(zhuǎn)的第一站,最后一個(gè)位置是當(dāng)前站。這里存在一個(gè)因果關(guān)系:只有跳轉(zhuǎn)了才可以跳回去。這樣使得我們可以用數(shù)組來保存這個(gè)路徑,F(xiàn)實(shí)中,跳轉(zhuǎn)的情形應(yīng)該不會(huì)超過10次,所以我們把路徑長(zhǎng)度設(shè)為10(當(dāng)然你可以根據(jù)需要更改)。這個(gè)類的樣子大概象這樣:
class ViewPath{
JPanel[] pnlPath = null; //跳轉(zhuǎn)的界面路徑,界面跳轉(zhuǎn)最大10個(gè)層次吧!!!
int index = 0; //路徑中的當(dāng)前下標(biāo)
BaseView bsView = null; //當(dāng)前路徑所在的同一個(gè)View
//在路徑中尋找目標(biāo)的方法
public int find(JPanel pnl){ //該路徑下是否有某個(gè)Panel,有的話返回下標(biāo),沒有的話返回-1
if(bsView==null) return -1; //沒有初始化,該路徑下沒有任何Panel
for(int i=0;i
if(pnl==pnlPath[i]){
index = i;
return i; //如果找到了則返回位置,并且把當(dāng)前位置設(shè)為目標(biāo)位置
}
}
return -1; //沒有找到,返回-1
}
//構(gòu)造函數(shù)
ViewPath(JPanel myPanel,BaseView myView){
pnlPath = new JPanel[10]; //設(shè)置路徑最大長(zhǎng)度為10
bsView = myView; //設(shè)置該路徑所屬的那個(gè)View
pnlPath[0] = myPanel; //設(shè)立起始站
index = 0; //設(shè)立起始站索引
}
}
這樣一個(gè)類就完成了保存一次跳轉(zhuǎn)路徑的作用.(當(dāng)然,是否應(yīng)該在find方法中設(shè)立目標(biāo)位置是否合適有待商榷)
那么我們?nèi)绾问褂眠@樣一個(gè)路徑?
我們?cè)O(shè)立一個(gè)輔助類來完成這個(gè)工作,我們命名為ViewJump,我們知道作為輔助的類最好是不要有實(shí)例,特別是象這樣的起接口作用的類,只提供靜態(tài)方法.它的框架象這樣:
public class ViewJump{
private static ViewPath[] viewPath = null; //路徑池,系統(tǒng)多處使用,靜態(tài)但私有,因?yàn)楣﹥?nèi)部用
private ViewJump(){} //私有構(gòu)造方法,輔助類只提供靜態(tài)方法
private static int find(JPanel pnl); //尋找給定的Panel是否在已有路徑中,私有
private static int newPath(JPanel myPanel,BaseView myView); //建立一個(gè)新路徑,私有
/**
* 每個(gè)類需要使用該輔助類時(shí)都需要第一步注冊(cè)自己,然后才能做其他操作
* 返回一個(gè)注冊(cè)碼id,輔助類需要使用這個(gè)注冊(cè)碼進(jìn)行其他操作
*/
public static int registerPath(JPanel myPanel,BaseView myView);
/**
* 設(shè)立下一個(gè)界面.
*/
public static void setNext(int id,JPanel aim);
/**
* 回到上一個(gè)界面
*/
public static void back(int id);
/**
* 回到第一個(gè)界面
*/
public static void backHome(int id);
/**
* 跳轉(zhuǎn)到下一個(gè)界面
*/
public static void jump(int id);
}
完成這樣一個(gè)類的代碼量并不多,一百多行,但是卻使得用戶完全脫離了處理不同界面的煩惱.稍后會(huì)把該類的源碼附上,值得一提的是,這個(gè)類的實(shí)現(xiàn)固然可以用到類似的實(shí)現(xiàn)當(dāng)中,但是如果用戶的界面結(jié)構(gòu)并不是如此搭建,你就需要更改參數(shù)類型了.如果能把這些抽象出來,得到一個(gè)抽象類或接口,參數(shù)用Object類型.用戶根據(jù)自己的需要去實(shí)現(xiàn)這些方法,豈不妙哉!
使用這個(gè)類,你可以簡(jiǎn)便的多的完成諸如上面的任務(wù):
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行代碼僅僅用了兩行就實(shí)現(xiàn)了!
好了,我就說這么多了,一切都掌握在你手中,用你的智慧來優(yōu)化我們的冗余代碼吧,因?yàn)檫@樣它看起來相當(dāng)不錯(cuò).
附:完整代碼:(我把ViewPath類放在同一個(gè)文件ViewJump.java里,代碼上面已經(jīng)給出)
public class ViewJump{
private static ViewPath[] viewPath = null;
//私有構(gòu)造函數(shù)
private ViewJump(){}
//尋找該P(yáng)anel是不是在路徑中
/**
* 找到了返回在實(shí)例數(shù)組中的下標(biāo)
* 沒有找到返回-1
* @param pnl
* @return
*/
private static int find(JPanel pnl){
// System.out.println("執(zhí)行find() in ViewJump");
if(viewPath == null viewPath.length==0) return -1;
for(int i = 0;i
ViewPath vp = viewPath[i]; //對(duì)該路徑檢查
if(vp.find(pnl) != -1){
return i;
}
}
return -1;
}
//建立一個(gè)新的路徑
/**
*
* @param myPanel
* @param myView
*/
private static int newPath(JPanel myPanel,BaseView myView){
System.out.println("執(zhí)行newPath() in ViewJump");
//檢驗(yàn)一下看有沒有無(wú)效的路徑,有則清除
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); //復(fù)制到原來的數(shù)組變量中
//最后一個(gè)位置留給新加入的元素
viewPath[count] = new ViewPath(myPanel,myView);
return count;
}
//獲得實(shí)例的方法
/**
* 必須檢查該P(yáng)anel是不是已經(jīng)在路徑中了,如果在路徑中,
* 則返回注冊(cè)的編號(hào),用此編號(hào)扁可以訪問到正確的類型了
* 如果不在路徑中,則以此為開始新建一個(gè)新的路徑
* 本來檢查路徑的時(shí)候沒有必要檢查路徑的第一個(gè)元素,
* 因?yàn)橐粋(gè)元素不可能是開端,但是為了防止用戶連續(xù)兩次registerPath的錯(cuò)誤
* 請(qǐng)把第一個(gè)元素也給檢查一下
* myView 參數(shù)只有當(dāng)該界面為跳轉(zhuǎn)的起始點(diǎn)時(shí)才需要,否則保持原始的View
* @param me
* @param other
* 返回實(shí)例數(shù)組的下標(biāo),
*/
public static int registerPath(JPanel myPanel,BaseView myView){
System.out.println("執(zhí)行registerPath() in ViewJump");
int idx = find(myPanel);
System.out.println("idx="+idx);
if(idx==-1){ //返回-1表示沒有找到,建立一個(gè)新的路徑
System.out.println("新建一個(gè)路徑");
idx = newPath(myPanel,myView);
}
System.out.println("執(zhí)行完注冊(cè)路徑..");
return idx; //返回實(shí)例下標(biāo)
}
//設(shè)定要跳轉(zhuǎn)的下一個(gè)目標(biāo)
public static void setNext(int id,JPanel aim){
if(id<0 id>=viewPath.length){
return;
}
ViewPath vp = viewPath[id];
//設(shè)定目標(biāo),從這里看,這是存在安全漏洞的,如果使用者亂傳遞id進(jìn)來的話
JPanel[] path = vp.pnlPath;
path[vp.index+1] = aim;
}
//回到上一個(gè)
public static void back(int id){
if(id<0 id>=viewPath.length){
return;
}
ViewPath vp = viewPath[id];
//回到上一個(gè)界面
if(vp.index>0){ //只有當(dāng)前面有路徑時(shí)才作
vp.bsView.remove(vp.pnlPath[vp.index]); //移去當(dāng)前的
vp.index--; //游標(biāo)往前走一步
vp.bsView.add(vp.pnlPath[vp.index],BorderLayout.CENTER); //增加當(dāng)前的到界面
vp.bsView.validate();
vp.bsView.repaint();
}
}
//回到起源處
public static void backHome(int id){
if(id<0 id>=viewPath.length){
return;
}
ViewPath vp = viewPath[id];
//直接回到第一步,需要清除該路徑嗎?中途斷裂怎么辦?辦法是檢查View是否已為空
//選擇不清除,每次在建立新的路徑時(shí),檢查路徑是不是已經(jīng)無(wú)效了
vp.bsView.remove(vp.pnlPath[vp.index]); //移去當(dāng)前的
vp.index = 0; //游標(biāo)往前走一步
vp.bsView.add(vp.pnlPath[vp.index],BorderLayout.CENTER); //增加當(dāng)前的到界面
vp.bsView.validate();
vp.bsView.repaint();
}
//跳轉(zhuǎn)到下一處
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; //下一步根本沒有設(shè)置
}
vp.bsView.remove(vp.pnlPath[vp.index]); //移去當(dāng)前的
vp.index++;
vp.bsView.add(vp.pnlPath[vp.index],BorderLayout.CENTER);
vp.bsView.validate();
vp.bsView.repaint();
}
}