无论是XXX平台的分功能导航,还是想把用户所有经常使用的功能集中到一个界面方便用户操作,有一个方便美观的导航都是很有必要的。如果是可配置的,不需要动程序就可以更改导航的内容那就更好了,实现了导航程序的一劳永逸,SO,今天给大家带来的就是这么一个程序。
树状导航是一种常见的导航方式,它通过层次结构的方式、展开/折叠效果、图标或缩略图等呈现功能之间的关系,增加导航的可视化吸引力,使用户能够清晰地了解整个系统的结构,并快速找到所需的功能,所以我们采用了树状导航的形式。
导航程序功能的实现大概经历了三个阶段:
1、每一个导航都单独写一个程序,功能写死在程序里面。不论是按钮也好,树状导航也罢,每次想给用户弄一个导航的时候都新写一个程序,需要导航的事务代码Hardcodeing,如有新加项则修改程序。当然这个程序一般来说是固定的结构,有固定的模板,写起来或者修改添加都非常简单。
2、数据驱动的导航结构,动态生成导航界面。主程序不再Hardcodeing,将导航数据从代码中抽离,存储到数据库中,使导航结构变得灵活可配置。可以使用适合的数据结构来表示导航的层次关系,并通过对数据库表或配置文件的增、删、改操作来进行导航项的管理和更新。同时用户账号作为主键之一,每个用户有自己的一个界面。只要配置表就可以了。
3、前两个方法都有明显的缺点,第一个需要不断的新增加程序,第二个一个账号一般来说只有一个导航界面,使用起来不灵活,所以第三个方案的是针对第二个方案的优化。导航数据还是维护到表里面,程序的主体结构使用单个函数来完成,可以在不同场景随时灵活方便的调用。然后有一个调用此函数的可执行程序,可以通过选择界面输入的根节点显示不同的导航,如果存成不同的变式就可以新加事务代码(使用变式的事务)来实现不同导航内容,既不需要动代码又可以实现灵活的导航内容。
另外,导航预设支持三种对象,事务代码、程序、维护表,可以根据实际情况再添加其他对象。
下面界面就是导航界面的样子,主打一个无需改代码,可配置生成。
首先创建表ZUM1:
然后创建文本表ZUMT,使用标准文本表的好处是SM30维护的时候自动根据登录语言维护对应的描述。
定义ZUMT-NODID的外键,如下图,这样ZUMT就成了ZUM1的文本表
再定义一个结构ZUMN:
SM30维护ZUM1:
函数:ZNAVIGATION_TREE:
参数 IV_OBJID 为右面显示图片的ID,SMW0维护。如不需显示可以置空。
参数 IV_TITLE 为导航界面的Title。
SCREEN 200:
GUI状态:
GUI标题:
函数ZNAVIGATION_TREE代码:
FUNCTION znavigation_tree.
*"----------------------------------------------------------------------
*"*"局部接口:
*" IMPORTING
*" REFERENCE(IV_OBJID) TYPE W3OBJID OPTIONAL
*" REFERENCE(IV_TITLE) OPTIONAL
*" TABLES
*" IT_NODES STRUCTURE ZUMN
*"----------------------------------------------------------------------
LOOP AT it_nodes.
PERFORM addroot USING it_nodes.
CHECK sy-subrc = 0.
PERFORM getnodes USING it_nodes.
ENDLOOP.
CHECK gt_nodes IS NOT INITIAL.
gv_title = iv_title.
IMPORT width = gv_width FROM DATABASE indx(nt) ID sy-uname.
IF gv_width IS INITIAL.
gv_width = 25.
ENDIF.
IF iv_objid IS NOT INITIAL. "SSM_CUAT/START_IMAGE
PERFORM get_pic_url USING iv_objid CHANGING gv_picurl.
ENDIF.
CALL SCREEN 200.
ENDFUNCTION.
程序LZNAVI_TREETOP:
FUNCTION-POOL znavi_tree. "MESSAGE-ID ..
CLASS lcl_receiver DEFINITION DEFERRED.
DATA: go_receiver TYPE REF TO lcl_receiver,
go_container TYPE REF TO cl_gui_custom_container,
go_spliter TYPE REF TO cl_gui_splitter_container,
go_cont_tree TYPE REF TO cl_gui_container,
go_cont_image TYPE REF TO cl_gui_container,
go_tree TYPE REF TO cl_gui_simple_tree,
go_picture TYPE REF TO cl_gui_picture,
gv_picurl TYPE char255,
gv_title TYPE char255,
gv_width TYPE i,
gv_okcode TYPE sy-ucomm.
DATA: gt_nodes TYPE TABLE OF mtreesnode,
gs_nodes TYPE mtreesnode.
DATA: gt_event TYPE cntl_simple_events,
gs_event TYPE cntl_simple_event.
*----------------------------------------------------------------------*
* CLASS lcl_receiver DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_receiver DEFINITION.
PUBLIC SECTION.
METHODS handle_node_double_click
FOR EVENT node_double_click OF cl_gui_simple_tree
IMPORTING node_key.
ENDCLASS. "lcl_receiver DEFINITION
*----------------------------------------------------------------------*
* CLASS lcl_receiver IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_receiver IMPLEMENTATION.
METHOD handle_node_double_click.
PERFORM navigation USING node_key.
ENDMETHOD. "handle_node_double_click
ENDCLASS. "lcl_receiver IMPLEMENTATION
*&---------------------------------------------------------------------*
*& MODULE user_command_0200 INPUT
*&---------------------------------------------------------------------*
MODULE user_command_0200 INPUT.
CASE gv_okcode.
WHEN 'EXPA'. "展开
go_tree->expand_root_nodes( expand_subtree = 'X' ).
WHEN 'CPRA'. "折叠
go_tree->collapse_all_nodes( ).
WHEN 'EXIT' OR 'CANC'.
go_spliter->get_column_width( EXPORTING id = 1
IMPORTING result = gv_width ).
cl_gui_cfw=>flush( ).
EXPORT width = gv_width TO DATABASE indx(nt) ID sy-uname.
LEAVE TO SCREEN 0.
ENDCASE.
CLEAR gv_okcode.
ENDMODULE. "user_command_0200 INPUT
*&---------------------------------------------------------------------*
*& Module STATUS_0200 OUTPUT
*&---------------------------------------------------------------------*
MODULE status_0200 OUTPUT.
SET PF-STATUS 'MAIN'.
SET TITLEBAR 'T001' WITH gv_title.
CHECK go_container IS INITIAL.
CREATE OBJECT go_container
EXPORTING
container_name = 'IMAGE_CONTAINER'
EXCEPTIONS
others = 1.
CREATE OBJECT go_spliter
EXPORTING
parent = go_container
rows = 1
columns = 2.
go_spliter->set_column_width( id = 1 width = gv_width ).
go_cont_tree = go_spliter->get_container( row = 1 column = 1 ).
CREATE OBJECT go_tree
EXPORTING
parent = go_cont_tree
node_selection_mode = cl_gui_simple_tree=>node_sel_mode_single
EXCEPTIONS
lifetime_error = 1
cntl_system_error = 2
create_error = 3
failed = 4
OTHERS = 5.
CREATE OBJECT go_receiver.
gs_event-eventid = cl_gui_simple_tree=>eventid_node_double_click.
gs_event-appl_event = 'X'.
APPEND gs_event TO gt_event.
go_tree->set_registered_events( gt_event ).
SET HANDLER go_receiver->handle_node_double_click FOR go_tree.
go_tree->add_nodes( table_structure_name = 'MTREESNODE'
node_table = gt_nodes ).
go_tree->expand_root_nodes( expand_subtree = 'X' ).
IF gv_picurl IS NOT INITIAL.
go_cont_image = go_spliter->get_container( row = 1 column = 2 ).
CREATE OBJECT go_picture
EXPORTING
parent = go_cont_image.
go_picture->set_display_mode( cl_gui_picture=>display_mode_fit_center ).
go_picture->load_picture_from_url( url = gv_picurl ).
ENDIF.
ENDMODULE. "status_0200 OUTPUT
*&---------------------------------------------------------------------*
*& FORM navigation
*&---------------------------------------------------------------------*
FORM navigation USING nodekey.
DATA: ls_zum1 TYPE zum1.
SELECT SINGLE * INTO ls_zum1
FROM zum1
WHERE nodid = nodekey.
IF sy-subrc = 0.
CASE ls_zum1-ntype.
WHEN 'C'.
CHECK ls_zum1-tcode NE ''.
CALL TRANSACTION ls_zum1-tcode.
WHEN 'R'.
PERFORM submit USING ls_zum1-tcode.
WHEN 'T'.
PERFORM mt_view USING ls_zum1-tcode.
ENDCASE.
ENDIF.
ENDFORM. "navigation
*&---------------------------------------------------------------------*
*& FORM addroot
*&---------------------------------------------------------------------*
FORM addroot USING root.
SELECT SINGLE zum1~nodid zumt~ndtxt
INTO (gs_nodes-node_key,gs_nodes-text)
FROM zum1 INNER JOIN zumt ON zumt~nodid = zum1~nodid AND
zumt~spras = sy-langu
WHERE zum1~nodid = root.
IF sy-subrc = 0.
gs_nodes-isfolder = 'X'.
APPEND gs_nodes TO gt_nodes.
ENDIF.
CLEAR gs_nodes.
ENDFORM. "addroot
*&---------------------------------------------------------------------*
*& FORM getnodes
*&---------------------------------------------------------------------*
FORM getnodes USING value(p_node).
DATA: BEGIN OF ls_zum1,
nodid TYPE zum1-nodid,
ntype TYPE zum1-ntype,
upnod TYPE zum1-upnod,
posnr TYPE zum1-posnr,
tcode TYPE zum1-tcode,
nicon TYPE zum1-nicon,
ndtxt TYPE zumt-ndtxt,
END OF ls_zum1.
DATA: lt_zum1 LIKE TABLE OF ls_zum1.
DATA: lv_tcode TYPE tcode.
SELECT zum1~nodid
zum1~ntype
zum1~upnod
zum1~posnr
zum1~tcode
zum1~nicon
zumt~ndtxt
INTO CORRESPONDING FIELDS OF TABLE lt_zum1
FROM zum1 LEFT JOIN zumt ON zumt~nodid = zum1~nodid AND
zumt~spras = sy-langu
WHERE zum1~upnod = p_node
ORDER BY ntype posnr.
IF sy-subrc = 0.
LOOP AT lt_zum1 INTO ls_zum1.
gs_nodes-node_key = ls_zum1-nodid.
gs_nodes-relatkey = p_node.
IF ls_zum1-ntype = ''.
gs_nodes-isfolder = 'X'.
gs_nodes-text = ls_zum1-ndtxt.
ELSE.
gs_nodes-text = ls_zum1-nodid && ` - ` && ls_zum1-ndtxt.
gs_nodes-n_image = ls_zum1-nicon.
ENDIF.
IF ls_zum1-ntype = 'C'. "检查事务码权限
lv_tcode = ls_zum1-tcode.
CALL FUNCTION 'AUTH_CHECK_TCODE'
EXPORTING
tcode = lv_tcode
EXCEPTIONS
OTHERS = 7.
IF sy-subrc <> 0.
* gs_nodes-hidden = 'X'.
gs_nodes-disabled = 'X'.
ENDIF.
ENDIF.
APPEND gs_nodes TO gt_nodes.
CLEAR gs_nodes.
IF ls_zum1-ntype = ''.
PERFORM getnodes USING ls_zum1-nodid.
ENDIF.
ENDLOOP.
ENDIF.
ENDFORM. "getnodes
*&---------------------------------------------------------------------*
*& FORM get_pic_url
*&---------------------------------------------------------------------*
FORM get_pic_url USING pv_mimenam CHANGING cv_url.
DATA lt_query TYPE TABLE OF w3query.
DATA ls_query TYPE w3query.
DATA lt_html TYPE TABLE OF w3html.
DATA lv_code TYPE w3param-ret_code.
DATA lv_type TYPE w3param-cont_type.
DATA lv_length TYPE w3param-cont_len.
DATA lt_picture TYPE TABLE OF w3mime.
DATA lv_size TYPE i.
ls_query-name = '_OBJECT_ID'.
ls_query-value = pv_mimenam . "'ENJOYSAP_LOGO'.
APPEND ls_query TO lt_query.
CALL FUNCTION 'WWW_GET_MIME_OBJECT'
TABLES
query_string = lt_query
html = lt_html
mime = lt_picture
CHANGING
return_code = lv_code
content_type = lv_type
content_length = lv_length
EXCEPTIONS
object_not_found = 1
parameter_not_found = 2
OTHERS = 3.
IF sy-subrc = 0.
lv_size = lv_length.
ELSE.
RETURN.
ENDIF.
CALL FUNCTION 'DP_CREATE_URL'
EXPORTING
type = 'image'
subtype = cndp_sap_tab_unknown
size = lv_size
lifetime = cndp_lifetime_transaction
TABLES
data = lt_picture
CHANGING
url = cv_url
EXCEPTIONS
OTHERS = 1.
ENDFORM. "get_pic_url
*&---------------------------------------------------------------------*
*& FORM submit report
*&---------------------------------------------------------------------*
FORM submit USING repid.
DATA: lt_efunct TYPE TABLE OF vimexclfun.
DATA: lt_fld TYPE TABLE OF sval,
ls_fld TYPE sval.
DATA: lv_code TYPE c.
DATA: ls_trdir TYPE trdir.
IF repid IS INITIAL.
ls_fld-tabname = 'TRDIR'.
ls_fld-fieldname = 'NAME'.
APPEND ls_fld TO lt_fld.
CALL FUNCTION 'POPUP_GET_VALUES'
EXPORTING
popup_title = '输入'
IMPORTING
returncode = lv_code
TABLES
fields = lt_fld.
IF lv_code = 'A'.
RETURN.
ELSE.
READ TABLE lt_fld INTO ls_fld INDEX 1.
ENDIF.
ELSE.
ls_fld-value = repid.
ENDIF.
SELECT SINGLE * INTO ls_trdir FROM trdir
WHERE name = ls_fld-value AND
subc = '1'.
IF sy-subrc = 0.
SUBMIT (ls_fld-value) VIA SELECTION-SCREEN AND RETURN.
ELSE.
MESSAGE s000(oo) WITH 'Report not exist'.
ENDIF.
ENDFORM. "submit
*&---------------------------------------------------------------------*
*& FORM maintain_table
*&---------------------------------------------------------------------*
FORM mt_view USING viewname.
DATA: lt_efunct TYPE TABLE OF vimexclfun ##needed.
DATA: lt_fld TYPE TABLE OF sval,
ls_fld TYPE sval.
DATA: lv_code TYPE c,
lv_vnam TYPE dd02v-tabname.
IF viewname IS INITIAL.
ls_fld-tabname = 'TVDIR'.
ls_fld-fieldname = 'TABNAME'.
APPEND ls_fld TO lt_fld.
CALL FUNCTION 'POPUP_GET_VALUES'
EXPORTING
popup_title = '输入'
IMPORTING
returncode = lv_code
TABLES
fields = lt_fld.
IF lv_code = 'A'.
RETURN.
ELSE.
READ TABLE lt_fld INTO ls_fld INDEX 1.
ENDIF.
ELSE.
ls_fld-value = viewname.
ENDIF.
lv_vnam = ls_fld-value.
CALL FUNCTION 'VIEW_MAINTENANCE_CALL'
EXPORTING
action = 'U'
view_name = lv_vnam
TABLES
excl_cua_funct = lt_efunct
EXCEPTIONS
OTHERS = 15.
ENDFORM. "mt_view
测试程序:
REPORT ztest_navi_tree NO STANDARD PAGE HEADING.
DATA it_nodes TYPE TABLE OF zumn.
START-OF-SELECTION.
APPEND 'ZRMM848' TO it_nodes.
APPEND 'ZRMM596' TO it_nodes.
CALL FUNCTION 'ZNAVIGATION_TREE'
EXPORTING
iv_title = '测试配置导航'
iv_objid = 'ENJOYSAP_LOGO' "'ENJOYSAP_LOGO'
TABLES
it_nodes = it_nodes.
正式程序如下,
可以根据不同的需求保存不同的变式,然后根据此程序在创建事务码的时候选择“使用变式的事务”,即可配置出不同的导航了。
REPORT znavi_tree NO STANDARD PAGE HEADING.
DATA it_nodes TYPE TABLE OF zumn WITH HEADER LINE.
SELECT-OPTIONS: s_nodid FOR it_nodes-nodid NO INTERVALS.
PARAMETERS: p_objid TYPE w3objid,
p_title TYPE cua_tit_tx.
AT SELECTION-SCREEN OUTPUT.
%_s_nodid_%_app_%-text = '根节点'.
%_p_objid_%_app_%-text = '图片ID'.
%_p_title_%_app_%-text = '导航界面Title'.
START-OF-SELECTION.
LOOP AT s_nodid WHERE low <> ''.
APPEND s_nodid-low TO it_nodes.
ENDLOOP.
CALL FUNCTION 'ZNAVIGATION_TREE'
EXPORTING
iv_title = p_title
iv_objid = p_objid
TABLES
it_nodes = it_nodes.