NC开发流程一览表

NC开发流程一览表
NC开发流程一览表

单表体的卡片型单据制作

单表体的单据:指装载界面数据的聚合VO表头为空,只存在一组表体VO。UI工厂设计了借口ISingleController,单表体单据界面控制类应实现此借口,并实现isSingleDetail方法。前期准备:单据注册,模板初始化等等,在构造好类框架后要修改界面控制类。

1.注册单据类型

2.注册VO对象如下:

public String[] getBillVoName(){

Return new String[]{

SampleVo.class.getName(),

SampleHeadVO.class.getName(),

SampleHeadVo.class.getName(),

};

}

public String getPKField(){

Return “pk_sample”;

}

public String getChildPKField(){

Return “pk_sample”;

}

注意此时的表头,表体的VO类一致。

3.是否走平台

public int getBusinessActionType(){

Return nc.ui.trade.businessaction.IBusinessActionType.BD;

}

4.注册按钮

public int[] getCardButtonAry(){

Return new int[]{

IBillButton.Query,

IBillButton.Add,

IBillButton.Edit,

IBillButton.Line,

IBillButton.Save,

IBillButton.Cancel,

IBillButton.Refresh,

};

}

最重要的一步,实现isSingleDetail方法。

public Boolean isSingleDetail(){

//单表体

Return true;

}

ISingleController用来支持但表头或单表体的单据,因此,当isSingleDetail方法返回true时,单据为单表体;当返回false时,单据为但表头。

单表头的卡片型单据制作

除了显示有很大差异外,单表头于单表体的唯一区别在于isSingleDetail方法的返回值。另外,在单表头界面增加浏览按钮和去掉行操作按钮。

虚拟主子表的卡片型单据制作

虚拟主子表单据:指的是那种数据来源于一张表,却根据(自定义的)特定规则虚拟主子表的结构,将一部分放到表头,剩下的字段放到表体的单据。它通常用于数据的分组,即把数据根据(自定义的)特定字段的值进行分组。字段值相等的数据自然的被归为一类,然后,把特定字段放到表头显示,属于它的一组数据在表体列表显示,形成了标准主子表的结构。由于数据分组的特定规则取决于业务,因此UI工厂无法做缺省的实现。但加载数据库数据一般都在查询时完成,所以可以定制查询事件的行为,这需要为单据创建按钮事件处理器,并重载查询时基类调用的方法。加载数据的步骤如下:

1.第一步,与前面的步骤一样,并配置好界面控制器类。

2.在UI类重载按钮事件处理器类的方法,如下:

Protected CardEventHandler createEventHandler(){

Return new SampleCardEventHandle(this.getUIControl());

}

3.构造按钮事件处理器类,重载onBoQuery方法。如下:

Protected void onBoQuery() throws Exception{

UIDialog querydialog = getQueryUI();

If(querydialog.showModel())==(INormalQuery)querydialog;

String strWhere=query.getWhereSql();

If(strWhere==null)

strWhere=”1=1”;

strWhere=”(”+strWhere+”) and (isnull(dr,0)=0)”;

//将查询对话框条件加到整个查询条件后

If(getHeadCondition()!=null)

strWhere=strWhere+”and”+getHeadCondition();

//查询数据表数据

SuperVO[] queryVos=getBusinessAction().queryHeadAllData(

Class.forName(getUIController().getBillVoName()[1]),

getUIController().getBillType(),

strWhere);

//清空缓冲数据

getBUfferData().clear();

if(queryVos==null||queryVos.length==0){

getBillUI().setBillOperate(IBillOperate.OP_INIT);

getBufferData().setCurrentRow(-1);

}else{

//根据规则将数据进行分组

AggregatedValueObject[] bills=createBillVOs(queryVos);

getBillUI().setBillOperate(IBillOperate.OP_NOTEDIT);

getBufferData().setCurrentRow(0);

}

}

/**

*对一组VO数据进行分类

*

*@param待分类的VO数据

*@return 分类的结果

*/

Private AggregatedValueObject[]

createBillVOs(CircularlyAccessibleValueObject[]vos){

if(vos==null||vos.length==0)

return null;

//按照年度,月度将数据分组

HashMap tmpMap=Hashlize.hashlizeObjects(vos,new VOHashKeyAdapter(new String[]{“vyear”,”vmonth”}));

AggregatedValueObject[] bills=new AggregatedValueObject[tmpMap.size()];

Int i=0;

Iterator it=tmpMap.keySet().iterator()

For(;it.hasNext();i++){

Object key=it.next();

ArrayList al=(ArrayList)tmpMap.get(key);

Bills[i]=new nc.vo.trade.pub.HYBillVO();

//设置表头数据

bill[i].setChildrenVO(

(SuperVO[]).toArray(new SuperVO[0]));

}

Return bills;

}

对数据增,删,改的控制

因为是虚拟主子表的数据结构,它在进行数据的操作时需要额外的控制。这个问题的本质是在将前台数据写回后台时,需将前台的主子表结构还原为单表结构。

1.数据修改时的控制,这包括新增和编辑

在编辑(行操作)完毕,点击保存按钮。程序会从界面取得被修改的数据,这些数据被标志成新增,删除,修改等状态,提交给后台处理。对于真正的主子表,表头数据和标题数据会分别存储到对应的表中,但对于虚拟主子表的单据,主表数据加上字表数据的一行才构成数据表中的一行记录。这个问题的解决方法如下:

在获取界面VO时做控制,方法是重载UI类重载基类的getChangedVOFramUI方法:Public AggregateValueObject getChangeVOFromUI()Throws Exception

{

AggregatedValueObject vo=super.getChangedVOFromUI();

If(vo!=null){

//将聚合VO的主表设为空

Vo.setParentVO(null);

}

Return vo;

}

通过将聚合VO的主表舍为空,后台不会再处理主表的数据。

在编辑时,将需要存储的主表数据放到字表中。这需要控制行操作的行为,方法是时间处理器重载基类的行操作方法:

/**

*增行方法

*/

Public void onBoLineAdd() throws https://www.360docs.net/doc/7015132895.html,ng.Exception{

Super.onBoLineAdd();

addDefaultData();

}

/**

*粘贴行的方法

*/

Protected void onBoLinePaste() throws Exception{

Super.onBoLinePaste();

addDefaultData();

}

/**

*插入行方法

*/

Protected void onBoLineIns() throws Exception{

super.onBoLineIns();

addDefaultData();

}

/**

*将表头数据放到表体中

*/

Private void addDefaultData() throws Exception{

Int

currentBodyrow=getBillCardPanelWrapper().getBillCardPanel().getBillTable().getSelected Row();

Object

vyear=getBillCardPanelWrapper().getBillCardPanel().getHeadItem(“vyear”).getValue(); getBillCardPanelWrapper().getBillCardPanel().setBodyValueAt(vyear,currentBodyrow,”vye ar”);

Object

vmonth=getBillCardPanelWrapper().getBillCardPanel().getHeadItem(“vmonth”).getValue ();

getBillCardPanelWrapper().getBillCardPanel().setBodyValueAt(vmonth,currentBodyrow,”vmonth”);

}

可以看到,在每个意在更新数据的行操作方法中,都会调用将表头相关数据放到表体当前操作行的方法。

控制保存后否再次查询数据库,以取得数据库最新数据。对于真正的主子表,在数

据库更新数据后重新查询一下最新数据并向前台返回,是具有意义的,并且根据表头数据的主键即可获得表头数据和表体数据。而虚拟主子表,如前所述,数据的组织在UI端完成,后台没有足够的信息区查询和组织数据。因此,此时只能向前台返回当前的数据。UI工厂使用IRetCurrentDataAfterSave借口做此标志,如果UI类的getUserObject方法返回的对象实现了此接口,则在保存后部重新读取数据库。我们加了一个RetCurrentDataAfterSaveImpl类,让它实现IRetCurrentDataAfterSave接口。

如:

Public Object getUserObject(){

Return new RetCurrentDataAfterSaveImpl();

}

需要注意的是:从程序健壮性考虑,我们应该加一些前台校验类,依照前面介绍,我们创建前台校验类,并在单据类型中注册。

3.对数据的删除控制

这需要让事件处理器重载基类的onBoDelete方法,如:

Protected void onBoDelete() throws Exception{

If(MessageDialog.showYesNoDlg(

getBiollUI(),”档案删除”,”是否确认删除该基本档案?”)!=UIDialog.ID_YES)

return;

AggregateValueObject modelVo=getBufferData().getCurrentVO();

//将聚合VO的表头设为空

modelVo.setParentVo(null);

getBusinesssAction().delete(

modelVo,

getBillUI()._getDate().toString(),

getBillUI.getUserObject());

getBufferData().removeCurrentRow();

if(getBufferData().getVOBufferSize()==0)

getBillUI().setBillOperate(IBillOperate.OP_INIT);

else

getBillUI().setBillOperate(IBillOperate.OP_NOTEDIT);

}

注:删除单据时,并不涉及到界面的数据,因此只需控制BillUIBuffer中的缓存的当前VO。

多字表卡片型单据

多字表单据在界面显示上通常是表头+多也签的表体,每一个页签代表一个字表。在UI 工厂中,这种单据得到了抽象,主要从以下两个角度:

1.对UI显示界面的抽象。多子表单据的UI类不使用BillCardUI做基类,而是继承与一

个新的UI基类,MultiChildBillCardUI,它封装了多个页签的界面显示。

2.对VO数据的抽象。在NC应用中,主子表数据存储在聚合VO中,它支持一个主表

+一个字表的结构,但是,这种结构不适合于多子表的情况。因此,UI工厂设计了接口IExAggVO,需要装载多子表数据的聚合VO类,应该实现此接口,并实现它的关键方法。

制作多子表单据的步骤

定义多子表VO

多子表Vo是聚合VO,同事又像一个装载多个字表数据的容器,因此它必然继承自AggregatedValueObject的类层次,又实现多子表VO的接口,IExAggVO,具体如下:Public class SampleExAggVO extends nc.vo.trade.pub.HYBillVO implements nc.vo.trade.pub.IExAggVO{

//用来装载多子表数据的hashmap

Private HashMap hmChildVOs=new HashMap();

/**

*返回各个子表的编码

*必须与单据模板的页签编码对应

*/

Public https://www.360docs.net/doc/7015132895.html,ng.String[] getTableCodes(){

Return new String[]{“sample_table1”,”sample_table2”};

}

/**

*返回各个子表的中文名称

*创建日期:(01-3-20 17:36:56)

*/

Public https://www.360docs.net/doc/7015132895.html,ng.String[] getTableNames(){

Return nw String[]{“字表一”,”字表二”};

}

/**

*取得所有字表的所有VO对象

*/

Public CircularlyAccessibleValueObject[] getAllChildrenVO()

{

ArrayLIst all=new ArrayList();

For(int i=0;i

CircularlyAccessibleValueObject[] cvos=getTableVO(getTableCode()[i]);

If(cvos!=null)

Al.addAll(Arrays.asList(cvos));

}

Return(SuperVO[]) al.toArray(new SuperVO[0]);

}

/**

*返回某个字表的VO数组。

*/

Public CircularlyAccessibleValueObject[]

getTableVO(String tableCode){

return(CircularlyAccessibleValueObject[])

hmChildVOs.get(tableCode);

}

/**

*为特定字表设置VO数据

*/

Public void setTableVO()(String tableCode,CircularlyAccessibleValueObject[]vos){ hmChildVOs.put(tableCode,vos);

}

/**

*缺省的页签编码

*/

Public String getDefaultTableCode(){

Return getTableCodes()[0];

}

Public nc.vo.pub.SuperVO[] getChildVOsByParentId(String tableCode,String parentid)

{

Return null;

}

Public java.util.HashMap getHmEditingVOs() throws Exception{

return null;

}

Public https://www.360docs.net/doc/7015132895.html,ng.String getParaentId(SpuerVO item){

Return null;

}

}

代码的解释:

HYBillVO类是UI工厂定义的继承自AggregatedValueObject的类。它实现了AggregatedValueObject的抽象方法。

返回的字表编码必须与单据模板定义的页签编码一致,这样数据才能正确显示。2.定义单据界面控制类

需要重点强调的是以下代码

public String[] getBillVoName(){

return new String[]{

//聚合VO

SampleExAggVO.class.getName(),

//主表

SampleHeadVO.class.getName(),

//子表一

SampleBodyVO.class.getName(),

//字表二

SampleBody_BVO.class.getName()

};

}

3.定义事件处理类

如果没有特殊的按钮事件处理,现在暂时可以不创建

4.定义业务代理类

对于多子表的单据,一定要创建业务代理类并重载loadChildDataAty方法如下所示:Public class SampleCardDelegator extends BDBusinessDelegator{

/**

*取得不同表体页签的数据

*/

Public Hashtable loadChildDataAry(String[] tableCodes,String key)throws https://www.360docs.net/doc/7015132895.html,ng.Exception{ //根据主表主键,取得子表一的数据

SampleBodyVO[]

AVOs=(SampleBodyVO[])queryByCondition(SampleBodyVO.class,”pk_sample=’”+key+”’and isnull(dr,0)=0”);

//根据主表主键,取得子表二的数据

SampleBody_BVO[]

BVOs=(SampleBody_BVO[])queryByCondition(SampleBody_BVO.class,”pk_sample=’”+key+”’and isnull(dr,0)=0”);

//将查询数据放入hashtable并返回

Hashtable dataHashTable = new Hashtable();

If(AVOs!=null&&AVOs.length>0){

dataHashTable.put(tableCodes[0],AVOs);

}

If(BVOs!=null&&BVOs.length>0){

dataHashTable.put(tableCodes[1],BVOs);

}

Return dataHashTable;

}

}

5.定义单据UI类

创建一个继承MultiChildBillCardUI类的单据UI类,并关联上先前创建的界面控制类,业务代理类:

/**

*关联上界面控制类

*/

Protected ICardController createController(){

Return new SampleCardController();

}

/**

*关联上业务代理类

*/

Protected BusinessDelegator createBusinessDelegator(){

Return new SampleCardDelegator();

}

如何制作列表型单据

列表型单据统一的界面基类是ListCardUI,统一的事件处理基类是ListEventHandler,统一的界面控制接口为IListController。

对于数据表满足真正的主子表结构的单据,要开发单表头,单表体,多子表的单据非常简单,只是在类的继承关系上有所不同,因此在制作列表型单据时,绝大部分过程都可以仿照卡片型单据的制作。

标准的列表型单据和卡片型单据相比,不同之处是:

列表型单据的控制器实现IListController接口,并且应该把按钮的设置实现在getListButtonAry 方法中,如:

Public int[] getListButtonAry(){

Return new int[]{

IBillButton.Query,

IBillButton.Edit,

IBillButton.Line,

IBillButton.Save,

IBillButton.Cancel,

IBillButton.Refresh,

};

}

与多子表的卡片单据相比,有两个不同:

1.多子表列表型单据的UI类继承自MultiChildlistUI类;

2.多子表列表型单据的界面控制类实现IListController接口。

需要注意的是:列表型单据也应该创建自己的业务代理类,负责加载多页签的数据。

单表头和单表体的列表型单据:

因为列表界面的表头和表体都是由列表组成的,所以单表头和单表体对于列表型单据在界面显示上是一致的。UI工厂定义了ISingleController接口来指定单据时单表头还是单表体,因此,如果单据的界面控制类实现ISingleController接口,辅之以配套的单据模板,就可以实现单列表的界面。需要注意的是:1.列表型单据不支持新增,而卡片型单据可以新增.2.就是列表型单据支持UI初始化时自动加载数据,而卡片型单据要初始化时自动加载,只能在构造函数中调用数据加载的方法。

虚拟主子表的列表型单据:

制作虚拟主子表的列表型单据,基本策略和办法还是和卡片型单据一样。因为列表型单据在UI初始化时可以调用加载单据数据的方法。

BillListUI初始化时调用initBillData方法加载单据数据因此我们在UI子类重载此方法:

/**

*初始化时加载单据数据

*/

Protected void initBillData(String strWhere)throws Exception{

If(strWhere==null)

strWhere=”1=1”;

strWhere = “(“+strWhere+”)and(isnull(dr,0)=0)”;

SuperVO[] queryVos=

getBusiDelegator().queryHeadAllData(Class.forName(getUIControl().getBillVoName()[1]),getUICo ntrol().getBillTye(),strWhere);

//清空缓冲数据

getBufferData().clear();

if(queryVos==null||query.length==0){

setBillOperate(IBillOPerate.OP_INIT);

setListHeadData(queryVos);

getBufferData().setCurrentRow(-1);

}else{

//将VO数据分组

AggregatedValueObject[] bills=createBillVOs(queryVos);

getBufferData().addVOsToBuffer(bills);

//将表头数据加到表头的列表中

setListHeadData(getBufferData().getAllHeadVOsFromBuffer());

setBillOperate(IBillOperate.OP_NOTEDIT);

getBufferData().setCurrentRow(0);

}

}

Private AggregatedValueObject[] createBillVOs(CircularlyAccessibleValueObject[] vos){ If(vos==null||vos.length==0)

Return null;

//将数据按年度,月度分组

HashMap tmpMap=Hashlize.hashlizeObject(vos,new VOHashKeyAdapter(new

String[]{“vyear”,”vmonth”}));

AggregatedValueObject[] bills = new AggregatedValueObject[tmpMap.size()];

Int I = 0;

For(Iterator it = tmpMap.keySet().iterator();it.hasNext();i++){

Object key= it.next();

ArrayList al =(ArrayList)tmpMap.get(key);

Bills[i] = new nc.vo.trade.pub.HYBillVO();

Bills[i].setParentVO((CircularlyAccessibleValueObject)al.get(0));

Bill[i].setChildrenVO((SuperVO[])al.toArray(new SuperVO[0]));

}

Return bills;

}

这部分数据加载的逻辑和前面虚拟主子表的卡片单据例子很相似,只是它多了一步操作—将查询得到的表头数据加到表头的列表中。

管理型单据制作

管理型单据时列表型单据和卡片型单据的组合,因此,它同时具备这两种单据的特征,也就是说,管理型单据具有两种视图,并且可以在这两种视图之间进行切换。另外,管理型单据对这两种视图又做了功能上的划分---卡片视图和列表视图都可用于数据的显示,但是一旦要对列表视图的数据进行编辑操作时,界面自动切换单卡片视图。

管理型单据统一的界面基类是BillManageUI,统一的事件处理类是ManageEventHandler,统一的界面控制类为AbstractManageController。这个类实际上实现了ICardController和IListController两个接口。

标准的管理型单据:

1.使单据UI类继承BIllManageUI。

2.使单据界面控制器类继承AbstractManageController类,这个类实现了卡片型单据控制器

的通用接口ICardController和列表型单据控制器的通用接口IListController,因此我们的界面控制器类实际上需要实现卡片和列表控制器的所有方法,除了单据类型,单据VO 的名字,是否走平台,主表主键名,字表主键名这些通用的设置以外,这里重点展示对于按钮的定义,如下:

/**

*取得列表界面的按钮

*/

Public int[] getListButtonAry(){

Return new int[]{

IBillButton.Query,

IBillButton.Add

IBillButton.Edit,

IBillButton.Line,

IBillButton.Save,

IBillButton.Delete,

IBillButton.Cancel,

//卡片按钮

IBillButton.Card,

IBillButton.Refresh,

};

}

/**

*取得卡片界面的按钮

*/

Public int [] getCardButtonAry(){

Return new int[]{

IBillButton.Query,

IBillButton.Add,

IBillButton.Edit,

IBillButton.Line,

IBillButton.Save

IBillButton.Delete,

IBillButton.Cancel,

//返回按钮

IBillButton.Return,

IBillButton.Refresh,

};

}

3.当单据不走平台时,单据UI类应该重载基类的createBusinessDelegator方法,并返回不

走平台的业务代理类。如下:

Protected BusinessDelegator createBusinessDelegator(){

Return new BDBusinessDelegator();

}

这样就完成了标准管理性的单据的制作。

多子表的管理型单据:

1.单据UI类应该继承MultiChildManageUI。

2.单据控制器类与标准管理型单据相同,但是VO的配置应按照多子表卡片型单据所示。另外,就像制作卡片型多子表单据一样,加载多子表的数据需要设置一个业务代理类,我们完全可以重用卡片型多子表单据例子中的业务代理类。

这样就完成了多子表管理型单据的制作。

虚拟多子表的管理型单据:

1.单据UI类继承BillManageUI。

2.单据控制器类继承AbstractManageController。

3.当单据不走平台时,单据UI类应该重载基类的createBusinessDelegator方法

4.查询时必须将查询得到的数据加到表头列表中,如下所示:

Protected void onBoQuery() throws Exception{

UIDialog query = getQueryUI();

If(querydialog.showModal()==UIDialog.ID_OK){

INormalQuery query = (INormalQuery)querydialog;

String strWhere = query.getWhereSql();

If(strWhere==null)

strWhere=”1=1”;

strWhere=”(“+strWhere+”)and(isnull(dr,0)=0)”;

if(getHeadCondition()!=null)

strWhere = strWhere+”and”+getHeadCondition();

SuperVO[] queryVos =

getBusinessAction().queryHeadAllData(Class.forName(getUIController().getBillVoName()[1]), getUIController().getBillType(),strWhere);

清空缓冲数据

getBufferData().clear();

if(queryVos==null||queryVos.length==0){

getBillUI().setBillOperate(IBillOperate.OP_INIT);

getBillUI().setListHeadData(queryVos);

getBufferData().setCurrentRow(-1);

}else{

AggregatedValueObject[] bills = createBillVOs(queryVos);

getBufferData().addVOsToBuffer(bills);

//将表头数据加到表头列表中

getBufferData().getAllHeadVOsFromBuffer();

getBillUI().setBillOperate(IBillOperate.OP_NOTEDIT);

getBufferData().setCurrentRow(0);

}

}

}

5.和虚拟多子表的卡片型单据一样,管理型单据应创建事件处理类,负责查询时组织数据

以及删除和保存单据时去掉表头VO,但是,由于管理型单据的表头是列表,UI工厂将此列表VO缓存到界面上,因此,在修改单据和新增单据后,应该同时更新表头列表的VO数据。虚拟主子表的表头是一个逻辑的表头,在保存单据时,我们首先取得界面改变的VO数据,并将其表头VO设置为空,但是,这保证了保存操作的正确性,却给自动更新表头列表的VO数据制造了麻烦,解决的办法是在保存后将VO数据的表头VO还原,代码如下:

/**

*单据保存后调用的方法

*/

Protected void setAddNewOperate(Boolean isAdding,AggregatedValueObject billVO)throws Exception{

If(billVO!=null&&billVO.getChildrenVO().length!=0){

CircularlyAccessibleValueObject pvo= billVo.getChildrenVO()[0];

//还原表头VO

billVO.setParentVO(pvo);

super.setAddNewOperate(isAdding,billVO);

}

}

setAddNewOperate方法在单据半寸后会被调用,它将去更新表头列表的VO数据。6.删除时须将表头列表中对应行删除,如下所示:

Protected void onBoDelete() throws Exception{

If(MessageDialog.showYesNoDlg(getBillUI,”档案删除”,”是否确认删除该基本档案?”)!=UIDialog.ID_YES)

Return;

AggregatedValueObject modelVo = getBufferData().getCurrentVO();

modelVo.setParentVO(null);

getBusinessAction().delete(modelVo,getUIController().getBillType(),getBillUI()._getData().toS tring(),getBillUI().getUserObject());

//将列表中该行删除

getBillUI().removeListHeadData(getBufferData().getCurrentRow());

getBufferData().removeCurrentRow();

if(getBufferData().getVOBufferSize()==0)

getBillUI().setBillOperate(IBillOperate.OP_INIT)

else

getBillUI().setBillOperate(IBillOperate.OP_NOTED)

}

树卡片类型单据

UI工厂提供了左树右单据这种界面形式,根据右边单据的界面类型又可以分为树卡片型单据和树管理型单据,树型结构为单据提供了更为丰富的界面表达形式,对客户来说具有很好的导航效果,NC-UAP提供了产生树形结构的工具类,我们可以有两种方法生成树:

1.通过ID和ParentID,树的最基本元素是节点,节点既可以作为父节点,又可以作为

孩子节点。每个节点都有一个ID标识自身,如果采用孩子节点链接父亲节点的数据结构,那么节点还需要一个域存储父亲节点的ID,这个ID是ParentID。

2.通过编码和编码规则,这里的编码规则实际上是将编码分段,然后通过判断编码长

度构造树,假设编码规则是“1.2.2”,它意味着第一级树节点的编码只有一个字符长度,第二级树节点的编码长度是三个字符长度,第三极树节点是五个字符长度。如果有4个节点A,B,C,D,他们的编码分别是0,000,001,00100,那么构造的树的根节点是A,A有两个子节点B和C,C的子节点是D。

这两种构造树的方法并不影响单据的制作,选择哪种策略完全取决于业务的要求和数据的构成形态。

树卡片型单据的类结构:

树卡片型单据统一的界面基类是BillTreeCardUI,它继承自BillCardUI。统一的事件处理基类是TreeCardEventHandler,它继承自CardEventHandler。统一的界面控制类接口为ITreeCardController,它继承自IcardController。

开发树卡片型单据的步骤:

标准的树卡片型界面:(构造树数据类)

树的数据类封装了树的构造规则,如何获取数据等,按照ID构造的树,其数据必须实现IVOTreeDataByID接口,而按编码构造的树,其数据类必须实现IVOTreeDataByCode接口。

例子如下:(按ID为准)

Public class SampleTreeCardData implements IVOTreeDataByID{

/**

*取得节点的ID域名称

*/

Public String getIDFieldName(){

Return “pk_sample”;

}

/**

*取得节点的PARENT_ID域名称

*/

Public String getParentIDFieldName(){

Return null;

}

/**

*取得节点的显示域名称

*/

Public String getShowFieldName(){

Return “pk_sample”;

}

/**

*取得树的数据

*/

Public SuperVO[] getTreeVO(){

SuperVO[] treeVOs = null;

Nc.ui.trade.bsdelegate.BusinessDelegator business = new

nc.ui.trade.bsdelegate.BDBusinessDelegator();

Try{

treeVOs = business.queryByCondition(SampleHeadVO.class,null);

}catch(https://www.360docs.net/doc/7015132895.html,ng.Exception e){

e.printStackTrace();

}

Return treeVOs;

}

}

创建界面控制器类:

树卡片型单据的界面控制器类应实现ISingleController和ITreeCardController接口。在这里需要强调一下几个方法:

/**

*单据的增加删除时,是否自动维护树结构

*/

Public Boolean isAutoManageTree(){

Return true;

}

Public String[] getBillVoName(){

Return new String[]{

SampleVO.class.getName(),

SampleHeadVO.class.getName(),

SampleBodyVO.class.getName()

};

}

Public Boolean isSingleDetail(){

Return true;

}

在定义VO信息时,可以看到,主表VO和在数数据类中定义的是一致的。

创建界面UI类:

界面UI类应该继承BillTreeCardUI类,并重载下面的方法:

/**

*取得树的数据类

*/

Protected IVOTreeData createTreeData(){

Return new SampleTreeCardData();

}

Protected ICardController createController(){

Return new SampleTreeCardController();

}

上面几步就完成了一个标准的树卡片类型单据的制作。

多子表的树卡片型单据:

学会了多子表卡片型单据并结合上面的标准树卡片型单据的制作,制作多子表的树卡片型单据非常简单,构造业务代理类负责加载多页签,这与多子表卡片型单据相同,不同在于:

1.需要构造树数据类,这与上面一节讲的完全相同。

2.单据UI类需要继承MultiChildBillTreeCardUI类。

3.单据控制器类需实现ITreeCardController和ISingleController接口并重载isSingleDetail,令其返回ture。

单表的树卡片型单据:

上面两个例子中,单据界面控制器类的isSingleDetail方法返回都是true,因此意味着对应每个表头数据,都需要加载对应的表体数据。如果单据没有表体,显然无需再加载表体数据,这种单据的制作只需要针对标准的树卡片界面修改单据模板(移

除表体页签),并按如下代码修改界面控制器类:

Public String[] getBillVoName(){

Return new String[]{

SampleVO.class.getName(),

SampleHeadVO.class.getName(),

SampleHeadVO.class.getName()

};

}

Public Boolean isSingleDetail(){

Return false;

}

树管理类型单据

开发标准的树管理型单据的步骤:

这与树卡片型单据很相似,在这里我们引入一个新表,它组成了树的数据,又是单据主表的主表。

Public class SampleTreeManageData implements IVOTreeDataByID{

Public String getIDFieldName(){

Return “pk_materialclass”;

}

Public String getParentIDFieldName(){

Return null;

}

Public String getShowFieldName(){

Return “vname”;

}

Public SuperVO[] getTreeVO(){

SuperVO[] treeVOs = null;

BusinessDelegator business = new BDBusinessDelegator();

Try{

treeVOs = business.queryByCondition(MaterialclassVO.class,null);

}catch(Exception e){

e.printStackTrace();

}

Return treeVOs;

}

}

如果依据编码构造树,代码如下:

Public class SampleTreeManageDataByCode implements IVOTreeDataByCode{ /**

*包含编码值的域

*/

Public String getCodeFieldName(){

Return “vcode”;

}

/**

*编码规则

*/

Public String getCodeRule(){

Return “2.2”;

}

Public String getShowFieldName(){

Return “vname”;

}

Public SuperVO[] getTreeVO(){

SuperVO[] treeVOs = null;

BusinessDelegator business = new BDBusinessDelegator();

Try{

treeVos = business.queryByCondition(MaterialclassVO.class,null);

}catch(Exception e){

e.printStackTrace();

}

Return treeVOs;

}

}

创建界面控制器类:

界面控制器类需继承AbstractTreeManageController类,需要配置的信息和其他管理型单据一样,配置的VO信息如下:

Public String[] getBillVoName(){

Return new String[]{

SampleVO.class.getName(),

SmpleHeadVO.class.getName(),

SampleBodyVO.class.getName()

}

}

界面UI类需继承BillTreeManageUI类,需要重载的方法是:

Protected AbstractManageController createController(){

Return new SampleTreeManageController();

}

Protected IVOTreeData createTreeData(){

Renturn new SampleTreeManageData();

}

上面就完成了一个标准的树卡片类型单据的制作。

多子表的树管理型单据:

1.需要创建树数据类。

2.接买呢控制器类需要继承AbstractTreeManageController类。

3.接买呢UI类需要继承MultiChildTreeManageUI类,并重载下面的方法:Protected IVOTreeData createTreeData(){

Return new SampleTreeManageData();

}

虚拟主子表的树管理型单据:

像虚拟主子表的管理型单据一样,我们可以用一张表虚拟成两张表构成单据的表头和表体。虚拟主子表的树管理型单据的步骤和制作标准树管理型单据的步骤完全一致,只不过在表头表体数据组织上稍有不同。为了构造虚拟主子表,我们需要控制这个环节,方法是创建事件处理器类,并使它继承TreeManageEventHandler类,重载onTreeSelected方法:

Public void onTreeSelected(VOTreeNode selectnode){

Try{

onQueryHeadData(selectnode);

}catch(BusinessException ex){

getBillUI().showErrorMessage(ex.getMessage());

ex.printStackTrace();

}catch(Exception e){

getBillUI().showErrorMessage(e.getMessage());

e.printStackTrace();

}

}

Private void onQueryHeadData(VOTreeNode selectnode) throws Exception{ Class voClass = Class.forName(getUIController().getBillVoName()[1]);

SuperVO vo = (SuperVO)voClass.newInstance();

String strWhere = “(isnull(dr,0)=0)”;

If(vo.getParentPKFieldName() != null)

strWhere = “(“+strWhere+”)and”+vo.getParentPKFieldName()+”=’”

//取得节点树聚合主键值作为表头的parent_pk值

+selectnode.getData().getPrimaryKey()+”’”;

SuperVO[] queryVos = getBusinessAction().queryHeadAllData(

voClass,getUIController().getBillType(),strWhere

);

//清空缓冲数据

getBufferData().clear();

if(queryVos != null && queryVos.length != 0){

//将数据分组

AggregatedValueObject [] bills = createBillVOs(queryVos);

getBufferData().addVOsToBuffer(bills);

getBillUI.setListHeadData(getBufferData().getAllHeadVOsFromBuffer());

getBufferData().setCurrentRow(0);

getBillUI().setBillOperate(IBillOperate.OP_NOEDIT);

}

Else

{

getBillUI().setListHeadData(queryVos);

getBufferData().setCurrentRow(-1);

getBillUI().setBillOperate(IBillOperate.OP_INIT);

}

}

控制删除,行操作的方法和虚拟主子表的管理型单据一样。

单表头的树管理型单据:

单表头的树管理型单据和标准的树管理型单据的唯一区别在于前者的表体数据位空,因此在实现的时候,其控制器类应实现ISingleController接口,并使isSingleDetail方法返回false。VO的配置等关键信息均与后者一致。

列表卡片类型单据的制作步骤:

以标准的列表卡片型单据为例,而其他几种变体的实现,则可以与前面的一一对应。创建界面控制类:

界面控制类应实现IListCardController接口,这个借口继承了ICardController,只是增加了一个方法,我们应该实现此方法,如下:

/**

*取得列表数据单元的类名

*/

Public String getSelectVoClassName(){

Return MaterialclassVO.class.getName();

}

创建界面UI类:

界面UI类继承ListCardUI类,我们介绍两个基本的操作:

1.加载列表数据:因为基类并不自动加载列表数据,我们可以自己加上列表数据的加载方法,并在UI构造器中调用.

/**

*取得列表数据的查询条件

*/

Public String getListVOQueryCondition(){

Return null;

}

/**

*构造器调用的加载列表数据的方法

*/

Private void initListData(){

Try{

//调用基类加载列表数据的方法

addVoToList();

}catch(Exception e){

e.printStackTrace();

}

}

通过控制器类配置的列表VO数据的类名和此处定义的查询条件,我们即可获得列表数据。

2.加载表头数据

当前列表(点击)选择一个节点时,会触发查询单据表头数据的操作。我们可以

定义加载表头数据的查询条件,并结合控制器配置的单据主表VO类,即可查询出表头的数据,如下所示:

/**

*表头数据的查询条件

*/

Public String getHeadVOQueryCondition(CircularlyAccessibleValueObject selectedVO){

MaterialclassVO listvo = (MaterialclassVO) selectedVO;

Return “pk_materialclass=’”

//根据当前选择节点的逐渐

+listvo.getPrimaryKey()+”’”;

}

渲染列表,定义显示属性

我们可以很灵活地定义列表显示的内容,因为在Swing中,列表的渲染定义由LIstCellRenderer接口定义,因此我们创建自己的渲染类,并实现此接口。Public class SampleListCellRender extends jLabel implements ListCellRenderer,Serializable{

Protected static Border noFocusBorder;

Public SampleListCellRender(){

Super();

noFocusBorder = new EmptyBorder(1,1,1,1);

setOperate(true);

setBorder(noFocusBorder);

}

Public Component getListCellRendererComponent(JList list,Object value,int

index,Boolean isSelected,Boolean cellHasFocus){

setComponentOrientation(list.getComponentOrientation());

if(isSelected){

setBackground(list.getSelectionBackground());

setForeground(list.getSelectionForeground());

}

Else{

setBackground(list.getBackground());

setForeground(list.getForeground());

}

MaterialclassVO vo= (MaterialclassVO)value;

//取得VO对象的名称属性值

setText(vo==null?””:vo.getVname());

setEnabled(list.isEnabled());

setFont(list.getFont());

return this;

}

}

最后,应在UI类中将定义的渲染类公布,如下:

相关主题
相关文档
最新文档